--- php5-5.2.10.dfsg.1.orig/pear/install-pear-nozlib.phar +++ php5-5.2.10.dfsg.1/pear/install-pear-nozlib.phar @@ -1234,27 +1234,54 @@ require_once 'phar://install-pear-nozlib.phar/index.php'; -__HALT_COMPILER(); Einstall-pear-nozlib.pharArchive/Tar.php+IrdImArchive_Tar-1.3.3.tarv+Iv` mConsole/Getopt.php(+I(=mConsole_Getopt-1.2.3.tarF+IFYxm index.php$+I$$m OS/Guess.php)+I) ymPEAR-1.8.0.tar<+I<f;mPEAR.php+I$8MmPEAR/ChannelFile.php+I;]RmPEAR/ChannelFile/Parser.php>+I>r׷mPEAR/Command.php62+I62{~mPEAR/Command/Common.php +I mPEAR/Command/Install.php+I?RbmPEAR/Command/Install.xml~!+I~!W_EmPEAR/Common.php#i+I#if4mPEAR/Config.php +I P mPEAR/Dependency2.phpL+IL7+mPEAR/DependencyDB.php_+I_mPEAR/Downloader.php+IJ mPEAR/Downloader/Package.php++I+N"mPEAR/ErrorStack.php+Ib!mPEAR/Frontend.phpJ+IJ`mPEAR/Frontend/CLI.phpa+IamPEAR/Installer.php*+I*mPEAR/Installer/Role.php +I bCimPEAR/Installer/Role/Common.php+It]mPEAR/Installer/Role/Data.phpp+Ip[rmPEAR/Installer/Role/Data.xml+IfszmPEAR/Installer/Role/Doc.phpm+Im mPEAR/Installer/Role/Doc.xml+Ih&P*mPEAR/Installer/Role/Php.phpm+ImmPEAR/Installer/Role/Php.xml+IzqmPEAR/Installer/Role/Script.phpv+Iv |mPEAR/Installer/Role/Script.xml+I@vmPEAR/Installer/Role/Test.phpp+Ip}amPEAR/Installer/Role/Test.xml+IB] mPEAR/PackageFile.php@+I@ulAm!PEAR/PackageFile/Generator/v1.php+I7|m!PEAR/PackageFile/Generator/v2.php+IT)+lmPEAR/PackageFile/Parser/v1.php@+I@yU3mPEAR/PackageFile/Parser/v2.php +I ﴓmPEAR/PackageFile/v1.php+IpmPEAR/PackageFile/v2.php+Iݮm!PEAR/PackageFile/v2/Validator.php%P+I%PhsRmPEAR/Registry.phpc0+Ic0gxm PEAR/REST.php<+I< *mPEAR/REST/10.php +I %mPEAR/Start.php6+I6=mPEAR/Start/CLI.phpQ+IQw -mPEAR/Task/Common.php+I]7bmPEAR/Task/Postinstallscript.php8+I8Ym"PEAR/Task/Postinstallscript/rw.php+I$mPEAR/Task/Replace.php+I]>mPEAR/Task/Replace/rw.php+I}mPEAR/Task/Unixeol.php +I ymPEAR/Task/Unixeol/rw.php+ItmPEAR/Task/Windowseol.php +I u(mPEAR/Task/Windowseol/rw.php+IBXmPEAR/Validate.phpzV+IzV-mPEAR/Validator/PECL.php+IHmPEAR/XMLParser.php+IhemStructures/Graph.php+Ir *m,Structures/Graph/Manipulator/AcyclicTest.php+I1sm2Structures/Graph/Manipulator/TopologicalSorter.php+IEmStructures/Graph/Node.php*+I*TmStructures_Graph-1.0.2.tarX+IX'(m -System.phpLN+ILNOjm XML/Util.phpv+IvmXML_Util-1.2.1.tar+I7l\m | -// +----------------------------------------------------------------------+ -// -// $Id: Tar.php,v 1.24 2007/01/06 04:03:32 cellog Exp $ +__HALT_COMPILER(); Finstall-pear-nozlib.pharArchive/Tar.php 8£J wmArchive_Tar-1.3.3.tarv8£Jv` mConsole/Getopt.php_28£J_2 + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * @category File_Formats + * @package Archive_Tar + * @author Vincent Blavet + * @copyright 1997-2008 The Authors + * @license http://www.opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Tar.php 287963 2009-09-02 08:18:55Z mrook $ + * @link http://pear.php.net/package/Archive_Tar + */ require_once 'phar://install-pear-nozlib.phar/' . 'PEAR.php'; @@ -1266,8 +1293,9 @@ * Creates a (compressed) Tar archive * * @author Vincent Blavet -* @version $Revision: 1.24 $ -* @package Archive +* @version $Revision: 287963 $ +* @license http://www.opensource.org/licenses/bsd-license.php New BSD License +* @package Archive_Tar */ class Archive_Tar extends PEAR { @@ -1356,7 +1384,7 @@ $this->_compress = true; $this->_compress_type = 'bz2'; } else { - die("Unsupported compression type '$p_compress'\n". + $this->_error("Unsupported compression type '$p_compress'\n". "Supported types are 'gz' and 'bz2'.\n"); return false; } @@ -1372,7 +1400,7 @@ PEAR::loadExtension($extname); } if (!extension_loaded($extname)) { - die("The extension '$extname' couldn't be found.\n". + $this->_error("The extension '$extname' couldn't be found.\n". "Please make sure your version of PHP was built ". "with '$extname' support.\n"); return false; @@ -1615,14 +1643,14 @@ function addString($p_filename, $p_string) { $v_result = true; - + if (!$this->_isArchive()) { if (!$this->_openWrite()) { return false; } $this->_close(); } - + if (!$this->_openAppend()) return false; @@ -1762,12 +1790,12 @@ function setAttribute() { $v_result = true; - + // ----- Get the number of variable list of arguments if (($v_size = func_num_args()) == 0) { return true; } - + // ----- Get the arguments $v_att_list = &func_get_args(); @@ -1827,7 +1855,7 @@ $p_filename = $this->_tarname; } clearstatcache(); - return @is_file($p_filename); + return @is_file($p_filename) && !@is_link($p_filename); } // }}} @@ -1837,7 +1865,7 @@ if ($this->_compress_type == 'gz') $this->_file = @gzopen($this->_tarname, "wb9"); else if ($this->_compress_type == 'bz2') - $this->_file = @bzopen($this->_tarname, "wb"); + $this->_file = @bzopen($this->_tarname, "w"); else if ($this->_compress_type == 'none') $this->_file = @fopen($this->_tarname, "wb"); else @@ -1890,7 +1918,7 @@ if ($this->_compress_type == 'gz') $this->_file = @gzopen($v_filename, "rb"); else if ($this->_compress_type == 'bz2') - $this->_file = @bzopen($v_filename, "rb"); + $this->_file = @bzopen($v_filename, "r"); else if ($this->_compress_type == 'none') $this->_file = @fopen($v_filename, "rb"); else @@ -1911,9 +1939,11 @@ { if ($this->_compress_type == 'gz') $this->_file = @gzopen($this->_tarname, "r+b"); - else if ($this->_compress_type == 'bz2') - $this->_file = @bzopen($this->_tarname, "r+b"); - else if ($this->_compress_type == 'none') + else if ($this->_compress_type == 'bz2') { + $this->_error('Unable to open bz2 in read/write mode \'' + .$this->_tarname.'\' (limitation of bz2 extension)'); + return false; + } else if ($this->_compress_type == 'none') $this->_file = @fopen($this->_tarname, "r+b"); else $this->_error('Unknown or missing compression type (' @@ -2104,7 +2134,7 @@ if (!$this->_addFile($v_filename, $v_header, $p_add_dir, $p_remove_dir)) return false; - if (@is_dir($v_filename)) { + if (@is_dir($v_filename) && !@is_link($v_filename)) { if (!($p_hdir = opendir($v_filename))) { $this->_warning("Directory '$v_filename' can not be read"); continue; @@ -2237,31 +2267,45 @@ return false; } - $v_info = stat($p_filename); - $v_uid = sprintf("%6s ", DecOct($v_info[4])); - $v_gid = sprintf("%6s ", DecOct($v_info[5])); - $v_perms = sprintf("%6s ", DecOct(fileperms($p_filename))); + $v_info = lstat($p_filename); + $v_uid = sprintf("%07s", DecOct($v_info[4])); + $v_gid = sprintf("%07s", DecOct($v_info[5])); + $v_perms = sprintf("%07s", DecOct($v_info['mode'] & 000777)); - $v_mtime = sprintf("%11s", DecOct(filemtime($p_filename))); + $v_mtime = sprintf("%011s", DecOct($v_info['mtime'])); + + $v_linkname = ''; - if (@is_dir($p_filename)) { + if (@is_link($p_filename)) { + $v_typeflag = '2'; + $v_linkname = readlink($p_filename); + $v_size = sprintf("%011s", DecOct(0)); + } elseif (@is_dir($p_filename)) { $v_typeflag = "5"; - $v_size = sprintf("%11s ", DecOct(0)); + $v_size = sprintf("%011s", DecOct(0)); } else { - $v_typeflag = ''; + $v_typeflag = '0'; clearstatcache(); - $v_size = sprintf("%11s ", DecOct(filesize($p_filename))); + $v_size = sprintf("%011s", DecOct($v_info['size'])); } - $v_linkname = ''; - - $v_magic = ''; - - $v_version = ''; - - $v_uname = ''; + $v_magic = 'ustar '; - $v_gname = ''; + $v_version = ' '; + + if (function_exists('posix_getpwuid')) + { + $userinfo = posix_getpwuid($v_info[4]); + $groupinfo = posix_getgrgid($v_info[5]); + + $v_uname = $userinfo['name']; + $v_gname = $groupinfo['name']; + } + else + { + $v_uname = ''; + $v_gname = ''; + } $v_devmajor = ''; @@ -2269,7 +2313,7 @@ $v_prefix = ''; - $v_binary_data_first = pack("a100a8a8a8a12A12", + $v_binary_data_first = pack("a100a8a8a8a12a12", $v_reduce_filename, $v_perms, $v_uid, $v_gid, $v_size, $v_mtime); $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12", @@ -2293,7 +2337,7 @@ $this->_writeBlock($v_binary_data_first, 148); // ----- Write the calculated checksum - $v_checksum = sprintf("%6s ", DecOct($v_checksum)); + $v_checksum = sprintf("%06s ", DecOct($v_checksum)); $v_binary_data = pack("a8", $v_checksum); $this->_writeBlock($v_binary_data, 8); @@ -2316,27 +2360,37 @@ } if ($p_type == "5") { - $v_size = sprintf("%11s ", DecOct(0)); + $v_size = sprintf("%011s", DecOct(0)); } else { - $v_size = sprintf("%11s ", DecOct($p_size)); + $v_size = sprintf("%011s", DecOct($p_size)); } - $v_uid = sprintf("%6s ", DecOct($p_uid)); - $v_gid = sprintf("%6s ", DecOct($p_gid)); - $v_perms = sprintf("%6s ", DecOct($p_perms)); + $v_uid = sprintf("%07s", DecOct($p_uid)); + $v_gid = sprintf("%07s", DecOct($p_gid)); + $v_perms = sprintf("%07s", DecOct($p_perms & 000777)); $v_mtime = sprintf("%11s", DecOct($p_mtime)); $v_linkname = ''; - $v_magic = ''; - - $v_version = ''; - - $v_uname = ''; + $v_magic = 'ustar '; - $v_gname = ''; + $v_version = ' '; + if (function_exists('posix_getpwuid')) + { + $userinfo = posix_getpwuid($p_uid); + $groupinfo = posix_getgrgid($p_gid); + + $v_uname = $userinfo['name']; + $v_gname = $groupinfo['name']; + } + else + { + $v_uname = ''; + $v_gname = ''; + } + $v_devmajor = ''; $v_devminor = ''; @@ -2367,7 +2421,7 @@ $this->_writeBlock($v_binary_data_first, 148); // ----- Write the calculated checksum - $v_checksum = sprintf("%6s ", DecOct($v_checksum)); + $v_checksum = sprintf("%06s ", DecOct($v_checksum)); $v_binary_data = pack("a8", $v_checksum); $this->_writeBlock($v_binary_data, 8); @@ -2401,7 +2455,7 @@ $v_prefix = ''; - $v_binary_data_first = pack("a100a8a8a8a12A12", + $v_binary_data_first = pack("a100a8a8a8a12a12", '././@LongLink', 0, 0, 0, $v_size, 0); $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12", $v_typeflag, $v_linkname, $v_magic, @@ -2424,7 +2478,7 @@ $this->_writeBlock($v_binary_data_first, 148); // ----- Write the calculated checksum - $v_checksum = sprintf("%6s ", DecOct($v_checksum)); + $v_checksum = sprintf("%06s ", DecOct($v_checksum)); $v_binary_data = pack("a8", $v_checksum); $this->_writeBlock($v_binary_data, 8); @@ -2492,7 +2546,7 @@ } // ----- Extract the properties - $v_header['filename'] = trim($v_data['filename']); + $v_header['filename'] = $v_data['filename']; if ($this->_maliciousFilename($v_header['filename'])) { $this->_error('Malicious .tar detected, file "' . $v_header['filename'] . '" will not install in desired directory tree'); @@ -2552,7 +2606,7 @@ } if (($v_header['size'] % 512) != 0) { $v_content = $this->_readBlock(); - $v_filename .= $v_content; + $v_filename .= trim($v_content); } // ----- Read the next header @@ -2561,6 +2615,7 @@ if (!$this->_readHeader($v_binary_data, $v_header)) return false; + $v_filename = trim($v_filename); $v_header['filename'] = $v_filename; if ($this->_maliciousFilename($v_filename)) { $this->_error('Malicious .tar detected, file "' . $v_filename . @@ -2768,6 +2823,9 @@ } } } elseif ($v_header['typeflag'] == "2") { + if (@file_exists($v_header['filename'])) { + @unlink($v_header['filename']); + } if (!@symlink($v_header['link'], $v_header['filename'])) { $this->_error('Unable to extract symbolic link {' .$v_header['filename'].'}'); @@ -2849,7 +2907,7 @@ { if (filesize($this->_tarname) == 0) return $this->_openWrite(); - + if ($this->_compress) { $this->_close(); @@ -2863,8 +2921,8 @@ if ($this->_compress_type == 'gz') $v_temp_tar = @gzopen($this->_tarname.".tmp", "rb"); elseif ($this->_compress_type == 'bz2') - $v_temp_tar = @bzopen($this->_tarname.".tmp", "rb"); - + $v_temp_tar = @bzopen($this->_tarname.".tmp", "r"); + if ($v_temp_tar == 0) { $this->_error('Unable to open file \''.$this->_tarname .'.tmp\' in binary read mode'); @@ -2918,14 +2976,14 @@ $v_size = filesize($this->_tarname); // We might have zero, one or two end blocks. - // The standard is two, but we should try to handle + // The standard is two, but we should try to handle // other cases. fseek($this->_file, $v_size - 1024); if (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) { fseek($this->_file, $v_size - 1024); } elseif (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) { - fseek($this->_file, $v_size - 512); + fseek($this->_file, $v_size - 512); } } @@ -2938,7 +2996,7 @@ { if (!$this->_openAppend()) return false; - + if ($this->_addList($p_filelist, $p_add_dir, $p_remove_dir)) $this->_writeFooter(); @@ -2984,7 +3042,7 @@ // {{{ _pathReduction() /** - * Compress path by changing for example "/dir/foo/../bar" to "/dir/bar", + * Compress path by changing for example "/dir/foo/../bar" to "/dir/bar", * rand emove double slashes. * * @param string $p_dir path to reduce @@ -5764,33 +5822,43 @@ | -// +----------------------------------------------------------------------+ -// -// $Id: Getopt.php,v 1.32 2007/02/18 04:13:07 cellog Exp $ +/** + * Color.php + * + * PHP Version 5 + * + * Copyright (c) 1997-2004 The PHP Group + * + * This source file is subject to version 3.0 of the PHP license, + * that is bundled with this package in the file LICENSE, and is + * available through the world-wide-web at the following url: + * 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 world-wide-web, please send a note to + * license@php.net so we can mail you a copy immediately. + * + * @category Console + * @package Console_Getopt + * @author Andrei Zmievski + * @license http://www.php.net/license/3_0.txt PHP 3.0 + * @version CVS: $Id: Getopt.php 267328 2008-10-14 18:53:25Z andrei $ + * @link http://pear.php.net/package/Console_Getopt + */ require_once 'phar://install-pear-nozlib.phar/' . 'PEAR.php'; /** * Command-line options parsing class. * - * @author Andrei Zmievski - * + * @category Console + * @package Console_Getopt + * @author Andrei Zmievski + * @license http://www.php.net/license/3_0.txt PHP 3.0 + * @link http://pear.php.net/package/Console_Getopt */ -class Console_Getopt { +class Console_Getopt +{ + /** * Parses the command-line options. * @@ -5817,15 +5885,13 @@ * * Most of the semantics of this function are based on GNU getopt_long(). * - * @param array $args an array of command-line arguments - * @param string $short_options specifies the list of allowed short options - * @param array $long_options specifies the list of allowed long options + * @param array $args an array of command-line arguments + * @param string $short_options specifies the list of allowed short options + * @param array $long_options specifies the list of allowed long options * * @return array two-element array containing the list of parsed options and * the non-option arguments - * * @access public - * */ function getopt2($args, $short_options, $long_options = null) { @@ -5835,7 +5901,14 @@ /** * This function expects $args to start with the script name (POSIX-style). * Preserved for backwards compatibility. + * + * @param array $args an array of command-line arguments + * @param string $short_options specifies the list of allowed short options + * @param array $long_options specifies the list of allowed long options + * * @see getopt2() + * @return array two-element array containing the list of parsed options and + * the non-option arguments */ function getopt($args, $short_options, $long_options = null) { @@ -5844,6 +5917,13 @@ /** * The actual implementation of the argument parsing code. + * + * @param int $version Version to use + * @param array $args an array of command-line arguments + * @param string $short_options specifies the list of allowed short options + * @param array $long_options specifies the list of allowed long options + * + * @return array */ function doGetopt($version, $args, $short_options, $long_options = null) { @@ -5884,17 +5964,28 @@ break; } - if ($arg{0} != '-' || (strlen($arg) > 1 && $arg{1} == '-' && !$long_options)) { + if ($arg{0} != '-' || (strlen($arg) > 1 && $arg{1} == '-' + && !$long_options)) { $non_opts = array_merge($non_opts, array_slice($args, $i)); break; } elseif (strlen($arg) > 1 && $arg{1} == '-') { - $error = Console_Getopt::_parseLongOption(substr($arg, 2), $long_options, $opts, $args); - if (PEAR::isError($error)) + $error = Console_Getopt::_parseLongOption(substr($arg, 2), + $long_options, $opts, + $args); + if (PEAR::isError($error)) { return $error; + } + } elseif ($arg == '-') { + // - is stdin + $non_opts = array_merge($non_opts, array_slice($args, $i)); + break; } else { - $error = Console_Getopt::_parseShortOption(substr($arg, 1), $short_options, $opts, $args); - if (PEAR::isError($error)) + $error = Console_Getopt::_parseShortOption(substr($arg, 1), + $short_options, $opts, + $args); + if (PEAR::isError($error)) { return $error; + } } } @@ -5902,19 +5993,27 @@ } /** - * @access private + * Parse short option * + * @param string $arg Argument + * @param string[] $short_options Available short options + * @param string[][] &$opts + * @param string[] &$args + * + * @access private + * @return void */ function _parseShortOption($arg, $short_options, &$opts, &$args) { for ($i = 0; $i < strlen($arg); $i++) { - $opt = $arg{$i}; + $opt = $arg{$i}; $opt_arg = null; /* Try to find the short option in the specifier string. */ - if (($spec = strstr($short_options, $opt)) === false || $arg{$i} == ':') - { - return PEAR::raiseError("Console_Getopt: unrecognized option -- $opt"); + if (($spec = strstr($short_options, $opt)) === false + || $arg{$i} == ':') { + $msg = "Console_Getopt: unrecognized option -- $opt"; + return PEAR::raiseError($msg); } if (strlen($spec) > 1 && $spec{1} == ':') { @@ -5933,11 +6032,14 @@ break; } else if (list(, $opt_arg) = each($args)) { /* Else use the next argument. */; - if (Console_Getopt::_isShortOpt($opt_arg) || Console_Getopt::_isLongOpt($opt_arg)) { - return PEAR::raiseError("Console_Getopt: option requires an argument -- $opt"); + if (Console_Getopt::_isShortOpt($opt_arg) + || Console_Getopt::_isLongOpt($opt_arg)) { + $msg = "option requires an argument --$opt"; + return PEAR::raiseError("Console_Getopt:" . $msg); } } else { - return PEAR::raiseError("Console_Getopt: option requires an argument -- $opt"); + $msg = "option requires an argument --$opt"; + return PEAR::raiseError("Console_Getopt:" . $msg); } } } @@ -5947,36 +6049,54 @@ } /** - * @access private + * Checks if an argument is a short option + * + * @param string $arg Argument to check * + * @access private + * @return bool */ function _isShortOpt($arg) { - return strlen($arg) == 2 && $arg[0] == '-' && preg_match('/[a-zA-Z]/', $arg[1]); + return strlen($arg) == 2 && $arg[0] == '-' + && preg_match('/[a-zA-Z]/', $arg[1]); } /** - * @access private + * Checks if an argument is a long option * + * @param string $arg Argument to check + * + * @access private + * @return bool */ function _isLongOpt($arg) { return strlen($arg) > 2 && $arg[0] == '-' && $arg[1] == '-' && - preg_match('/[a-zA-Z]+$/', substr($arg, 2)); + preg_match('/[a-zA-Z]+$/', substr($arg, 2)); } /** - * @access private + * Parse long option + * + * @param string $arg Argument + * @param string[] $long_options Available long options + * @param string[][] &$opts + * @param string[] &$args * + * @access private + * @return void|PEAR_Error */ function _parseLongOption($arg, $long_options, &$opts, &$args) { @list($opt, $opt_arg) = explode('=', $arg, 2); + $opt_len = strlen($opt); for ($i = 0; $i < count($long_options); $i++) { $long_opt = $long_options[$i]; $opt_start = substr($long_opt, 0, $opt_len); + $long_opt_name = str_replace('=', '', $long_opt); /* Option doesn't match. Go on to the next one. */ @@ -5984,17 +6104,24 @@ continue; } - $opt_rest = substr($long_opt, $opt_len); + $opt_rest = substr($long_opt, $opt_len); /* Check that the options uniquely matches one of the allowed options. */ - $next_option_rest = substr($long_options[$i + 1], $opt_len); + if ($i + 1 < count($long_options)) { + $next_option_rest = substr($long_options[$i + 1], $opt_len); + } else { + $next_option_rest = ''; + } + if ($opt_rest != '' && $opt{0} != '=' && $i + 1 < count($long_options) && $opt == substr($long_options[$i+1], 0, $opt_len) && $next_option_rest != '' && $next_option_rest{0} != '=') { - return PEAR::raiseError("Console_Getopt: option --$opt is ambiguous"); + + $msg = "Console_Getopt: option --$opt is ambiguous"; + return PEAR::raiseError($msg); } if (substr($long_opt, -1) == '=') { @@ -6002,11 +6129,19 @@ /* Long option requires an argument. Take the next argument if one wasn't specified. */; if (!strlen($opt_arg) && !(list(, $opt_arg) = each($args))) { - return PEAR::raiseError("Console_Getopt: option --$opt requires an argument"); + $msg = "Console_Getopt: option requires an argument --$opt"; + return PEAR::raiseError($msg); + } + + if (Console_Getopt::_isShortOpt($opt_arg) + || Console_Getopt::_isLongOpt($opt_arg)) { + $msg = "Console_Getopt: option requires an argument --$opt"; + return PEAR::raiseError($msg); } } } else if ($opt_arg) { - return PEAR::raiseError("Console_Getopt: option --$opt doesn't allow an argument"); + $msg = "Console_Getopt: option --$opt doesn't allow an argument"; + return PEAR::raiseError($msg); } $opts[] = array('--' . $opt, $opt_arg); @@ -6017,19 +6152,20 @@ } /** - * Safely read the $argv PHP array across different PHP configurations. - * Will take care on register_globals and register_argc_argv ini directives - * - * @access public - * @return mixed the $argv PHP array or PEAR error if not registered - */ + * Safely read the $argv PHP array across different PHP configurations. + * Will take care on register_globals and register_argc_argv ini directives + * + * @access public + * @return mixed the $argv PHP array or PEAR error if not registered + */ function readPHPArgv() { global $argv; if (!is_array($argv)) { if (!@is_array($_SERVER['argv'])) { if (!@is_array($GLOBALS['HTTP_SERVER_VARS']['argv'])) { - return PEAR::raiseError("Console_Getopt: Could not read cmd args (register_argc_argv=Off?)"); + $msg = "Could not read cmd args (register_argc_argv=Off?)"; + return PEAR::raiseError("Console_Getopt: " . $msg); } return $GLOBALS['HTTP_SERVER_VARS']['argv']; } @@ -6486,278 +6622,307 @@ } ?> - 'phar://install-pear-nozlib.phar/Archive_Tar-1.3.3.tar', 'Console_Getopt' => 'phar://install-pear-nozlib.phar/Console_Getopt-1.2.3.tar', 'Structures_Graph' => 'phar://install-pear-nozlib.phar/Structures_Graph-1.0.2.tar', 'XML_Util' => 'phar://install-pear-nozlib.phar/XML_Util-1.2.1.tar', -'PEAR' => 'phar://install-pear-nozlib.phar/PEAR-1.8.0.tar', -); -array_shift($argv); -$debug = false; -for ($i = 0; $i < sizeof($argv); $i++) { - $arg = $argv[$i]; - $bn = basename($arg); - if (ereg('package-(.*)\.xml$', $bn, $matches) || - ereg('([A-Za-z0-9_:]+)-.*\.(tar|tgz)$', $bn, $matches)) { - $install_files[$matches[1]] = $arg; - } elseif ($arg == '-a') { - $cache_dir = $argv[$i+1]; - $i++; - } elseif ($arg == '--force') { - $force = true; - } elseif ($arg == '-d') { - $with_dir = $argv[$i+1]; - $i++; - } elseif ($arg == '-b') { - $bin_dir = $argv[$i+1]; - $i++; - } elseif ($arg == '-c') { - $cfg_dir = $argv[$i+1]; - $i++; - } elseif ($arg == '-w') { - $www_dir = $argv[$i+1]; - $i++; - } elseif ($arg == '-p') { - $php_bin = $argv[$i+1]; - $i++; - } elseif ($arg == '-o') { - $download_dir = $argv[$i+1]; - $i++; - } elseif ($arg == '-t') { - $temp_dir = $argv[$i+1]; - $i++; - } elseif ($arg == '--debug') { - $debug = 1; - } elseif ($arg == '--extremedebug') { - $debug = 2; - } -} - -$config = PEAR_Config::singleton(); - -if (PEAR::isError($config)) { - $locs = PEAR_Config::getDefaultConfigFiles(); - die("ERROR: One of $locs[user] or $locs[system] is corrupt, please remove them and try again"); -} - -// make sure we use only default values -$config_layers = $config->getLayers(); -foreach ($config_layers as $layer) { - if ($layer == 'default') continue; - $config->removeLayer($layer); -} -$keys = $config->getKeys(); -if ($debug) { - $config->set('verbose', 5, 'default'); -} else { - $config->set('verbose', 0, 'default'); -} -// PEAR executables -if (!empty($bin_dir)) { - $config->set('bin_dir', $bin_dir, 'default'); -} - -// Cache files -if (!empty($cache_dir)) { - $config->set('cache_dir', $cache_dir, 'default'); -} - -// Config files -if (!empty($cfg_dir)) { - $config->set('cfg_dir', $cfg_dir, 'default'); -} - -// Web files -if (!empty($www_dir)) { - $config->set('www_dir', $www_dir, 'default'); -} - -// Downloaded files -if (!empty($download_dir)) { - $config->set('download_dir', $download_dir, 'default'); -} - -// Temporary files -if (!empty($temp_dir)) { - $config->set('temp_dir', $temp_dir, 'default'); -} - -// User supplied a dir prefix -if (!empty($with_dir)) { - $ds = DIRECTORY_SEPARATOR; - $config->set('php_dir', $with_dir, 'default'); - $config->set('doc_dir', $with_dir . $ds . 'doc', 'default'); - $config->set('data_dir', $with_dir . $ds . 'data', 'default'); - $config->set('test_dir', $with_dir . $ds . 'test', 'default'); - if (empty($www_dir)) { - $config->set('www_dir', $with_dir . $ds . 'htdocs', 'default'); - } - if (empty($cfg_dir)) { - $config->set('cfg_dir', $with_dir . $ds . 'cfg', 'default'); - } - if (!is_writable($config->get('cache_dir'))) { - include_once 'phar://install-pear-nozlib.phar/System.php'; - $cdir = System::mktemp(array('-d', 'pear')); - if (PEAR::isError($cdir)) { - $ui->outputData("[PEAR] cannot make new temporary directory: " . $cdir); - die(1); - } - $oldcachedir = $config->get('cache_dir'); - $config->set('cache_dir', $cdir); - } -} -if (!empty($php_bin)) { - $config->set('php_bin', $php_bin); -} -/* Print PEAR Conf (useful for debuging do NOT REMOVE) */ -if ($debug) { - sort($keys); - foreach ($keys as $key) { - echo $key . ' ' . - $config->getPrompt($key) . ": " . $config->get($key, null, 'default') . "\n"; - } - if ($debug == 2) { // extreme debugging - exit; - } -} -// end print - -$php_dir = $config->get('php_dir'); -$options = array(); -$options['upgrade'] = true; -$install_root = getenv('INSTALL_ROOT'); -if (!empty($install_root)) { - $options['packagingroot'] = $install_root; - $reg = &new PEAR_Registry($options['packagingroot']); -} else { - $reg = $config->getRegistry('default'); -} - -$ui = PEAR_Frontend::singleton('PEAR_Frontend_CLI'); -if (PEAR::isError($ui)) { - die($ui->getMessage()); -} -$installer = new PEAR_Installer($ui); -$pkg = new PEAR_PackageFile($config, $debug); - -foreach ($install_files as $package => $instfile) { - $info = $pkg->fromAnyFile($instfile, PEAR_VALIDATE_INSTALLING); - if (PEAR::isError($info)) { - if (is_array($info->getUserInfo())) { - foreach ($info->getUserInfo() as $err) { - $ui->outputData(sprintf("[PEAR] %s: %s", $package, $err['message'])); - } - } - $ui->outputData(sprintf("[PEAR] %s: %s", $package, $info->getMessage())); - continue; - } - $new_ver = $info->getVersion(); - $downloaderpackage = new PEAR_Downloader_Package($installer); - $err = $downloaderpackage->initialize($instfile); - if (PEAR::isError($err)) { - $ui->outputData(sprintf("[PEAR] %s: %s", $package, $err->getMessage())); - continue; - } - if ($reg->packageExists($package)) { - $old_ver = $reg->packageInfo($package, 'version'); - if (version_compare($new_ver, $old_ver, 'gt')) { - $installer->setOptions($options); - $dp = array($downloaderpackage); - $installer->setDownloadedPackages($dp); - $err = $installer->install($downloaderpackage, $options); - if (PEAR::isError($err)) { - $ui->outputData(sprintf("[PEAR] %s: %s", $package, $err->getMessage())); - continue; - } - $ui->outputData(sprintf("[PEAR] %-15s- upgraded: %s", $package, $new_ver)); - } else { - if ($force) { - $options['force'] = true; - $installer->setOptions($options); - $dp = array($downloaderpackage); - $installer->setDownloadedPackages($dp); - $err = $installer->install($downloaderpackage, $options); - if (PEAR::isError($err)) { - $ui->outputData(sprintf("[PEAR] %s: %s", $package, $err->getMessage())); - continue; - } - $ui->outputData(sprintf("[PEAR] %-15s- installed: %s", $package, $new_ver)); - } else { - $ui->outputData(sprintf("[PEAR] %-15s- already installed: %s", $package, $old_ver)); - } - } - } else { - $options['nodeps'] = true; - $installer->setOptions($options); - $dp = array($downloaderpackage); - $installer->setDownloadedPackages($dp); - $err = $installer->install($downloaderpackage, $options); - if (PEAR::isError($err)) { - $ui->outputData(sprintf("[PEAR] %s: %s", $package, $err->getMessage())); - continue; - } - $ui->outputData(sprintf("[PEAR] %-15s- installed: %s", $package, $new_ver)); - } - if ($package == 'PEAR') { - if (is_file($ufile = $config->getConfFile('user'))) { - $ui->outputData('Warning! a PEAR user config file already exists from ' . - 'a previous PEAR installation at ' . - "'$ufile'. You may probably want to remove it."); - } - $config->set('verbose', 1, 'default'); - if (isset($oldcachedir)) { - $config->set('cache_dir', $oldcachedir); - } - $data = array(); - foreach ($config->getKeys() as $key) { - $data[$key] = $config->get($key); - } - $cnf_file = $config->getConfFile('system'); - if (!empty($install_root)) { - $cnf_file = $install_root . DIRECTORY_SEPARATOR . $cnf_file; - } - $config->writeConfigFile($cnf_file, 'system', $data); - $ui->outputData('Wrote PEAR system config file at: ' . $cnf_file); - $ui->outputData('You may want to add: ' . $config->get('php_dir') . ' to your php.ini include_path'); - } -} -?> +'PEAR' => 'phar://install-pear-nozlib.phar/PEAR-1.9.0.tar', +); +array_shift($argv); +$debug = false; +for ($i = 0; $i < sizeof($argv); $i++) { + $arg = $argv[$i]; + $bn = basename($arg); + if (preg_match('/package-(.*)\.xml$/', $bn, $matches) || + preg_match('/([A-Za-z0-9_:]+)-.*\.(tar|tgz)$/', $bn, $matches)) { + $install_files[$matches[1]] = $arg; + } elseif ($arg == '-a') { + $cache_dir = $argv[$i+1]; + $i++; + } elseif ($arg == '--force') { + $force = true; + } elseif ($arg == '-dp') { + $prefix = $argv[$i+1]; + $i++; + } elseif ($arg == '-ds') { + $suffix = $argv[$i+1]; + $i++; + } elseif ($arg == '-d') { + $with_dir = $argv[$i+1]; + $i++; + } elseif ($arg == '-b') { + $bin_dir = $argv[$i+1]; + $i++; + } elseif ($arg == '-c') { + $cfg_dir = $argv[$i+1]; + $i++; + } elseif ($arg == '-w') { + $www_dir = $argv[$i+1]; + $i++; + } elseif ($arg == '-p') { + $php_bin = $argv[$i+1]; + $i++; + } elseif ($arg == '-o') { + $download_dir = $argv[$i+1]; + $i++; + } elseif ($arg == '-t') { + $temp_dir = $argv[$i+1]; + $i++; + } elseif ($arg == '--debug') { + $debug = 1; + } elseif ($arg == '--extremedebug') { + $debug = 2; + } +} + +$config = PEAR_Config::singleton(); + +if (PEAR::isError($config)) { + $locs = PEAR_Config::getDefaultConfigFiles(); + die("ERROR: One of $locs[user] or $locs[system] is corrupt, please remove them and try again"); +} + +// make sure we use only default values +$config_layers = $config->getLayers(); +foreach ($config_layers as $layer) { + if ($layer == 'default') continue; + $config->removeLayer($layer); +} +$keys = $config->getKeys(); +if ($debug) { + $config->set('verbose', 5, 'default'); +} else { + $config->set('verbose', 0, 'default'); +} +// PEAR executables +if (!empty($bin_dir)) { + $config->set('bin_dir', $bin_dir, 'default'); +} + +// Cache files +if (!empty($cache_dir)) { + $config->set('cache_dir', $cache_dir, 'default'); +} + +// Config files +if (!empty($cfg_dir)) { + $config->set('cfg_dir', $cfg_dir, 'default'); +} + +// Web files +if (!empty($www_dir)) { + $config->set('www_dir', $www_dir, 'default'); +} + +// Downloaded files +if (!empty($download_dir)) { + $config->set('download_dir', $download_dir, 'default'); +} + +// Temporary files +if (!empty($temp_dir)) { + $config->set('temp_dir', $temp_dir, 'default'); +} + +// User supplied a dir prefix +if (!empty($with_dir)) { + $ds = DIRECTORY_SEPARATOR; + $config->set('php_dir', $with_dir, 'default'); + $config->set('doc_dir', $with_dir . $ds . 'doc', 'default'); + $config->set('data_dir', $with_dir . $ds . 'data', 'default'); + $config->set('test_dir', $with_dir . $ds . 'test', 'default'); + if (empty($www_dir)) { + $config->set('www_dir', $with_dir . $ds . 'htdocs', 'default'); + } + if (empty($cfg_dir)) { + $config->set('cfg_dir', $with_dir . $ds . 'cfg', 'default'); + } + if (!is_writable($config->get('cache_dir'))) { + include_once 'phar://install-pear-nozlib.phar/System.php'; + $cdir = System::mktemp(array('-d', 'pear')); + if (PEAR::isError($cdir)) { + $ui->outputData("[PEAR] cannot make new temporary directory: " . $cdir); + die(1); + } + $oldcachedir = $config->get('cache_dir'); + $config->set('cache_dir', $cdir); + } +} + +// PHP executable +if (!empty($php_bin)) { + $config->set('php_bin', $php_bin); +} + +// PHP prefix +if (isset($prefix)) { + if ($prefix != 'a') { + if ($prefix[0] == 'a') { + $prefix = substr($prefix, 1); + } + $config->set('php_prefix', $prefix, 'system'); + } +} + +// PHP suffix +if (isset($suffix)) { + if ($suffix != 'a') { + if ($suffix[0] == 'a') { + $suffix = substr($suffix, 1); + } + $config->set('php_suffix', $suffix, 'system'); + } +} + +/* Print PEAR Conf (useful for debuging do NOT REMOVE) */ +if ($debug) { + sort($keys); + foreach ($keys as $key) { + echo $key . ' ' . + $config->getPrompt($key) . ": " . $config->get($key, null, 'default') . "\n"; + } + if ($debug == 2) { // extreme debugging + exit; + } +} +// end print + +$php_dir = $config->get('php_dir'); +$options = array(); +$options['upgrade'] = true; +$install_root = getenv('INSTALL_ROOT'); +if (!empty($install_root)) { + $options['packagingroot'] = $install_root; + $reg = &new PEAR_Registry($options['packagingroot']); +} else { + $reg = $config->getRegistry('default'); +} + +$ui = PEAR_Frontend::singleton('PEAR_Frontend_CLI'); +if (PEAR::isError($ui)) { + die($ui->getMessage()); +} +$installer = new PEAR_Installer($ui); +$pkg = new PEAR_PackageFile($config, $debug); + +foreach ($install_files as $package => $instfile) { + $info = $pkg->fromAnyFile($instfile, PEAR_VALIDATE_INSTALLING); + if (PEAR::isError($info)) { + if (is_array($info->getUserInfo())) { + foreach ($info->getUserInfo() as $err) { + $ui->outputData(sprintf("[PEAR] %s: %s", $package, $err['message'])); + } + } + $ui->outputData(sprintf("[PEAR] %s: %s", $package, $info->getMessage())); + continue; + } + $new_ver = $info->getVersion(); + $downloaderpackage = new PEAR_Downloader_Package($installer); + $err = $downloaderpackage->initialize($instfile); + if (PEAR::isError($err)) { + $ui->outputData(sprintf("[PEAR] %s: %s", $package, $err->getMessage())); + continue; + } + if ($reg->packageExists($package)) { + $old_ver = $reg->packageInfo($package, 'version'); + if (version_compare($new_ver, $old_ver, 'gt')) { + $installer->setOptions($options); + $dp = array($downloaderpackage); + $installer->setDownloadedPackages($dp); + $err = $installer->install($downloaderpackage, $options); + if (PEAR::isError($err)) { + $ui->outputData(sprintf("[PEAR] %s: %s", $package, $err->getMessage())); + continue; + } + $ui->outputData(sprintf("[PEAR] %-15s- upgraded: %s", $package, $new_ver)); + } else { + if ($force) { + $options['force'] = true; + $installer->setOptions($options); + $dp = array($downloaderpackage); + $installer->setDownloadedPackages($dp); + $err = $installer->install($downloaderpackage, $options); + if (PEAR::isError($err)) { + $ui->outputData(sprintf("[PEAR] %s: %s", $package, $err->getMessage())); + continue; + } + $ui->outputData(sprintf("[PEAR] %-15s- installed: %s", $package, $new_ver)); + } else { + $ui->outputData(sprintf("[PEAR] %-15s- already installed: %s", $package, $old_ver)); + } + } + } else { + $options['nodeps'] = true; + $installer->setOptions($options); + $dp = array($downloaderpackage); + $installer->setDownloadedPackages($dp); + $err = $installer->install($downloaderpackage, $options); + if (PEAR::isError($err)) { + $ui->outputData(sprintf("[PEAR] %s: %s", $package, $err->getMessage())); + continue; + } + $ui->outputData(sprintf("[PEAR] %-15s- installed: %s", $package, $new_ver)); + } + if ($package == 'PEAR') { + if (is_file($ufile = $config->getConfFile('user'))) { + $ui->outputData('Warning! a PEAR user config file already exists from ' . + 'a previous PEAR installation at ' . + "'$ufile'. You may probably want to remove it."); + } + $config->set('verbose', 1, 'default'); + if (isset($oldcachedir)) { + $config->set('cache_dir', $oldcachedir); + } + $data = array(); + foreach ($config->getKeys() as $key) { + $data[$key] = $config->get($key); + } + $cnf_file = $config->getConfFile('system'); + if (!empty($install_root)) { + $cnf_file = $install_root . DIRECTORY_SEPARATOR . $cnf_file; + } + $config->writeConfigFile($cnf_file, 'system', $data); + $ui->outputData('Wrote PEAR system config file at: ' . $cnf_file); + $ui->outputData('You may want to add: ' . $config->get('php_dir') . ' to your php.ini include_path'); + } +} +?> * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Guess.php,v 1.29 2009/04/09 22:24:12 dufuz Exp $ + * @version CVS: $Id: Guess.php 278521 2009-04-09 22:24:12Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since PEAR 0.1 */ @@ -6847,7 +7012,7 @@ * @author Gregory Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 0.1 */ @@ -7095,8 +7260,8 @@ * indent-tabs-mode: nil * c-basic-offset: 4 * End: - */package2.xml100664 764 764 123245 100664 6362 - + */package2.xml100664 764 764 117255 100664 6366 + PEAR pear.php.net PEAR Base System @@ -7178,325 +7343,246 @@ mj@php.net no - 2009-04-10 - + 2009-09-03 + - 1.8.0 - 1.8.0 + 1.9.0 + 1.9.0 stable stable - New BSD License + New BSD License -Changes since RC1: - * Fix Bug #14792: Bad md5sum for files with replaced content [dufuz] - * Fix Bug #16057:-r is limited to 4 directories in depth [dufuz] - * Fix Bug #16077: PEAR5::getStaticProperty does not return a reference to the property [dufuz] - - Remove custom XML_Util class in favor of using upstream XML_Util package as dependency - -RC1 Release Notes: - * Fix Bug #14331: pear cvstag only works from inside the package directory [dufuz] - * Fix Bug #16045: E_Notice: Undefined index: channel in PEAR/DependencyDB.php [dufuz] - - * Implemented Request #11230: better error message when mirror not in channel.xml file [dufuz] - * Implemented Request #13150: Add support for following HTTP 302 redirects [dufuz] - -Alpha1 Release Notes: - * Implement Request #10373: if pref_state=stable and installed package=beta, allow up to latest beta version [dufuz] - * Implement Request #10581: login / logout should map to channel-login / channel-logout [dufuz] - * Implement Request #10825: Only display the "invalid or missing package file"-error if it makes sense [dufuz] - * Implement Request #11170: script to generate Command/[command].xml [dufuz] - * Implement Request #11176: improve channel ... has updated its protocols message [dufuz] - * Implement Request #12706: pear list -a hard to read [dufuz] - * Implement Request #11353: upgrade-all and upgrade commands to upgrade within the same stability level [dufuz] - * Implement Request #13015: Add https discovery for channel.xml [dufuz / initial patch by Martin Roos] - * Implement Request #13927: install-pear.php should have option to set www_dir [timj] - * Implement Request #14324: Make the pear install command behave similar to apt-get [dufuz] - * Implement Request #14325: make pear upgrade with no params behave like pear upgrade-all [dufuz] - - upgrade-all can be considered deprecated in favor of calling upgrade with no parameters to replicate - better what other package managers are doing. upgrade-all will still work as intended. - * Implement Request #14504: add a channel parameter support to the upgrade function [dufuz] - - Options -c ezc and --channel=ezc got added to upgrade and upgrade-all to allow for - channel specific upgrades - * Implement Request #14556: install-pear-nozlib.phar should get download_dir config and other options [cweiske] - * Implement Request #15566: Add doc.php.net as a default channel [dufuz / saltybeagle] - - * Fix PHP Bug #43857: --program-suffix not always reflected everywhere [cellog] - * Fix PHP Bug #47323: strotime warnings in make install [dufuz] - - * Fix Bug #13908: pear info command and maintainers inactive not mentioned [dufuz] - * Fix Bug #13926: install-pear.php does not set cfg_dir if -d option set with no -c option [timj] - * Fix Bug #13943: tests fail when php.exe path contains spaces [dufuz / jorrit] - * Fix Bug #13953: config-set/config-show with channel alias fail [cellog] - * Fix Bug #13958: When a phpt tests exit() or die() xdebug coverage is not generated, patch by izi (David Jean Louis) [izi / dufuz] - * Fix Bug #14041: Unpredictable unit test processing sequence [dufuz] - * Fix Bug #14140: Strict warning not suppressed in the shutdown function [dufuz] - * Fix Bug #14210: pear list -ia brings warnings [dufuz] - * Fix Bug #14274: PEAR packager mangles package.xml encoding, then complains about it [dufuz] - * Fix Bug #14287: cannot upgrade from stable to beta via -beta when config is set to stable [dufuz] - * Fix Bug #14300: Package files themselves can not be served over https [dufuz / initial patch by Martin Roos] - * Fix Bug #14437: openbasedir warning when loading config [dufuz] - * Fix Bug #14558: PackageFile.php creates tmp directory outside configured temp_dir [cweiske] - * Fix Bug #14947: downloadHttp() is missing Host part of the HTTP Request when using Proxy [ifeghali] - * Fix Bug #14977: PEAR/Frontend.php doesn't require_once PEAR.php [dufuz] - * Fix Bug #15750: Unreachable code in PEAR_Downloader [dufuz] - * Fix Bug #15979: Package files incorrectly removed when splitting a package into multiple pkgs [dufuz] - * Fix Bug #15914: pear upgrade installs different version if desired version not found [dufuz] - - NOTE! - Functions that have been deprecated for 3+ years in PEAR_Common, please take a moment - to migrate over to one of the alternatives that have ben provided: - * PEAR_Common->downloadHttp (use PEAR_Downloader->downloadHttp instead) - * PEAR_Common->infoFromTgzFile (use PEAR_PackageFile->fromTgzFile instead) - * PEAR_Common->infoFromDescriptionFile (use PEAR_PackageFile->fromPackageFile instead) - * PEAR_Common->infoFromString (use PEAR_PackageFile->fromXmlstring instead) - * PEAR_Common->infoFromArray (use PEAR_PackageFile->fromAnyFile instead) - * PEAR_Common->xmlFromInfo (use a PEAR_PackageFile_v* object's generator instead) - * PEAR_Common->validatePackageInfo (use the validation of PEAR_PackageFile objects) - * PEAR_Common->analyzeSourceCode (use a PEAR_PackageFile_v* object instead) - * PEAR_Common->detectDependencies (use PEAR_Downloader_Package->detectDependencies instead) - * PEAR_Common->buildProvidesArray (use PEAR_PackageFile_v1->_buildProvidesArray or - PEAR_PackageFile_v2_Validator->_buildProvidesArray) - - PHP 4.4 and 5.1.6 are now the minimum PHP requirements, for brave souls - pear upgrade -f PEAR will allow people with lower versions - to upgrade to this release but no guarantees will be made that it will work properly. - - Support for XML RPC channels has been dropped - The only ones that used it - (pear.php.net and pecl.php.net) have used the REST interface for years now. - SOAP support also removed as it was only proof of concept. - - Move codebase from the PHP License to New BSD 2 clause license +* Fix Bug #16547: The phar for PEAR installer uses ereg() which is deprecated [dufuz] - + - + - + - - + + - - + + - + - + - - + + - + - - + + - + - + - + - - + + - + - + - + - + - + - + - + - + - + - - + + - + - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -7505,7 +7591,7 @@ - + @@ -7538,26 +7624,27 @@ - + - + - - - + + + + - - + + @@ -7684,7 +7771,7 @@ stable 2009-03-09 - New BSD License + New BSD License * Implement Request #10373: if pref_state=stable and installed package=beta, allow up to latest beta version [dufuz] * Implement Request #10581: login / logout should map to channel-login / channel-logout [dufuz] @@ -7763,7 +7850,7 @@ beta stable - New BSD License + New BSD License * Fix Bug #14331: pear cvstag only works from inside the package directory [dufuz] * Fix Bug #16045: E_Notice: Undefined index: channel in PEAR/DependencyDB.php [dufuz] @@ -7782,7 +7869,7 @@ stable stable - New BSD License + New BSD License Changes since RC1: * Fix Bug #14792: Bad md5sum for files with replaced content [dufuz] @@ -7866,9 +7953,116 @@ Move codebase from the PHP License to New BSD 2 clause license + + 2009-04-15 + + 1.8.1 + 1.8.1 + + + stable + stable + + New BSD License + +* Fix Bug #16099 PEAR crash on PHP4 (parse error) [dufuz] + + + + 2009-08-18 + + 1.9.0RC1 + 1.9.0RC1 + + + beta + stable + + New BSD License + +* Implement Request #16213: add alias to list-channels output [dufuz] +* Implement Request #16378: pear svntag [dufuz] +* Implement Request #16386: PEAR_Config::remove() does not support specifying a channel [timj] +* Implement Request #16396: package-dependencies should allow package names [dufuz] + +* Fix Bug #11181: pear requests channel.xml from main server instead from mirror [dufuz] +* Fix Bug #14493: pear install --offline doesn't print out errors [dufuz] +* Fix Bug #11348: pear package-dependencies isn't well explained [dufuz] +* Fix Bug #16108: PEAR_PackageFile_Generator_v2 PHP4 parse error when running upgrade-all [dufuz] +* Fix Bug #16113: Installing certain packages fails due incorrect encoding handling [dufuz] +* Fix Bug #16122: PEAR RunTest failed to run as expected [dufuz] +* Fix Bug #16366: compiling 5.2.10 leads to non-functioning pear [dufuz] +* Fix Bug #16387: channel-logout does not support logging out from a non-default channel [timj] +* Fix Bug #16444: Setting preferred mirror fails [dufuz] +* Fix the shutdown functions where a index might not exist and thus raise a notice [derick] + + + + 2009-08-20 + + 1.9.0RC2 + 1.9.0RC2 + + + beta + stable + + New BSD License + +* REST 1.4 file was occasionally being included but REST 1.4 is not intended for this release cycle [dufuz] + + + + 2009-08-21 + + 1.9.0RC3 + 1.9.0RC3 + + + beta + stable + + New BSD License + +* Improved svntag support to handle packages like PEAR it self [dufuz] + + + + 2009-08-23 + + 1.9.0RC4 + 1.9.0RC4 + + + beta + stable + + New BSD License + +* Fixed a problem where the original channel could not be set as a preferred_mirror again [dufuz] +* Make sure channel aliases can't be made to start with - [dufuz] +* Output issues with pear search [dufuz] +* Fixed couple of stray notices [dufuz] + + + + 2009-09-03 + + 1.9.0 + 1.9.0 + + + stable + stable + + New BSD License + +* Fix Bug #16547: The phar for PEAR installer uses ereg() which is deprecated [dufuz] + + -PEAR-1.8.0/OS/Guess.php100664 764 764 24637 100664 7461 * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Guess.php,v 1.29 2009/04/09 22:24:12 dufuz Exp $ + * @version CVS: $Id: Guess.php 278521 2009-04-09 22:24:12Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since PEAR 0.1 */ @@ -7957,7 +8151,7 @@ * @author Gregory Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 0.1 */ @@ -8205,7 +8399,7 @@ * indent-tabs-mode: nil * c-basic-offset: 4 * End: - */PEAR-1.8.0/PEAR/ChannelFile/Parser.php100664 764 764 3364 100664 12157 * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Parser.php,v 1.7 2009/02/24 23:39:07 dufuz Exp $ + * @version CVS: $Id: Parser.php 276383 2009-02-24 23:39:37Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since Release 1.4.0a1 */ @@ -8233,7 +8427,7 @@ * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 1.4.0a1 */ @@ -8272,7 +8466,7 @@ $ret->setPackagefile($file, $archive); return $ret; } -}PEAR-1.8.0/PEAR/Command/Auth.xml100777 764 764 2314 100777 11047 +}PEAR-1.9.0/PEAR/Command/Auth.xml100664 764 764 2314 100664 11036 Connects and authenticates to remote server [Deprecated in favor of channel-login] doLogin @@ -8301,7 +8495,7 @@ connect to the remote server, it only deletes the stored username and password from your user configuration. -PEAR-1.8.0/PEAR/Command/Auth.php100664 764 764 5141 100664 11025 PEAR-1.9.0/PEAR/Command/Auth.php100664 764 764 5136 100664 11032 * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Auth.php,v 1.36 2009/02/24 23:39:29 dufuz Exp $ + * @version CVS: $Id: Auth.php 276383 2009-02-24 23:39:37Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since Release 0.1 * @deprecated since 1.8.0alpha1 @@ -8333,7 +8527,7 @@ * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 0.1 * @deprecated since 1.8.0alpha1 @@ -8381,110 +8575,110 @@ { parent::PEAR_Command_Channels($ui, $config); } -}PEAR-1.8.0/PEAR/Command/Build.xml100777 764 764 405 100777 11164 +}PEAR-1.9.0/PEAR/Command/Build.xml100664 764 764 404 100664 11152 Build an Extension From C Source doBuild b - [package.xml] + [package.xml] Builds one or more extensions contained in a package. -PEAR-1.8.0/PEAR/Command/Build.php100664 764 764 4602 100664 11164 - * @author Tomas V.V.Cox - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Build.php,v 1.16 2009/02/24 23:39:29 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/** - * base class - */ -require_once 'PEAR/Command/Common.php'; - -/** - * PEAR commands for building extensions. - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Tomas V.V.Cox - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 - */ -class PEAR_Command_Build extends PEAR_Command_Common -{ - var $commands = array( - 'build' => array( - 'summary' => 'Build an Extension From C Source', - 'function' => 'doBuild', - 'shortcut' => 'b', - 'options' => array(), - 'doc' => '[package.xml] -Builds one or more extensions contained in a package.' - ), - ); - - /** - * PEAR_Command_Build constructor. - * - * @access public - */ - function PEAR_Command_Build(&$ui, &$config) - { - parent::PEAR_Command_Common($ui, $config); - } - - function doBuild($command, $options, $params) - { - require_once 'PEAR/Builder.php'; - if (sizeof($params) < 1) { - $params[0] = 'package.xml'; - } - - $builder = &new PEAR_Builder($this->ui); - $this->debug = $this->config->get('verbose'); - $err = $builder->build($params[0], array(&$this, 'buildCallback')); - if (PEAR::isError($err)) { - return $err; - } - - return true; - } - - function buildCallback($what, $data) - { - if (($what == 'cmdoutput' && $this->debug > 1) || - ($what == 'output' && $this->debug > 0)) { - $this->ui->outputData(rtrim($data), 'build'); - } - } -}PEAR-1.8.0/PEAR/Command/Channels.xml100777 764 764 10032 100777 11715 - - List Available Channels - doList - lc - - -List all available channels for installation. - - - +PEAR-1.9.0/PEAR/Command/Build.php100664 764 764 4453 100664 11171 + * @author Tomas V.V.Cox + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Build.php 276383 2009-02-24 23:39:37Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * base class + */ +require_once 'PEAR/Command/Common.php'; + +/** + * PEAR commands for building extensions. + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Tomas V.V.Cox + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Command_Build extends PEAR_Command_Common +{ + var $commands = array( + 'build' => array( + 'summary' => 'Build an Extension From C Source', + 'function' => 'doBuild', + 'shortcut' => 'b', + 'options' => array(), + 'doc' => '[package.xml] +Builds one or more extensions contained in a package.' + ), + ); + + /** + * PEAR_Command_Build constructor. + * + * @access public + */ + function PEAR_Command_Build(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + function doBuild($command, $options, $params) + { + require_once 'PEAR/Builder.php'; + if (sizeof($params) < 1) { + $params[0] = 'package.xml'; + } + + $builder = &new PEAR_Builder($this->ui); + $this->debug = $this->config->get('verbose'); + $err = $builder->build($params[0], array(&$this, 'buildCallback')); + if (PEAR::isError($err)) { + return $err; + } + + return true; + } + + function buildCallback($what, $data) + { + if (($what == 'cmdoutput' && $this->debug > 1) || + ($what == 'output' && $this->debug > 0)) { + $this->ui->outputData(rtrim($data), 'build'); + } + } +}PEAR-1.9.0/PEAR/Command/Channels.xml100664 764 764 10172 100664 11711 + + List Available Channels + doList + lc + + +List all available channels for installation. + + + Update the Channel List doUpdateAll uc @@ -8590,12 +8784,13 @@ doLogout clo - -Logs out from the remote server. This command does not actually -connect to the remote server, it only deletes the stored username and -password from your user configuration. + <channel name> +Logs out from a remote channel server. If <channel name> is not supplied, +the default channel is used. This command does not actually connect to the +remote server, it only deletes the stored username and password from your user +configuration. -PEAR-1.8.0/PEAR/Command/Channels.php100664 764 764 100632 100664 11720 PEAR-1.9.0/PEAR/Command/Channels.php100664 764 764 101377 100664 11730 * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Channels.php,v 1.64 2009/02/24 23:39:29 dufuz Exp $ + * @version CVS: $Id: Channels.php 287561 2009-08-21 22:42:58Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since Release 1.4.0a1 */ @@ -8629,7 +8824,7 @@ * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 1.4.0a1 */ @@ -8751,10 +8946,11 @@ 'shortcut' => 'clo', 'function' => 'doLogout', 'options' => array(), - 'doc' => ' -Logs out from the remote server. This command does not actually -connect to the remote server, it only deletes the stored username and -password from your user configuration.', + 'doc' => ' +Logs out from a remote channel server. If is not supplied, +the default channel is used. This command does not actually connect to the +remote server, it only deletes the stored username and password from your user +configuration.', ), ); @@ -8782,11 +8978,12 @@ $data = array( 'caption' => 'Registered Channels:', 'border' => true, - 'headline' => array('Channel', 'Summary') + 'headline' => array('Channel', 'Alias', 'Summary') ); foreach ($registered as $channel) { $data['data'][] = array($channel->getName(), - $channel->getSummary()); + $channel->getAlias(), + $channel->getSummary()); } if (count($registered) === 0) { @@ -9269,7 +9466,7 @@ return $this->raiseError('No channel alias specified'); } - if (count($params) !== 2) { + if (count($params) !== 2 || (!empty($params[1]) && $params[1]{0} == '-')) { return $this->raiseError( 'Invalid format, correct is: channel-alias channel alias'); } @@ -9459,20 +9656,23 @@ function doLogout($command, $options, $params) { $reg = &$this->config->getRegistry(); - $channel = $this->config->get('default_channel'); + + // If a parameter is supplied, use that as the channel to log in to + $channel = isset($params[0]) ? $params[0] : $this->config->get('default_channel'); + $chan = $reg->getChannel($channel); if (PEAR::isError($chan)) { return $this->raiseError($chan); } - $server = $this->config->get('preferred_mirror'); + $server = $this->config->get('preferred_mirror', null, $channel); $this->ui->outputData("Logging out from $server.", $command); - $this->config->remove('username'); - $this->config->remove('password'); + $this->config->remove('username', 'user', $channel); + $this->config->remove('password', 'user', $channel); $this->config->store(); return true; } -}PEAR-1.8.0/PEAR/Command/Common.php100664 764 764 20147 100664 11377 * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Common.php,v 1.39 2009/02/24 23:39:29 dufuz Exp $ + * @version CVS: $Id: Common.php 276383 2009-02-24 23:39:37Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since Release 0.1 */ @@ -9503,7 +9703,7 @@ * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 0.1 */ @@ -9744,7 +9944,7 @@ return $this->$func($command, $options, $params); } -}PEAR-1.8.0/PEAR/Command/Config.xml100777 764 764 6466 100777 11367 +}PEAR-1.9.0/PEAR/Command/Config.xml100664 764 764 6466 100664 11356 Show All Settings doConfigShow @@ -9835,7 +10035,7 @@ and uninstall). -PEAR-1.8.0/PEAR/Command/Config.php100664 764 764 35663 100664 11365 PEAR-1.9.0/PEAR/Command/Config.php100664 764 764 36076 100664 11365 * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Config.php,v 1.61 2009/03/26 21:36:32 dufuz Exp $ + * @version CVS: $Id: Config.php 287554 2009-08-21 21:16:25Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since Release 0.1 */ @@ -9866,7 +10066,7 @@ * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 0.1 */ @@ -10079,7 +10279,12 @@ return $this->raiseError('Channel "' . $params[1] . '" does not exist'); } - if ($params[0] == 'preferred_mirror' && !$reg->channelExists($params[1])) { + if ($params[0] == 'preferred_mirror' + && ( + !$reg->mirrorExists($channel, $params[1]) && + (!$reg->channelExists($params[1]) || $channel != $params[1]) + ) + ) { $msg = 'Channel Mirror "' . $params[1] . '" does not exist'; $msg .= ' in your registry for channel "' . $channel . '".'; $msg .= "\n" . 'Attempt to run "pear channel-update ' . $channel .'"'; @@ -10242,7 +10447,7 @@ return false; } -}PEAR-1.8.0/PEAR/Command/Install.xml100775 764 764 20576 100775 11602 +}PEAR-1.9.0/PEAR/Command/Install.xml100664 764 764 20576 100664 11575 Install Package doInstall @@ -10474,7 +10679,7 @@ DIR - f + force install even if there were errors @@ -10499,7 +10704,7 @@ DIR - + f Force the unpacking even if there were errors in the package @@ -10517,7 +10722,7 @@ Run post-installation scripts in package <package>, if any exist. -PEAR-1.8.0/PEAR/Command/Install.php100664 764 764 142453 100664 11602 PEAR-1.9.0/PEAR/Command/Install.php100664 764 764 143164 100664 11603 * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Install.php,v 1.153 2009/03/08 04:01:11 dufuz Exp $ + * @version CVS: $Id: Install.php 287477 2009-08-19 14:19:43Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since Release 0.1 */ @@ -10549,7 +10754,7 @@ * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 0.1 */ @@ -11082,8 +11287,7 @@ } } - $abstractpackages = array(); - $otherpackages = array(); + $abstractpackages = $otherpackages = array(); // parse params PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); @@ -11177,7 +11381,7 @@ } $this->downloader = &$this->getDownloader($this->ui, $options, $this->config); - $errors = $downloaded = $binaries = array(); + $errors = $downloaded = $binaries = array(); $downloaded = &$this->downloader->download($packages); if (PEAR::isError($downloaded)) { return $this->raiseError($downloaded); @@ -11222,8 +11426,7 @@ return true; } - $extrainfo = array(); - $binaries = array(); + $binaries = $extrainfo = array(); foreach ($downloaded as $param) { PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); $info = $this->installer->install($param, $options); @@ -11722,10 +11925,14 @@ return $this->raiseError($chan); } + $base2 = false; $preferred_mirror = $this->config->get('preferred_mirror', null, $channel); if ($chan->supportsREST($preferred_mirror) && - $base = $chan->getBaseURL('REST1.0', $preferred_mirror)) - { + ( + //($base2 = $chan->getBaseURL('REST1.4', $preferred_mirror)) || + ($base = $chan->getBaseURL('REST1.0', $preferred_mirror)) + ) + ) { $dorest = true; } @@ -11737,10 +11944,15 @@ } if ($dorest) { - $rest = &$this->config->getREST('1.0', array()); - $installed = array_flip($reg->listPackages($channel)); + if ($base2) { + $rest = &$this->config->getREST('1.4', array()); + $base = $base2; + } else { + $rest = &$this->config->getREST('1.0', array()); + } - $latest = $rest->listLatestUpgrades($base, $state, $installed, $channel, $reg); + $installed = array_flip($reg->listPackages($channel)); + $latest = $rest->listLatestUpgrades($base, $state, $installed, $channel, $reg); } PEAR::staticPopErrorHandling(); @@ -11775,7 +11987,7 @@ return $ret; } -}PEAR-1.8.0/PEAR/Command/Mirror.xml100777 764 764 1151 100777 11416 +}PEAR-1.9.0/PEAR/Command/Mirror.xml100664 764 764 1151 100664 11405 Downloads each available package from the default channel doDownloadAll @@ -11792,7 +12004,7 @@ and downloads them to current working directory. Note: only packages within preferred_state ({config preferred_state}) will be downloaded -PEAR-1.8.0/PEAR/Command/Mirror.php100664 764 764 10765 100664 11426 PEAR-1.9.0/PEAR/Command/Mirror.php100664 764 764 10762 100664 11424 * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Mirror.php,v 1.23 2009/02/24 23:39:29 dufuz Exp $ + * @version CVS: $Id: Mirror.php 276383 2009-02-24 23:39:37Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since Release 1.2.0 */ @@ -11821,7 +12033,7 @@ * @author Alexander Merz * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 1.2.0 */ @@ -11930,7 +12142,7 @@ return true; } -}PEAR-1.8.0/PEAR/Command/Package.xml100777 764 764 13665 100777 11534 +}PEAR-1.9.0/PEAR/Command/Package.xml100664 764 764 16066 100664 11521 Build Package doPackage @@ -11945,13 +12157,13 @@ Print the name of the packaged file. - [descfile] [descfile2] -Creates a PEAR package from its description file (usually called -package.xml). If a second packagefile is passed in, then -the packager will check to make sure that one is a package.xml -version 1.0, and the other is a package.xml version 2.0. The -package.xml version 1.0 will be saved as "package.xml" in the archive, -and the other as "package2.xml" in the archive" + [descfile] [descfile2] +Creates a PEAR package from its description file (usually called +package.xml). If a second packagefile is passed in, then +the packager will check to make sure that one is a package.xml +version 1.0, and the other is a package.xml version 2.0. The +package.xml version 1.0 will be saved as "package.xml" in the archive, +and the other as "package2.xml" in the archive" @@ -11959,7 +12171,7 @@ doPackageValidate pv - + @@ -12019,13 +12231,46 @@ Don't do anything, just pretend - <package.xml> -Compares all the files in a package. Without any options, this -command will compare the current code with the last checked-in code. -Using the -r or -R option you may compare the current code with that -of a specific release. + <package.xml> +Compares all the files in a package. Without any options, this +command will compare the current code with the last checked-in code. +Using the -r or -R option you may compare the current code with that +of a specific release. + + Set SVN Release Tag + doSvnTag + sv + + + q + Be quiet + + + F + Move (slide) tag if it exists + + + d + Remove tag + + + n + Don't do anything, just pretend + + + <package.xml> [files...] + Sets a SVN tag on all files in a package. Use this command after you have + packaged a distribution tarball with the "package" command to tag what + revisions of what files were in that release. If need to fix something + after running cvstag once, but before the tarball is released to the public, + use the "slide" option to move the release tag. + + to include files (such as a second package.xml, or tests not included in the + release), pass them as additional parameters. + + Set CVS Release Tag doCvsTag @@ -12052,15 +12297,15 @@ Don't do anything, just pretend - <package.xml> [files...] -Sets a CVS tag on all files in a package. Use this command after you have -packaged a distribution tarball with the "package" command to tag what -revisions of what files were in that release. If need to fix something -after running cvstag once, but before the tarball is released to the public, -use the "slide" option to move the release tag. - -to include files (such as a second package.xml, or tests not included in the -release), pass them as additional parameters. + <package.xml> [files...] +Sets a CVS tag on all files in a package. Use this command after you have +packaged a distribution tarball with the "package" command to tag what +revisions of what files were in that release. If need to fix something +after running cvstag once, but before the tarball is released to the public, +use the "slide" option to move the release tag. + +to include files (such as a second package.xml, or tests not included in the +release), pass them as additional parameters. @@ -12068,8 +12313,9 @@ doPackageDependencies pd - -List all dependencies the package has. + <package-file> or <package.xml> or <install-package-name> +List all dependencies the package has. +Can take a tgz / tar file, package.xml or a package name of an installed package. Sign a package distribution file @@ -12081,7 +12327,7 @@ Display GnuPG output - <package-file> + <package-file> Signs a package distribution (.tar or .tgz) file with GnuPG. @@ -12096,22 +12342,22 @@ p - Use FORMAT as format string for RPM package name, %s is replaced + Use FORMAT as format string for RPM package name, %s is replaced by the PEAR package name, defaults to "PEAR::%s". FORMAT - <package-file> - -Creates an RPM .spec file for wrapping a PEAR package inside an RPM -package. Intended to be used from the SPECS directory, with the PEAR -package tarball in the SOURCES directory: - -$ pear makerpm ../SOURCES/Net_Socket-1.0.tgz -Wrote RPM spec file PEAR::Net_Geo-1.0.spec -$ rpm -bb PEAR::Net_Socket-1.0.spec -... -Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm + <package-file> + +Creates an RPM .spec file for wrapping a PEAR package inside an RPM +package. Intended to be used from the SPECS directory, with the PEAR +package tarball in the SOURCES directory: + +$ pear makerpm ../SOURCES/Net_Socket-1.0.tgz +Wrote RPM spec file PEAR::Net_Geo-1.0.spec +$ rpm -bb PEAR::Net_Socket-1.0.spec +... +Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm @@ -12124,929 +12370,31 @@ do not beautify the filelist. - [descfile] [descfile2] -Converts a package.xml in 1.0 format into a package.xml -in 2.0 format. The new file will be named package2.xml by default, -and package.xml will be used as the old file by default. -This is not the most intelligent conversion, and should only be -used for automated conversion or learning the format. + [descfile] [descfile2] +Converts a package.xml in 1.0 format into a package.xml +in 2.0 format. The new file will be named package2.xml by default, +and package.xml will be used as the old file by default. +This is not the most intelligent conversion, and should only be +used for automated conversion or learning the format. -PEAR-1.8.0/PEAR/Command/Package.php100664 764 764 76030 100664 11504 - * @author Martin Jansen - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Package.php,v 1.133 2009/03/25 02:15:57 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/** - * base class - */ -require_once 'PEAR/Command/Common.php'; - -/** - * PEAR commands for login/logout - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Martin Jansen - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: @package_version@ - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 - */ - -class PEAR_Command_Package extends PEAR_Command_Common -{ - var $commands = array( - 'package' => array( - 'summary' => 'Build Package', - 'function' => 'doPackage', - 'shortcut' => 'p', - 'options' => array( - 'nocompress' => array( - 'shortopt' => 'Z', - 'doc' => 'Do not gzip the package file' - ), - 'showname' => array( - 'shortopt' => 'n', - 'doc' => 'Print the name of the packaged file.', - ), - ), - 'doc' => '[descfile] [descfile2] -Creates a PEAR package from its description file (usually called -package.xml). If a second packagefile is passed in, then -the packager will check to make sure that one is a package.xml -version 1.0, and the other is a package.xml version 2.0. The -package.xml version 1.0 will be saved as "package.xml" in the archive, -and the other as "package2.xml" in the archive" -' - ), - 'package-validate' => array( - 'summary' => 'Validate Package Consistency', - 'function' => 'doPackageValidate', - 'shortcut' => 'pv', - 'options' => array(), - 'doc' => ' -', - ), - 'cvsdiff' => array( - 'summary' => 'Run a "cvs diff" for all files in a package', - 'function' => 'doCvsDiff', - 'shortcut' => 'cd', - 'options' => array( - 'quiet' => array( - 'shortopt' => 'q', - 'doc' => 'Be quiet', - ), - 'reallyquiet' => array( - 'shortopt' => 'Q', - 'doc' => 'Be really quiet', - ), - 'date' => array( - 'shortopt' => 'D', - 'doc' => 'Diff against revision of DATE', - 'arg' => 'DATE', - ), - 'release' => array( - 'shortopt' => 'R', - 'doc' => 'Diff against tag for package release REL', - 'arg' => 'REL', - ), - 'revision' => array( - 'shortopt' => 'r', - 'doc' => 'Diff against revision REV', - 'arg' => 'REV', - ), - 'context' => array( - 'shortopt' => 'c', - 'doc' => 'Generate context diff', - ), - 'unified' => array( - 'shortopt' => 'u', - 'doc' => 'Generate unified diff', - ), - 'ignore-case' => array( - 'shortopt' => 'i', - 'doc' => 'Ignore case, consider upper- and lower-case letters equivalent', - ), - 'ignore-whitespace' => array( - 'shortopt' => 'b', - 'doc' => 'Ignore changes in amount of white space', - ), - 'ignore-blank-lines' => array( - 'shortopt' => 'B', - 'doc' => 'Ignore changes that insert or delete blank lines', - ), - 'brief' => array( - 'doc' => 'Report only whether the files differ, no details', - ), - 'dry-run' => array( - 'shortopt' => 'n', - 'doc' => 'Don\'t do anything, just pretend', - ), - ), - 'doc' => ' -Compares all the files in a package. Without any options, this -command will compare the current code with the last checked-in code. -Using the -r or -R option you may compare the current code with that -of a specific release. -', - ), - 'cvstag' => array( - 'summary' => 'Set CVS Release Tag', - 'function' => 'doCvsTag', - 'shortcut' => 'ct', - 'options' => array( - 'quiet' => array( - 'shortopt' => 'q', - 'doc' => 'Be quiet', - ), - 'reallyquiet' => array( - 'shortopt' => 'Q', - 'doc' => 'Be really quiet', - ), - 'slide' => array( - 'shortopt' => 'F', - 'doc' => 'Move (slide) tag if it exists', - ), - 'delete' => array( - 'shortopt' => 'd', - 'doc' => 'Remove tag', - ), - 'dry-run' => array( - 'shortopt' => 'n', - 'doc' => 'Don\'t do anything, just pretend', - ), - ), - 'doc' => ' [files...] -Sets a CVS tag on all files in a package. Use this command after you have -packaged a distribution tarball with the "package" command to tag what -revisions of what files were in that release. If need to fix something -after running cvstag once, but before the tarball is released to the public, -use the "slide" option to move the release tag. - -to include files (such as a second package.xml, or tests not included in the -release), pass them as additional parameters. -', - ), - 'package-dependencies' => array( - 'summary' => 'Show package dependencies', - 'function' => 'doPackageDependencies', - 'shortcut' => 'pd', - 'options' => array(), - 'doc' => ' -List all dependencies the package has.' - ), - 'sign' => array( - 'summary' => 'Sign a package distribution file', - 'function' => 'doSign', - 'shortcut' => 'si', - 'options' => array( - 'verbose' => array( - 'shortopt' => 'v', - 'doc' => 'Display GnuPG output', - ), - ), - 'doc' => ' -Signs a package distribution (.tar or .tgz) file with GnuPG.', - ), - 'makerpm' => array( - 'summary' => 'Builds an RPM spec file from a PEAR package', - 'function' => 'doMakeRPM', - 'shortcut' => 'rpm', - 'options' => array( - 'spec-template' => array( - 'shortopt' => 't', - 'arg' => 'FILE', - 'doc' => 'Use FILE as RPM spec file template' - ), - 'rpm-pkgname' => array( - 'shortopt' => 'p', - 'arg' => 'FORMAT', - 'doc' => 'Use FORMAT as format string for RPM package name, %s is replaced -by the PEAR package name, defaults to "PEAR::%s".', - ), - ), - 'doc' => ' - -Creates an RPM .spec file for wrapping a PEAR package inside an RPM -package. Intended to be used from the SPECS directory, with the PEAR -package tarball in the SOURCES directory: - -$ pear makerpm ../SOURCES/Net_Socket-1.0.tgz -Wrote RPM spec file PEAR::Net_Geo-1.0.spec -$ rpm -bb PEAR::Net_Socket-1.0.spec -... -Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm -', - ), - 'convert' => array( - 'summary' => 'Convert a package.xml 1.0 to package.xml 2.0 format', - 'function' => 'doConvert', - 'shortcut' => 'c2', - 'options' => array( - 'flat' => array( - 'shortopt' => 'f', - 'doc' => 'do not beautify the filelist.', - ), - ), - 'doc' => '[descfile] [descfile2] -Converts a package.xml in 1.0 format into a package.xml -in 2.0 format. The new file will be named package2.xml by default, -and package.xml will be used as the old file by default. -This is not the most intelligent conversion, and should only be -used for automated conversion or learning the format. -' - ), - ); - - var $output; - - /** - * PEAR_Command_Package constructor. - * - * @access public - */ - function PEAR_Command_Package(&$ui, &$config) - { - parent::PEAR_Command_Common($ui, $config); - } - - function _displayValidationResults($err, $warn, $strict = false) - { - foreach ($err as $e) { - $this->output .= "Error: $e\n"; - } - foreach ($warn as $w) { - $this->output .= "Warning: $w\n"; - } - $this->output .= sprintf('Validation: %d error(s), %d warning(s)'."\n", - sizeof($err), sizeof($warn)); - if ($strict && count($err) > 0) { - $this->output .= "Fix these errors and try again."; - return false; - } - return true; - } - - function &getPackager() - { - if (!class_exists('PEAR_Packager')) { - require_once 'PEAR/Packager.php'; - } - $a = &new PEAR_Packager; - return $a; - } - - function &getPackageFile($config, $debug = false, $tmpdir = null) - { - if (!class_exists('PEAR_Common')) { - require_once 'PEAR/Common.php'; - } - if (!class_exists('PEAR_PackageFile')) { - require_once 'PEAR/PackageFile.php'; - } - $a = &new PEAR_PackageFile($config, $debug, $tmpdir); - $common = new PEAR_Common; - $common->ui = $this->ui; - $a->setLogger($common); - return $a; - } - - function doPackage($command, $options, $params) - { - $this->output = ''; - $pkginfofile = isset($params[0]) ? $params[0] : 'package.xml'; - $pkg2 = isset($params[1]) ? $params[1] : null; - if (!$pkg2 && !isset($params[0]) && file_exists('package2.xml')) { - $pkg2 = 'package2.xml'; - } - - $packager = &$this->getPackager(); - $compress = empty($options['nocompress']) ? true : false; - $result = $packager->package($pkginfofile, $compress, $pkg2); - if (PEAR::isError($result)) { - return $this->raiseError($result); - } - - // Don't want output, only the package file name just created - if (isset($options['showname'])) { - $this->output = $result; - } - - if ($this->output) { - $this->ui->outputData($this->output, $command); - } - - return true; - } - - function doPackageValidate($command, $options, $params) - { - $this->output = ''; - if (count($params) < 1) { - $params[0] = 'package.xml'; - } - - $obj = &$this->getPackageFile($this->config, $this->_debug); - $obj->rawReturn(); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $info = $obj->fromTgzFile($params[0], PEAR_VALIDATE_NORMAL); - if (PEAR::isError($info)) { - $info = $obj->fromPackageFile($params[0], PEAR_VALIDATE_NORMAL); - } else { - $archive = $info->getArchiveFile(); - $tar = &new Archive_Tar($archive); - $tar->extract(dirname($info->getPackageFile())); - $info->setPackageFile(dirname($info->getPackageFile()) . DIRECTORY_SEPARATOR . - $info->getPackage() . '-' . $info->getVersion() . DIRECTORY_SEPARATOR . - basename($info->getPackageFile())); - } - - PEAR::staticPopErrorHandling(); - if (PEAR::isError($info)) { - return $this->raiseError($info); - } - - $valid = false; - if ($info->getPackagexmlVersion() == '2.0') { - if ($valid = $info->validate(PEAR_VALIDATE_NORMAL)) { - $info->flattenFileList(); - $valid = $info->validate(PEAR_VALIDATE_PACKAGING); - } - } else { - $valid = $info->validate(PEAR_VALIDATE_PACKAGING); - } - - $err = $warn = array(); - if ($errors = $info->getValidationWarnings()) { - foreach ($errors as $error) { - if ($error['level'] == 'warning') { - $warn[] = $error['message']; - } else { - $err[] = $error['message']; - } - } - } - - $this->_displayValidationResults($err, $warn); - $this->ui->outputData($this->output, $command); - return true; - } - - function doCvsTag($command, $options, $params) - { - $this->output = ''; - $_cmd = $command; - if (count($params) < 1) { - $help = $this->getHelp($command); - return $this->raiseError("$command: missing parameter: $help[0]"); - } - - $packageFile = realpath($params[0]); - $obj = &$this->getPackageFile($this->config, $this->_debug); - $info = $obj->fromAnyFile($packageFile, PEAR_VALIDATE_NORMAL); - if (PEAR::isError($info)) { - return $this->raiseError($info); - } - - $err = $warn = array(); - if (!$info->validate()) { - foreach ($info->getValidationWarnings() as $error) { - if ($error['level'] == 'warning') { - $warn[] = $error['message']; - } else { - $err[] = $error['message']; - } - } - } - - if (!$this->_displayValidationResults($err, $warn, true)) { - $this->ui->outputData($this->output, $command); - return $this->raiseError('CVS tag failed'); - } - - $version = $info->getVersion(); - $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $version); - $cvstag = "RELEASE_$cvsversion"; - $files = array_keys($info->getFilelist()); - $command = 'cvs'; - if (isset($options['quiet'])) { - $command .= ' -q'; - } - - if (isset($options['reallyquiet'])) { - $command .= ' -Q'; - } - - $command .= ' tag'; - if (isset($options['slide'])) { - $command .= ' -F'; - } - - if (isset($options['delete'])) { - $command .= ' -d'; - } - - $command .= ' ' . $cvstag . ' ' . escapeshellarg($params[0]); - array_shift($params); - if (count($params)) { - // add in additional files to be tagged - $files = array_merge($files, $params); - } - - $dir = dirname($packageFile); - $dir = substr($dir, strrpos($dir, '/') + 1); - foreach ($files as $file) { - if (!file_exists($file)) { - $file = $dir . DIRECTORY_SEPARATOR . $file; - } - $command .= ' ' . escapeshellarg($file); - } - - if ($this->config->get('verbose') > 1) { - $this->output .= "+ $command\n"; - } - - $this->output .= "+ $command\n"; - if (empty($options['dry-run'])) { - $fp = popen($command, "r"); - while ($line = fgets($fp, 1024)) { - $this->output .= rtrim($line)."\n"; - } - pclose($fp); - } - - $this->ui->outputData($this->output, $_cmd); - return true; - } - - function doCvsDiff($command, $options, $params) - { - $this->output = ''; - if (sizeof($params) < 1) { - $help = $this->getHelp($command); - return $this->raiseError("$command: missing parameter: $help[0]"); - } - - $file = realpath($params[0]); - $obj = &$this->getPackageFile($this->config, $this->_debug); - $info = $obj->fromAnyFile($file, PEAR_VALIDATE_NORMAL); - if (PEAR::isError($info)) { - return $this->raiseError($info); - } - - $err = $warn = array(); - if (!$info->validate()) { - foreach ($info->getValidationWarnings() as $error) { - if ($error['level'] == 'warning') { - $warn[] = $error['message']; - } else { - $err[] = $error['message']; - } - } - } - - if (!$this->_displayValidationResults($err, $warn, true)) { - $this->ui->outputData($this->output, $command); - return $this->raiseError('CVS diff failed'); - } - - $info1 = $info->getFilelist(); - $files = $info1; - $cmd = "cvs"; - if (isset($options['quiet'])) { - $cmd .= ' -q'; - unset($options['quiet']); - } - - if (isset($options['reallyquiet'])) { - $cmd .= ' -Q'; - unset($options['reallyquiet']); - } - - if (isset($options['release'])) { - $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $options['release']); - $cvstag = "RELEASE_$cvsversion"; - $options['revision'] = $cvstag; - unset($options['release']); - } - - $execute = true; - if (isset($options['dry-run'])) { - $execute = false; - unset($options['dry-run']); - } - - $cmd .= ' diff'; - // the rest of the options are passed right on to "cvs diff" - foreach ($options as $option => $optarg) { - $arg = $short = false; - if (isset($this->commands[$command]['options'][$option])) { - $arg = $this->commands[$command]['options'][$option]['arg']; - $short = $this->commands[$command]['options'][$option]['shortopt']; - } - $cmd .= $short ? " -$short" : " --$option"; - if ($arg && $optarg) { - $cmd .= ($short ? '' : '=') . escapeshellarg($optarg); - } - } - - foreach ($files as $file) { - $cmd .= ' ' . escapeshellarg($file['name']); - } - - if ($this->config->get('verbose') > 1) { - $this->output .= "+ $cmd\n"; - } - - if ($execute) { - $fp = popen($cmd, "r"); - while ($line = fgets($fp, 1024)) { - $this->output .= rtrim($line)."\n"; - } - pclose($fp); - } - - $this->ui->outputData($this->output, $command); - return true; - } - - function doPackageDependencies($command, $options, $params) - { - // $params[0] -> the PEAR package to list its information - if (count($params) !== 1) { - return $this->raiseError("bad parameter(s), try \"help $command\""); - } - - $obj = &$this->getPackageFile($this->config, $this->_debug); - $info = $obj->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL); - if (PEAR::isError($info)) { - return $this->raiseError($info); - } - - $deps = $info->getDeps(); - if (is_array($deps)) { - if ($info->getPackagexmlVersion() == '1.0') { - $data = array( - 'caption' => 'Dependencies for pear/' . $info->getPackage(), - 'border' => true, - 'headline' => array("Required?", "Type", "Name", "Relation", "Version"), - ); - - foreach ($deps as $d) { - if (isset($d['optional'])) { - if ($d['optional'] == 'yes') { - $req = 'No'; - } else { - $req = 'Yes'; - } - } else { - $req = 'Yes'; - } - - if (isset($this->_deps_rel_trans[$d['rel']])) { - $rel = $this->_deps_rel_trans[$d['rel']]; - } else { - $rel = $d['rel']; - } - - if (isset($this->_deps_type_trans[$d['type']])) { - $type = ucfirst($this->_deps_type_trans[$d['type']]); - } else { - $type = $d['type']; - } - - if (isset($d['name'])) { - $name = $d['name']; - } else { - $name = ''; - } - - if (isset($d['version'])) { - $version = $d['version']; - } else { - $version = ''; - } - - $data['data'][] = array($req, $type, $name, $rel, $version); - } - } else { // package.xml 2.0 dependencies display - require_once 'PEAR/Dependency2.php'; - $deps = $info->getDependencies(); - $reg = &$this->config->getRegistry(); - if (is_array($deps)) { - $d = new PEAR_Dependency2($this->config, array(), ''); - $data = array( - 'caption' => 'Dependencies for ' . $info->getPackage(), - 'border' => true, - 'headline' => array("Required?", "Type", "Name", 'Versioning', 'Group'), - ); - foreach ($deps as $type => $subd) { - $req = ($type == 'required') ? 'Yes' : 'No'; - if ($type == 'group') { - $group = $subd['attribs']['name']; - } else { - $group = ''; - } - - if (!isset($subd[0])) { - $subd = array($subd); - } - - foreach ($subd as $groupa) { - foreach ($groupa as $deptype => $depinfo) { - if ($deptype == 'attribs') { - continue; - } - - if ($deptype == 'pearinstaller') { - $deptype = 'pear Installer'; - } - - if (!isset($depinfo[0])) { - $depinfo = array($depinfo); - } - - foreach ($depinfo as $inf) { - $name = ''; - if (isset($inf['channel'])) { - $alias = $reg->channelAlias($inf['channel']); - if (!$alias) { - $alias = '(channel?) ' .$inf['channel']; - } - $name = $alias . '/'; - - } - if (isset($inf['name'])) { - $name .= $inf['name']; - } elseif (isset($inf['pattern'])) { - $name .= $inf['pattern']; - } else { - $name .= ''; - } - - if (isset($inf['uri'])) { - $name .= ' [' . $inf['uri'] . ']'; - } - - if (isset($inf['conflicts'])) { - $ver = 'conflicts'; - } else { - $ver = $d->_getExtraString($inf); - } - - $data['data'][] = array($req, ucfirst($deptype), $name, - $ver, $group); - } - } - } - } - } - } - - $this->ui->outputData($data, $command); - return true; - } - - // Fallback - $this->ui->outputData("This package does not have any dependencies.", $command); - } - - function doSign($command, $options, $params) - { - // should move most of this code into PEAR_Packager - // so it'll be easy to implement "pear package --sign" - if (count($params) !== 1) { - return $this->raiseError("bad parameter(s), try \"help $command\""); - } - - require_once 'System.php'; - require_once 'Archive/Tar.php'; - - if (!file_exists($params[0])) { - return $this->raiseError("file does not exist: $params[0]"); - } - - $obj = $this->getPackageFile($this->config, $this->_debug); - $info = $obj->fromTgzFile($params[0], PEAR_VALIDATE_NORMAL); - if (PEAR::isError($info)) { - return $this->raiseError($info); - } - - $tar = new Archive_Tar($params[0]); - $tmpdir = System::mktemp('-d pearsign'); - if (!$tar->extractList('package2.xml package.xml package.sig', $tmpdir)) { - return $this->raiseError("failed to extract tar file"); - } - - if (file_exists("$tmpdir/package.sig")) { - return $this->raiseError("package already signed"); - } - - $packagexml = 'package.xml'; - if (file_exists("$tmpdir/package2.xml")) { - $packagexml = 'package2.xml'; - } - - if (file_exists("$tmpdir/package.sig")) { - unlink("$tmpdir/package.sig"); - } - - if (!file_exists("$tmpdir/$packagexml")) { - return $this->raiseError("Extracted file $tmpdir/$packagexml not found."); - } - - $input = $this->ui->userDialog($command, - array('GnuPG Passphrase'), - array('password')); - if (!isset($input[0])) { - //use empty passphrase - $input[0] = ''; - } - - $devnull = (isset($options['verbose'])) ? '' : ' 2>/dev/null'; - $gpg = popen("gpg --batch --passphrase-fd 0 --armor --detach-sign --output $tmpdir/package.sig $tmpdir/$packagexml" . $devnull, "w"); - if (!$gpg) { - return $this->raiseError("gpg command failed"); - } - - fwrite($gpg, "$input[0]\n"); - if (pclose($gpg) || !file_exists("$tmpdir/package.sig")) { - return $this->raiseError("gpg sign failed"); - } - - if (!$tar->addModify("$tmpdir/package.sig", '', $tmpdir)) { - return $this->raiseError('failed adding signature to file'); - } - - $this->ui->outputData("Package signed.", $command); - return true; - } - - /** - * For unit testing purposes - */ - function &getInstaller(&$ui) - { - if (!class_exists('PEAR_Installer')) { - require_once 'PEAR/Installer.php'; - } - $a = &new PEAR_Installer($ui); - return $a; - } - - /** - * For unit testing purposes - */ - function &getCommandPackaging(&$ui, &$config) - { - if (!class_exists('PEAR_Command_Packaging')) { - if ($fp = @fopen('PEAR/Command/Packaging.php', 'r', true)) { - fclose($fp); - include_once 'PEAR/Command/Packaging.php'; - } - } - - if (class_exists('PEAR_Command_Packaging')) { - $a = &new PEAR_Command_Packaging($ui, $config); - } else { - $a = null; - } - - return $a; - } - - function doMakeRPM($command, $options, $params) - { - - // Check to see if PEAR_Command_Packaging is installed, and - // transparently switch to use the "make-rpm-spec" command from it - // instead, if it does. Otherwise, continue to use the old version - // of "makerpm" supplied with this package (PEAR). - $packaging_cmd = $this->getCommandPackaging($this->ui, $this->config); - if ($packaging_cmd !== null) { - $this->ui->outputData('PEAR_Command_Packaging is installed; using '. - 'newer "make-rpm-spec" command instead'); - return $packaging_cmd->run('make-rpm-spec', $options, $params); - } - - $this->ui->outputData('WARNING: "pear makerpm" is no longer available; an '. - 'improved version is available via "pear make-rpm-spec", which '. - 'is available by installing PEAR_Command_Packaging'); - return true; - } - - function doConvert($command, $options, $params) - { - $packagexml = isset($params[0]) ? $params[0] : 'package.xml'; - $newpackagexml = isset($params[1]) ? $params[1] : dirname($packagexml) . - DIRECTORY_SEPARATOR . 'package2.xml'; - $pkg = &$this->getPackageFile($this->config, $this->_debug); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $pf = $pkg->fromPackageFile($packagexml, PEAR_VALIDATE_NORMAL); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($pf)) { - if (is_array($pf->getUserInfo())) { - foreach ($pf->getUserInfo() as $warning) { - $this->ui->outputData($warning['message']); - } - } - return $this->raiseError($pf); - } - - if (is_a($pf, 'PEAR_PackageFile_v2')) { - $this->ui->outputData($packagexml . ' is already a package.xml version 2.0'); - return true; - } - - $gen = &$pf->getDefaultGenerator(); - $newpf = &$gen->toV2(); - $newpf->setPackagefile($newpackagexml); - $gen = &$newpf->getDefaultGenerator(); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $state = (isset($options['flat']) ? PEAR_VALIDATE_PACKAGING : PEAR_VALIDATE_NORMAL); - $saved = $gen->toPackageFile(dirname($newpackagexml), $state, basename($newpackagexml)); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($saved)) { - if (is_array($saved->getUserInfo())) { - foreach ($saved->getUserInfo() as $warning) { - $this->ui->outputData($warning['message']); - } - } - - $this->ui->outputData($saved->getMessage()); - return true; - } - - $this->ui->outputData('Wrote new version 2.0 package.xml to "' . $saved . '"'); - return true; - } -}PEAR-1.8.0/PEAR/Command/Pickle.xml100777 764 764 2233 100777 11355 - - Build PECL Package - doPackage - pi - - - Z - Do not gzip the package file - - - n - Print the name of the packaged file. - - - [descfile] -Creates a PECL package from its package2.xml file. - -An automatic conversion will be made to a package.xml 1.0 and written out to -disk in the current directory as "package.xml". Note that -only simple package.xml 2.0 will be converted. package.xml 2.0 with: - - - dependency types other than required/optional PECL package/ext/php/pearinstaller - - more than one extsrcrelease or zendextsrcrelease - - zendextbinrelease, extbinrelease, phprelease, or bundle release type - - dependency groups - - ignore tags in release filelist - - tasks other than replace - - custom roles - -will cause pickle to fail, and output an error message. If your package2.xml -uses any of these features, you are best off using PEAR_PackageFileManager to -generate both package.xml. - - -PEAR-1.8.0/PEAR/Command/Pickle.php100664 764 764 37212 100664 11357 PEAR-1.9.0/PEAR/Command/Package.php100664 764 764 114657 100664 11535 + * @author Martin Jansen * @author Greg Beaver - * @copyright 2005-2009 The Authors + * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Pickle.php,v 1.13 2009/02/24 23:39:29 dufuz Exp $ + * @version CVS: $Id: Package.php 287559 2009-08-21 22:33:10Z dufuz $ * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.1 + * @since File available since Release 0.1 */ /** @@ -13059,21 +12407,23 @@ * * @category pear * @package PEAR + * @author Stig Bakken + * @author Martin Jansen * @author Greg Beaver - * @copyright 2005-2009 The Authors + * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: @package_version@ * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.1 + * @since Class available since Release 0.1 */ -class PEAR_Command_Pickle extends PEAR_Command_Common +class PEAR_Command_Package extends PEAR_Command_Common { var $commands = array( - 'pickle' => array( - 'summary' => 'Build PECL Package', + 'package' => array( + 'summary' => 'Build Package', 'function' => 'doPackage', - 'shortcut' => 'pi', + 'shortcut' => 'p', 'options' => array( 'nocompress' => array( 'shortopt' => 'Z', @@ -13084,71 +12434,274 @@ 'doc' => 'Print the name of the packaged file.', ), ), - 'doc' => '[descfile] -Creates a PECL package from its package2.xml file. - -An automatic conversion will be made to a package.xml 1.0 and written out to -disk in the current directory as "package.xml". Note that -only simple package.xml 2.0 will be converted. package.xml 2.0 with: + 'doc' => '[descfile] [descfile2] +Creates a PEAR package from its description file (usually called +package.xml). If a second packagefile is passed in, then +the packager will check to make sure that one is a package.xml +version 1.0, and the other is a package.xml version 2.0. The +package.xml version 1.0 will be saved as "package.xml" in the archive, +and the other as "package2.xml" in the archive" +' + ), + 'package-validate' => array( + 'summary' => 'Validate Package Consistency', + 'function' => 'doPackageValidate', + 'shortcut' => 'pv', + 'options' => array(), + 'doc' => ' +', + ), + 'cvsdiff' => array( + 'summary' => 'Run a "cvs diff" for all files in a package', + 'function' => 'doCvsDiff', + 'shortcut' => 'cd', + 'options' => array( + 'quiet' => array( + 'shortopt' => 'q', + 'doc' => 'Be quiet', + ), + 'reallyquiet' => array( + 'shortopt' => 'Q', + 'doc' => 'Be really quiet', + ), + 'date' => array( + 'shortopt' => 'D', + 'doc' => 'Diff against revision of DATE', + 'arg' => 'DATE', + ), + 'release' => array( + 'shortopt' => 'R', + 'doc' => 'Diff against tag for package release REL', + 'arg' => 'REL', + ), + 'revision' => array( + 'shortopt' => 'r', + 'doc' => 'Diff against revision REV', + 'arg' => 'REV', + ), + 'context' => array( + 'shortopt' => 'c', + 'doc' => 'Generate context diff', + ), + 'unified' => array( + 'shortopt' => 'u', + 'doc' => 'Generate unified diff', + ), + 'ignore-case' => array( + 'shortopt' => 'i', + 'doc' => 'Ignore case, consider upper- and lower-case letters equivalent', + ), + 'ignore-whitespace' => array( + 'shortopt' => 'b', + 'doc' => 'Ignore changes in amount of white space', + ), + 'ignore-blank-lines' => array( + 'shortopt' => 'B', + 'doc' => 'Ignore changes that insert or delete blank lines', + ), + 'brief' => array( + 'doc' => 'Report only whether the files differ, no details', + ), + 'dry-run' => array( + 'shortopt' => 'n', + 'doc' => 'Don\'t do anything, just pretend', + ), + ), + 'doc' => ' +Compares all the files in a package. Without any options, this +command will compare the current code with the last checked-in code. +Using the -r or -R option you may compare the current code with that +of a specific release. +', + ), + 'svntag' => array( + 'summary' => 'Set SVN Release Tag', + 'function' => 'doSvnTag', + 'shortcut' => 'sv', + 'options' => array( + 'quiet' => array( + 'shortopt' => 'q', + 'doc' => 'Be quiet', + ), + 'slide' => array( + 'shortopt' => 'F', + 'doc' => 'Move (slide) tag if it exists', + ), + 'delete' => array( + 'shortopt' => 'd', + 'doc' => 'Remove tag', + ), + 'dry-run' => array( + 'shortopt' => 'n', + 'doc' => 'Don\'t do anything, just pretend', + ), + ), + 'doc' => ' [files...] + Sets a SVN tag on all files in a package. Use this command after you have + packaged a distribution tarball with the "package" command to tag what + revisions of what files were in that release. If need to fix something + after running cvstag once, but before the tarball is released to the public, + use the "slide" option to move the release tag. + + to include files (such as a second package.xml, or tests not included in the + release), pass them as additional parameters. + ', + ), + 'cvstag' => array( + 'summary' => 'Set CVS Release Tag', + 'function' => 'doCvsTag', + 'shortcut' => 'ct', + 'options' => array( + 'quiet' => array( + 'shortopt' => 'q', + 'doc' => 'Be quiet', + ), + 'reallyquiet' => array( + 'shortopt' => 'Q', + 'doc' => 'Be really quiet', + ), + 'slide' => array( + 'shortopt' => 'F', + 'doc' => 'Move (slide) tag if it exists', + ), + 'delete' => array( + 'shortopt' => 'd', + 'doc' => 'Remove tag', + ), + 'dry-run' => array( + 'shortopt' => 'n', + 'doc' => 'Don\'t do anything, just pretend', + ), + ), + 'doc' => ' [files...] +Sets a CVS tag on all files in a package. Use this command after you have +packaged a distribution tarball with the "package" command to tag what +revisions of what files were in that release. If need to fix something +after running cvstag once, but before the tarball is released to the public, +use the "slide" option to move the release tag. - - dependency types other than required/optional PECL package/ext/php/pearinstaller - - more than one extsrcrelease or zendextsrcrelease - - zendextbinrelease, extbinrelease, phprelease, or bundle release type - - dependency groups - - ignore tags in release filelist - - tasks other than replace - - custom roles +to include files (such as a second package.xml, or tests not included in the +release), pass them as additional parameters. +', + ), + 'package-dependencies' => array( + 'summary' => 'Show package dependencies', + 'function' => 'doPackageDependencies', + 'shortcut' => 'pd', + 'options' => array(), + 'doc' => ' or or +List all dependencies the package has. +Can take a tgz / tar file, package.xml or a package name of an installed package.' + ), + 'sign' => array( + 'summary' => 'Sign a package distribution file', + 'function' => 'doSign', + 'shortcut' => 'si', + 'options' => array( + 'verbose' => array( + 'shortopt' => 'v', + 'doc' => 'Display GnuPG output', + ), + ), + 'doc' => ' +Signs a package distribution (.tar or .tgz) file with GnuPG.', + ), + 'makerpm' => array( + 'summary' => 'Builds an RPM spec file from a PEAR package', + 'function' => 'doMakeRPM', + 'shortcut' => 'rpm', + 'options' => array( + 'spec-template' => array( + 'shortopt' => 't', + 'arg' => 'FILE', + 'doc' => 'Use FILE as RPM spec file template' + ), + 'rpm-pkgname' => array( + 'shortopt' => 'p', + 'arg' => 'FORMAT', + 'doc' => 'Use FORMAT as format string for RPM package name, %s is replaced +by the PEAR package name, defaults to "PEAR::%s".', + ), + ), + 'doc' => ' -will cause pickle to fail, and output an error message. If your package2.xml -uses any of these features, you are best off using PEAR_PackageFileManager to -generate both package.xml. +Creates an RPM .spec file for wrapping a PEAR package inside an RPM +package. Intended to be used from the SPECS directory, with the PEAR +package tarball in the SOURCES directory: + +$ pear makerpm ../SOURCES/Net_Socket-1.0.tgz +Wrote RPM spec file PEAR::Net_Geo-1.0.spec +$ rpm -bb PEAR::Net_Socket-1.0.spec +... +Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm +', + ), + 'convert' => array( + 'summary' => 'Convert a package.xml 1.0 to package.xml 2.0 format', + 'function' => 'doConvert', + 'shortcut' => 'c2', + 'options' => array( + 'flat' => array( + 'shortopt' => 'f', + 'doc' => 'do not beautify the filelist.', + ), + ), + 'doc' => '[descfile] [descfile2] +Converts a package.xml in 1.0 format into a package.xml +in 2.0 format. The new file will be named package2.xml by default, +and package.xml will be used as the old file by default. +This is not the most intelligent conversion, and should only be +used for automated conversion or learning the format. ' ), ); + var $output; + /** * PEAR_Command_Package constructor. * * @access public */ - function PEAR_Command_Pickle(&$ui, &$config) + function PEAR_Command_Package(&$ui, &$config) { parent::PEAR_Command_Common($ui, $config); } - /** - * For unit-testing ease - * - * @return PEAR_Packager - */ + function _displayValidationResults($err, $warn, $strict = false) + { + foreach ($err as $e) { + $this->output .= "Error: $e\n"; + } + foreach ($warn as $w) { + $this->output .= "Warning: $w\n"; + } + $this->output .= sprintf('Validation: %d error(s), %d warning(s)'."\n", + sizeof($err), sizeof($warn)); + if ($strict && count($err) > 0) { + $this->output .= "Fix these errors and try again."; + return false; + } + return true; + } + function &getPackager() { if (!class_exists('PEAR_Packager')) { require_once 'PEAR/Packager.php'; } - $a = &new PEAR_Packager; return $a; } - /** - * For unit-testing ease - * - * @param PEAR_Config $config - * @param bool $debug - * @param string|null $tmpdir - * @return PEAR_PackageFile - */ function &getPackageFile($config, $debug = false, $tmpdir = null) { if (!class_exists('PEAR_Common')) { require_once 'PEAR/Common.php'; } - if (!class_exists('PEAR_PackageFile')) { require_once 'PEAR/PackageFile.php'; } - $a = &new PEAR_PackageFile($config, $debug, $tmpdir); $common = new PEAR_Common; $common->ui = $this->ui; @@ -13159,372 +12712,828 @@ function doPackage($command, $options, $params) { $this->output = ''; - $pkginfofile = isset($params[0]) ? $params[0] : 'package2.xml'; - $packager = &$this->getPackager(); - if (PEAR::isError($err = $this->_convertPackage($pkginfofile))) { - return $err; + $pkginfofile = isset($params[0]) ? $params[0] : 'package.xml'; + $pkg2 = isset($params[1]) ? $params[1] : null; + if (!$pkg2 && !isset($params[0]) && file_exists('package2.xml')) { + $pkg2 = 'package2.xml'; } + $packager = &$this->getPackager(); $compress = empty($options['nocompress']) ? true : false; - $result = $packager->package($pkginfofile, $compress, 'package.xml'); + $result = $packager->package($pkginfofile, $compress, $pkg2); if (PEAR::isError($result)) { return $this->raiseError($result); } // Don't want output, only the package file name just created if (isset($options['showname'])) { - $this->ui->outputData($result, $command); + $this->output = $result; + } + + if ($this->output) { + $this->ui->outputData($this->output, $command); } return true; } - function _convertPackage($packagexml) + function doPackageValidate($command, $options, $params) { - $pkg = &$this->getPackageFile($this->config); - $pf2 = &$pkg->fromPackageFile($packagexml, PEAR_VALIDATE_NORMAL); - if (!is_a($pf2, 'PEAR_PackageFile_v2')) { - return $this->raiseError('Cannot process "' . - $packagexml . '", is not a package.xml 2.0'); + $this->output = ''; + if (count($params) < 1) { + $params[0] = 'package.xml'; } - require_once 'PEAR/PackageFile/v1.php'; - $pf = new PEAR_PackageFile_v1; - $pf->setConfig($this->config); - if ($pf2->getPackageType() != 'extsrc' && $pf2->getPackageType() != 'zendextsrc') { - return $this->raiseError('Cannot safely convert "' . $packagexml . - '", is not an extension source package. Using a PEAR_PackageFileManager-based ' . - 'script is an option'); + $obj = &$this->getPackageFile($this->config, $this->_debug); + $obj->rawReturn(); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $info = $obj->fromTgzFile($params[0], PEAR_VALIDATE_NORMAL); + if (PEAR::isError($info)) { + $info = $obj->fromPackageFile($params[0], PEAR_VALIDATE_NORMAL); + } else { + $archive = $info->getArchiveFile(); + $tar = &new Archive_Tar($archive); + $tar->extract(dirname($info->getPackageFile())); + $info->setPackageFile(dirname($info->getPackageFile()) . DIRECTORY_SEPARATOR . + $info->getPackage() . '-' . $info->getVersion() . DIRECTORY_SEPARATOR . + basename($info->getPackageFile())); } - if (is_array($pf2->getUsesRole())) { - return $this->raiseError('Cannot safely convert "' . $packagexml . - '", contains custom roles. Using a PEAR_PackageFileManager-based script or ' . - 'the convert command is an option'); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($info)) { + return $this->raiseError($info); } - if (is_array($pf2->getUsesTask())) { - return $this->raiseError('Cannot safely convert "' . $packagexml . - '", contains custom tasks. Using a PEAR_PackageFileManager-based script or ' . - 'the convert command is an option'); + $valid = false; + if ($info->getPackagexmlVersion() == '2.0') { + if ($valid = $info->validate(PEAR_VALIDATE_NORMAL)) { + $info->flattenFileList(); + $valid = $info->validate(PEAR_VALIDATE_PACKAGING); + } + } else { + $valid = $info->validate(PEAR_VALIDATE_PACKAGING); } - $deps = $pf2->getDependencies(); - if (isset($deps['group'])) { - return $this->raiseError('Cannot safely convert "' . $packagexml . - '", contains dependency groups. Using a PEAR_PackageFileManager-based script ' . - 'or the convert command is an option'); + $err = $warn = array(); + if ($errors = $info->getValidationWarnings()) { + foreach ($errors as $error) { + if ($error['level'] == 'warning') { + $warn[] = $error['message']; + } else { + $err[] = $error['message']; + } + } } - if (isset($deps['required']['subpackage']) || - isset($deps['optional']['subpackage'])) { - return $this->raiseError('Cannot safely convert "' . $packagexml . - '", contains subpackage dependencies. Using a PEAR_PackageFileManager-based '. - 'script is an option'); + $this->_displayValidationResults($err, $warn); + $this->ui->outputData($this->output, $command); + return true; + } + + function doSvnTag($command, $options, $params) + { + $this->output = ''; + $_cmd = $command; + if (count($params) < 1) { + $help = $this->getHelp($command); + return $this->raiseError("$command: missing parameter: $help[0]"); } - if (isset($deps['required']['os'])) { - return $this->raiseError('Cannot safely convert "' . $packagexml . - '", contains os dependencies. Using a PEAR_PackageFileManager-based '. - 'script is an option'); + $packageFile = realpath($params[0]); + $dir = dirname($packageFile); + $dir = substr($dir, strrpos($dir, '/') + 1); + $obj = &$this->getPackageFile($this->config, $this->_debug); + $info = $obj->fromAnyFile($packageFile, PEAR_VALIDATE_NORMAL); + if (PEAR::isError($info)) { + return $this->raiseError($info); } - if (isset($deps['required']['arch'])) { - return $this->raiseError('Cannot safely convert "' . $packagexml . - '", contains arch dependencies. Using a PEAR_PackageFileManager-based '. - 'script is an option'); + $err = $warn = array(); + if (!$info->validate()) { + foreach ($info->getValidationWarnings() as $error) { + if ($error['level'] == 'warning') { + $warn[] = $error['message']; + } else { + $err[] = $error['message']; + } + } } - $pf->setPackage($pf2->getPackage()); - $pf->setSummary($pf2->getSummary()); - $pf->setDescription($pf2->getDescription()); - foreach ($pf2->getMaintainers() as $maintainer) { - $pf->addMaintainer($maintainer['role'], $maintainer['handle'], - $maintainer['name'], $maintainer['email']); + if (!$this->_displayValidationResults($err, $warn, true)) { + $this->ui->outputData($this->output, $command); + return $this->raiseError('SVN tag failed'); } - $pf->setVersion($pf2->getVersion()); - $pf->setDate($pf2->getDate()); - $pf->setLicense($pf2->getLicense()); - $pf->setState($pf2->getState()); - $pf->setNotes($pf2->getNotes()); - $pf->addPhpDep($deps['required']['php']['min'], 'ge'); - if (isset($deps['required']['php']['max'])) { - $pf->addPhpDep($deps['required']['php']['max'], 'le'); + $version = $info->getVersion(); + $package = $info->getName(); + $svntag = "$package-$version"; + + if (isset($options['delete'])) { + return $this->_svnRemoveTag($version, $package, $svntag, $packageFile, $options); } - if (isset($deps['required']['package'])) { - if (!isset($deps['required']['package'][0])) { - $deps['required']['package'] = array($deps['required']['package']); - } + $path = $this->_svnFindPath($packageFile); - foreach ($deps['required']['package'] as $dep) { - if (!isset($dep['channel'])) { - return $this->raiseError('Cannot safely convert "' . $packagexml . '"' . - ' contains uri-based dependency on a package. Using a ' . - 'PEAR_PackageFileManager-based script is an option'); - } + // Check if there are any modified files + $fp = popen('svn st --xml ' . dirname($packageFile), "r"); + $out = ''; + while ($line = fgets($fp, 1024)) { + $out .= rtrim($line)."\n"; + } + pclose($fp); - if ($dep['channel'] != 'pear.php.net' - && $dep['channel'] != 'pecl.php.net' - && $dep['channel'] != 'doc.php.net') { - return $this->raiseError('Cannot safely convert "' . $packagexml . '"' . - ' contains dependency on a non-standard channel package. Using a ' . - 'PEAR_PackageFileManager-based script is an option'); - } + if (!isset($options['quiet']) && strpos($out, 'item="modified"')) { + $params = array(array( + 'name' => 'modified', + 'type' => 'yesno', + 'default' => 'no', + 'prompt' => 'You have files in your SVN checkout (' . $path['from'] . ') that have been modified but not commited, do you still want to tag ' . $version . '?', + )); + $answers = $this->ui->confirmDialog($params); - if (isset($dep['conflicts'])) { - return $this->raiseError('Cannot safely convert "' . $packagexml . '"' . - ' contains conflicts dependency. Using a ' . - 'PEAR_PackageFileManager-based script is an option'); - } + if (!in_array($answers['modified'], array('y', 'yes', 'on', '1'))) { + return true; + } + } - if (isset($dep['exclude'])) { - $this->ui->outputData('WARNING: exclude tags are ignored in conversion'); - } + if (isset($options['slide'])) { + $this->_svnRemoveTag($version, $package, $svntag, $packageFile, $options); + } - if (isset($dep['min'])) { - $pf->addPackageDep($dep['name'], $dep['min'], 'ge'); - } + // Check if tag already exists + $releaseTag = $path['local']['base'] . 'tags/' . $svntag; + $existsCommand = 'svn ls ' . $path['base'] . 'tags/'; - if (isset($dep['max'])) { - $pf->addPackageDep($dep['name'], $dep['max'], 'le'); + $fp = popen($existsCommand, "r"); + $out = ''; + while ($line = fgets($fp, 1024)) { + $out .= rtrim($line)."\n"; + } + pclose($fp); + + if (in_array($svntag . '/', explode("\n", $out))) { + $this->ui->outputData($this->output, $command); + return $this->raiseError('SVN tag ' . $svntag . ' for ' . $package . ' already exists.'); + } else { + $makeCommand = 'svn mkdir ' . $releaseTag; + $this->output .= "+ $makeCommand\n"; + if (empty($options['dry-run'])) { + // We need to create the tag dir. + $fp = popen($makeCommand, "r"); + $out = ''; + while ($line = fgets($fp, 1024)) { + $out .= rtrim($line)."\n"; } + pclose($fp); + $this->output .= "$out\n"; } } - if (isset($deps['required']['extension'])) { - if (!isset($deps['required']['extension'][0])) { - $deps['required']['extension'] = array($deps['required']['extension']); + $command = 'svn'; + if (isset($options['quiet'])) { + $command .= ' -q'; + } + + $command .= ' copy --parents '; + + $dir = dirname($packageFile); + $dir = substr($dir, strrpos($dir, '/') + 1); + $files = array_keys($info->getFilelist()); + $commands = array(); + foreach ($files as $file) { + if (!file_exists($file)) { + $file = $dir . DIRECTORY_SEPARATOR . $file; } + $commands[] = $command . ' ' . escapeshellarg($file) . ' ' . + escapeshellarg($releaseTag . DIRECTORY_SEPARATOR . $file); + } - foreach ($deps['required']['extension'] as $dep) { - if (isset($dep['conflicts'])) { - return $this->raiseError('Cannot safely convert "' . $packagexml . '"' . - ' contains conflicts dependency. Using a ' . - 'PEAR_PackageFileManager-based script is an option'); + $this->output .= implode("\n", $commands) . "\n"; + if (empty($options['dry-run'])) { + foreach ($commands as $command) { + $fp = popen($command, "r"); + while ($line = fgets($fp, 1024)) { + $this->output .= rtrim($line)."\n"; } + pclose($fp); + } + } - if (isset($dep['exclude'])) { - $this->ui->outputData('WARNING: exclude tags are ignored in conversion'); - } + $command = 'svn ci -m "Tagging the ' . $version . ' release" ' . $releaseTag . "\n"; + $this->output .= "+ $command\n"; + if (empty($options['dry-run'])) { + $fp = popen($command, "r"); + while ($line = fgets($fp, 1024)) { + $this->output .= rtrim($line)."\n"; + } + pclose($fp); + } - if (isset($dep['min'])) { - $pf->addExtensionDep($dep['name'], $dep['min'], 'ge'); - } + $this->ui->outputData($this->output, $_cmd); + return true; + } - if (isset($dep['max'])) { - $pf->addExtensionDep($dep['name'], $dep['max'], 'le'); - } - } + function _svnFindPath($file) + { + $xml = ''; + $command = "svn info --xml $file"; + $fp = popen($command, "r"); + while ($line = fgets($fp, 1024)) { + $xml .= rtrim($line)."\n"; } + pclose($fp); + $url_tag = strpos($xml, ''); + $url = substr($xml, $url_tag + 5, strpos($xml, '', $url_tag + 5) - ($url_tag + 5)); - if (isset($deps['optional']['package'])) { - if (!isset($deps['optional']['package'][0])) { - $deps['optional']['package'] = array($deps['optional']['package']); + $path = array(); + $path['from'] = substr($url, 0, strrpos($url, '/')); + $path['base'] = substr($path['from'], 0, strrpos($path['from'], '/') + 1); + + // Figure out the local paths + $pos = strpos($file, '/trunk/'); + if ($pos === false) { + $pos = strpos($file, '/branches/'); + } + $path['local']['base'] = substr($file, 0, $pos + 1); + + return $path; + } + + function _svnRemoveTag($version, $package, $tag, $packageFile, $options) + { + $command = 'svn'; + + if (isset($options['quiet'])) { + $command .= ' -q'; + } + + $command .= ' remove'; + $command .= ' -m "Removing tag for the ' . $version . ' release."'; + + $path = $this->_svnFindPath($packageFile); + $command .= ' ' . $path['base'] . 'tags/' . $tag; + + + if ($this->config->get('verbose') > 1) { + $this->output .= "+ $command\n"; + } + + $this->output .= "+ $command\n"; + if (empty($options['dry-run'])) { + $fp = popen($command, "r"); + while ($line = fgets($fp, 1024)) { + $this->output .= rtrim($line)."\n"; } + pclose($fp); + } - foreach ($deps['optional']['package'] as $dep) { - if (!isset($dep['channel'])) { - return $this->raiseError('Cannot safely convert "' . $packagexml . '"' . - ' contains uri-based dependency on a package. Using a ' . - 'PEAR_PackageFileManager-based script is an option'); - } + $this->ui->outputData($this->output, $command); + return true; + } - if ($dep['channel'] != 'pear.php.net' - && $dep['channel'] != 'pecl.php.net' - && $dep['channel'] != 'doc.php.net') { - return $this->raiseError('Cannot safely convert "' . $packagexml . '"' . - ' contains dependency on a non-standard channel package. Using a ' . - 'PEAR_PackageFileManager-based script is an option'); - } + function doCvsTag($command, $options, $params) + { + $this->output = ''; + $_cmd = $command; + if (count($params) < 1) { + $help = $this->getHelp($command); + return $this->raiseError("$command: missing parameter: $help[0]"); + } - if (isset($dep['exclude'])) { - $this->ui->outputData('WARNING: exclude tags are ignored in conversion'); - } + $packageFile = realpath($params[0]); + $obj = &$this->getPackageFile($this->config, $this->_debug); + $info = $obj->fromAnyFile($packageFile, PEAR_VALIDATE_NORMAL); + if (PEAR::isError($info)) { + return $this->raiseError($info); + } - if (isset($dep['min'])) { - $pf->addPackageDep($dep['name'], $dep['min'], 'ge', 'yes'); + $err = $warn = array(); + if (!$info->validate()) { + foreach ($info->getValidationWarnings() as $error) { + if ($error['level'] == 'warning') { + $warn[] = $error['message']; + } else { + $err[] = $error['message']; } + } + } - if (isset($dep['max'])) { - $pf->addPackageDep($dep['name'], $dep['max'], 'le', 'yes'); - } + if (!$this->_displayValidationResults($err, $warn, true)) { + $this->ui->outputData($this->output, $command); + return $this->raiseError('CVS tag failed'); + } + + $version = $info->getVersion(); + $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $version); + $cvstag = "RELEASE_$cvsversion"; + $files = array_keys($info->getFilelist()); + $command = 'cvs'; + if (isset($options['quiet'])) { + $command .= ' -q'; + } + + if (isset($options['reallyquiet'])) { + $command .= ' -Q'; + } + + $command .= ' tag'; + if (isset($options['slide'])) { + $command .= ' -F'; + } + + if (isset($options['delete'])) { + $command .= ' -d'; + } + + $command .= ' ' . $cvstag . ' ' . escapeshellarg($params[0]); + array_shift($params); + if (count($params)) { + // add in additional files to be tagged + $files = array_merge($files, $params); + } + + $dir = dirname($packageFile); + $dir = substr($dir, strrpos($dir, '/') + 1); + foreach ($files as $file) { + if (!file_exists($file)) { + $file = $dir . DIRECTORY_SEPARATOR . $file; } + $command .= ' ' . escapeshellarg($file); } - if (isset($deps['optional']['extension'])) { - if (!isset($deps['optional']['extension'][0])) { - $deps['optional']['extension'] = array($deps['optional']['extension']); + if ($this->config->get('verbose') > 1) { + $this->output .= "+ $command\n"; + } + + $this->output .= "+ $command\n"; + if (empty($options['dry-run'])) { + $fp = popen($command, "r"); + while ($line = fgets($fp, 1024)) { + $this->output .= rtrim($line)."\n"; } + pclose($fp); + } - foreach ($deps['optional']['extension'] as $dep) { - if (isset($dep['exclude'])) { - $this->ui->outputData('WARNING: exclude tags are ignored in conversion'); - } + $this->ui->outputData($this->output, $_cmd); + return true; + } - if (isset($dep['min'])) { - $pf->addExtensionDep($dep['name'], $dep['min'], 'ge', 'yes'); - } + function doCvsDiff($command, $options, $params) + { + $this->output = ''; + if (sizeof($params) < 1) { + $help = $this->getHelp($command); + return $this->raiseError("$command: missing parameter: $help[0]"); + } - if (isset($dep['max'])) { - $pf->addExtensionDep($dep['name'], $dep['max'], 'le', 'yes'); + $file = realpath($params[0]); + $obj = &$this->getPackageFile($this->config, $this->_debug); + $info = $obj->fromAnyFile($file, PEAR_VALIDATE_NORMAL); + if (PEAR::isError($info)) { + return $this->raiseError($info); + } + + $err = $warn = array(); + if (!$info->validate()) { + foreach ($info->getValidationWarnings() as $error) { + if ($error['level'] == 'warning') { + $warn[] = $error['message']; + } else { + $err[] = $error['message']; } } } - $contents = $pf2->getContents(); - $release = $pf2->getReleases(); - if (isset($releases[0])) { - return $this->raiseError('Cannot safely process "' . $packagexml . '" contains ' - . 'multiple extsrcrelease/zendextsrcrelease tags. Using a PEAR_PackageFileManager-based script ' . - 'or the convert command is an option'); + if (!$this->_displayValidationResults($err, $warn, true)) { + $this->ui->outputData($this->output, $command); + return $this->raiseError('CVS diff failed'); } - if ($configoptions = $pf2->getConfigureOptions()) { - foreach ($configoptions as $option) { - $default = isset($option['default']) ? $option['default'] : false; - $pf->addConfigureOption($option['name'], $option['prompt'], $default); + $info1 = $info->getFilelist(); + $files = $info1; + $cmd = "cvs"; + if (isset($options['quiet'])) { + $cmd .= ' -q'; + unset($options['quiet']); + } + + if (isset($options['reallyquiet'])) { + $cmd .= ' -Q'; + unset($options['reallyquiet']); + } + + if (isset($options['release'])) { + $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $options['release']); + $cvstag = "RELEASE_$cvsversion"; + $options['revision'] = $cvstag; + unset($options['release']); + } + + $execute = true; + if (isset($options['dry-run'])) { + $execute = false; + unset($options['dry-run']); + } + + $cmd .= ' diff'; + // the rest of the options are passed right on to "cvs diff" + foreach ($options as $option => $optarg) { + $arg = $short = false; + if (isset($this->commands[$command]['options'][$option])) { + $arg = $this->commands[$command]['options'][$option]['arg']; + $short = $this->commands[$command]['options'][$option]['shortopt']; + } + $cmd .= $short ? " -$short" : " --$option"; + if ($arg && $optarg) { + $cmd .= ($short ? '' : '=') . escapeshellarg($optarg); } } - if (isset($release['filelist']['ignore'])) { - return $this->raiseError('Cannot safely process "' . $packagexml . '" contains ' - . 'ignore tags. Using a PEAR_PackageFileManager-based script or the convert' . - ' command is an option'); + foreach ($files as $file) { + $cmd .= ' ' . escapeshellarg($file['name']); } - if (isset($release['filelist']['install']) && - !isset($release['filelist']['install'][0])) { - $release['filelist']['install'] = array($release['filelist']['install']); + if ($this->config->get('verbose') > 1) { + $this->output .= "+ $cmd\n"; } - if (isset($contents['dir']['attribs']['baseinstalldir'])) { - $baseinstalldir = $contents['dir']['attribs']['baseinstalldir']; + if ($execute) { + $fp = popen($cmd, "r"); + while ($line = fgets($fp, 1024)) { + $this->output .= rtrim($line)."\n"; + } + pclose($fp); + } + + $this->ui->outputData($this->output, $command); + return true; + } + + function doPackageDependencies($command, $options, $params) + { + // $params[0] -> the PEAR package to list its information + if (count($params) !== 1) { + return $this->raiseError("bad parameter(s), try \"help $command\""); + } + + $obj = &$this->getPackageFile($this->config, $this->_debug); + if (is_file($params[0]) || strpos($params[0], '.xml') > 0) { + $info = $obj->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL); } else { - $baseinstalldir = false; + $reg = $this->config->getRegistry(); + $info = $obj->fromArray($reg->packageInfo($params[0])); } - if (!isset($contents['dir']['file'][0])) { - $contents['dir']['file'] = array($contents['dir']['file']); + if (PEAR::isError($info)) { + return $this->raiseError($info); } - foreach ($contents['dir']['file'] as $file) { - if ($baseinstalldir && !isset($file['attribs']['baseinstalldir'])) { - $file['attribs']['baseinstalldir'] = $baseinstalldir; - } + $deps = $info->getDeps(); + if (is_array($deps)) { + if ($info->getPackagexmlVersion() == '1.0') { + $data = array( + 'caption' => 'Dependencies for pear/' . $info->getPackage(), + 'border' => true, + 'headline' => array("Required?", "Type", "Name", "Relation", "Version"), + ); - $processFile = $file; - unset($processFile['attribs']); - if (count($processFile)) { - foreach ($processFile as $name => $task) { - if ($name != $pf2->getTasksNs() . ':replace') { - return $this->raiseError('Cannot safely process "' . $packagexml . - '" contains tasks other than replace. Using a ' . - 'PEAR_PackageFileManager-based script is an option.'); + foreach ($deps as $d) { + if (isset($d['optional'])) { + if ($d['optional'] == 'yes') { + $req = 'No'; + } else { + $req = 'Yes'; + } + } else { + $req = 'Yes'; + } + + if (isset($this->_deps_rel_trans[$d['rel']])) { + $rel = $this->_deps_rel_trans[$d['rel']]; + } else { + $rel = $d['rel']; + } + + if (isset($this->_deps_type_trans[$d['type']])) { + $type = ucfirst($this->_deps_type_trans[$d['type']]); + } else { + $type = $d['type']; + } + + if (isset($d['name'])) { + $name = $d['name']; + } else { + $name = ''; + } + + if (isset($d['version'])) { + $version = $d['version']; + } else { + $version = ''; + } + + $data['data'][] = array($req, $type, $name, $rel, $version); + } + } else { // package.xml 2.0 dependencies display + require_once 'PEAR/Dependency2.php'; + $deps = $info->getDependencies(); + $reg = &$this->config->getRegistry(); + if (is_array($deps)) { + $d = new PEAR_Dependency2($this->config, array(), ''); + $data = array( + 'caption' => 'Dependencies for ' . $info->getPackage(), + 'border' => true, + 'headline' => array("Required?", "Type", "Name", 'Versioning', 'Group'), + ); + foreach ($deps as $type => $subd) { + $req = ($type == 'required') ? 'Yes' : 'No'; + if ($type == 'group') { + $group = $subd['attribs']['name']; + } else { + $group = ''; + } + + if (!isset($subd[0])) { + $subd = array($subd); + } + + foreach ($subd as $groupa) { + foreach ($groupa as $deptype => $depinfo) { + if ($deptype == 'attribs') { + continue; + } + + if ($deptype == 'pearinstaller') { + $deptype = 'pear Installer'; + } + + if (!isset($depinfo[0])) { + $depinfo = array($depinfo); + } + + foreach ($depinfo as $inf) { + $name = ''; + if (isset($inf['channel'])) { + $alias = $reg->channelAlias($inf['channel']); + if (!$alias) { + $alias = '(channel?) ' .$inf['channel']; + } + $name = $alias . '/'; + + } + if (isset($inf['name'])) { + $name .= $inf['name']; + } elseif (isset($inf['pattern'])) { + $name .= $inf['pattern']; + } else { + $name .= ''; + } + + if (isset($inf['uri'])) { + $name .= ' [' . $inf['uri'] . ']'; + } + + if (isset($inf['conflicts'])) { + $ver = 'conflicts'; + } else { + $ver = $d->_getExtraString($inf); + } + + $data['data'][] = array($req, ucfirst($deptype), $name, + $ver, $group); + } + } + } } - $file['attribs']['replace'][] = $task; } } - if (!in_array($file['attribs']['role'], PEAR_Common::getFileRoles())) { - return $this->raiseError('Cannot safely convert "' . $packagexml . - '", contains custom roles. Using a PEAR_PackageFileManager-based script ' . - 'or the convert command is an option'); + $this->ui->outputData($data, $command); + return true; + } + + // Fallback + $this->ui->outputData("This package does not have any dependencies.", $command); + } + + function doSign($command, $options, $params) + { + // should move most of this code into PEAR_Packager + // so it'll be easy to implement "pear package --sign" + if (count($params) !== 1) { + return $this->raiseError("bad parameter(s), try \"help $command\""); + } + + require_once 'System.php'; + require_once 'Archive/Tar.php'; + + if (!file_exists($params[0])) { + return $this->raiseError("file does not exist: $params[0]"); + } + + $obj = $this->getPackageFile($this->config, $this->_debug); + $info = $obj->fromTgzFile($params[0], PEAR_VALIDATE_NORMAL); + if (PEAR::isError($info)) { + return $this->raiseError($info); + } + + $tar = new Archive_Tar($params[0]); + $tmpdir = System::mktemp('-d pearsign'); + if (!$tar->extractList('package2.xml package.xml package.sig', $tmpdir)) { + return $this->raiseError("failed to extract tar file"); + } + + if (file_exists("$tmpdir/package.sig")) { + return $this->raiseError("package already signed"); + } + + $packagexml = 'package.xml'; + if (file_exists("$tmpdir/package2.xml")) { + $packagexml = 'package2.xml'; + } + + if (file_exists("$tmpdir/package.sig")) { + unlink("$tmpdir/package.sig"); + } + + if (!file_exists("$tmpdir/$packagexml")) { + return $this->raiseError("Extracted file $tmpdir/$packagexml not found."); + } + + $input = $this->ui->userDialog($command, + array('GnuPG Passphrase'), + array('password')); + if (!isset($input[0])) { + //use empty passphrase + $input[0] = ''; + } + + $devnull = (isset($options['verbose'])) ? '' : ' 2>/dev/null'; + $gpg = popen("gpg --batch --passphrase-fd 0 --armor --detach-sign --output $tmpdir/package.sig $tmpdir/$packagexml" . $devnull, "w"); + if (!$gpg) { + return $this->raiseError("gpg command failed"); + } + + fwrite($gpg, "$input[0]\n"); + if (pclose($gpg) || !file_exists("$tmpdir/package.sig")) { + return $this->raiseError("gpg sign failed"); + } + + if (!$tar->addModify("$tmpdir/package.sig", '', $tmpdir)) { + return $this->raiseError('failed adding signature to file'); + } + + $this->ui->outputData("Package signed.", $command); + return true; + } + + /** + * For unit testing purposes + */ + function &getInstaller(&$ui) + { + if (!class_exists('PEAR_Installer')) { + require_once 'PEAR/Installer.php'; + } + $a = &new PEAR_Installer($ui); + return $a; + } + + /** + * For unit testing purposes + */ + function &getCommandPackaging(&$ui, &$config) + { + if (!class_exists('PEAR_Command_Packaging')) { + if ($fp = @fopen('PEAR/Command/Packaging.php', 'r', true)) { + fclose($fp); + include_once 'PEAR/Command/Packaging.php'; } + } - if (isset($release['filelist']['install'])) { - foreach ($release['filelist']['install'] as $installas) { - if ($installas['attribs']['name'] == $file['attribs']['name']) { - $file['attribs']['install-as'] = $installas['attribs']['as']; - } + if (class_exists('PEAR_Command_Packaging')) { + $a = &new PEAR_Command_Packaging($ui, $config); + } else { + $a = null; + } + + return $a; + } + + function doMakeRPM($command, $options, $params) + { + + // Check to see if PEAR_Command_Packaging is installed, and + // transparently switch to use the "make-rpm-spec" command from it + // instead, if it does. Otherwise, continue to use the old version + // of "makerpm" supplied with this package (PEAR). + $packaging_cmd = $this->getCommandPackaging($this->ui, $this->config); + if ($packaging_cmd !== null) { + $this->ui->outputData('PEAR_Command_Packaging is installed; using '. + 'newer "make-rpm-spec" command instead'); + return $packaging_cmd->run('make-rpm-spec', $options, $params); + } + + $this->ui->outputData('WARNING: "pear makerpm" is no longer available; an '. + 'improved version is available via "pear make-rpm-spec", which '. + 'is available by installing PEAR_Command_Packaging'); + return true; + } + + function doConvert($command, $options, $params) + { + $packagexml = isset($params[0]) ? $params[0] : 'package.xml'; + $newpackagexml = isset($params[1]) ? $params[1] : dirname($packagexml) . + DIRECTORY_SEPARATOR . 'package2.xml'; + $pkg = &$this->getPackageFile($this->config, $this->_debug); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $pf = $pkg->fromPackageFile($packagexml, PEAR_VALIDATE_NORMAL); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($pf)) { + if (is_array($pf->getUserInfo())) { + foreach ($pf->getUserInfo() as $warning) { + $this->ui->outputData($warning['message']); } } + return $this->raiseError($pf); + } - $pf->addFile('/', $file['attribs']['name'], $file['attribs']); + if (is_a($pf, 'PEAR_PackageFile_v2')) { + $this->ui->outputData($packagexml . ' is already a package.xml version 2.0'); + return true; } - if ($pf2->getChangeLog()) { - $this->ui->outputData('WARNING: changelog is not translated to package.xml ' . - '1.0, use PEAR_PackageFileManager-based script if you need changelog-' . - 'translation for package.xml 1.0'); + $gen = &$pf->getDefaultGenerator(); + $newpf = &$gen->toV2(); + $newpf->setPackagefile($newpackagexml); + $gen = &$newpf->getDefaultGenerator(); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $state = (isset($options['flat']) ? PEAR_VALIDATE_PACKAGING : PEAR_VALIDATE_NORMAL); + $saved = $gen->toPackageFile(dirname($newpackagexml), $state, basename($newpackagexml)); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($saved)) { + if (is_array($saved->getUserInfo())) { + foreach ($saved->getUserInfo() as $warning) { + $this->ui->outputData($warning['message']); + } + } + + $this->ui->outputData($saved->getMessage()); + return true; } - $gen = &$pf->getDefaultGenerator(); - $gen->toPackageFile('.'); + $this->ui->outputData('Wrote new version 2.0 package.xml to "' . $saved . '"'); + return true; } -}PEAR-1.8.0/PEAR/Command/Registry.xml100777 764 764 3376 100777 11767 - - List Installed Packages In The Default Channel - doList - l +}PEAR-1.9.0/PEAR/Command/Pickle.xml100664 764 764 2233 100664 11344 + + Build PECL Package + doPackage + pi - - c - list installed packages from this channel - CHAN - - - a - list installed packages from all channels - - - i - output fully channel-aware data, even on failure - + + Z + Do not gzip the package file + + + n + Print the name of the packaged file. + - <package> -If invoked without parameters, this command lists the PEAR packages -installed in your php_dir ({config php_dir}). With a parameter, it -lists the files in a package. - - - - List Files In Installed Package - doFileList - fl - - <package> -List the files in an installed package. - - - - Shell Script Test - doShellTest - st - - <package> [[relation] version] -Tests if a package is installed in the system. Will exit(1) if it is not. - <relation> The version comparison operator. One of: - <, lt, <=, le, >, gt, >=, ge, ==, =, eq, !=, <>, ne - <version> The version to compare with + [descfile] +Creates a PECL package from its package2.xml file. + +An automatic conversion will be made to a package.xml 1.0 and written out to +disk in the current directory as "package.xml". Note that +only simple package.xml 2.0 will be converted. package.xml 2.0 with: + + - dependency types other than required/optional PECL package/ext/php/pearinstaller + - more than one extsrcrelease or zendextsrcrelease + - zendextbinrelease, extbinrelease, phprelease, or bundle release type + - dependency groups + - ignore tags in release filelist + - tasks other than replace + - custom roles + +will cause pickle to fail, and output an error message. If your package2.xml +uses any of these features, you are best off using PEAR_PackageFileManager to +generate both package.xml. - - - Display information about a package - doInfo - in - - <package> -Displays information about a package. The package argument may be a -local package file, an URL to a package file, or the name of an -installed package. - -PEAR-1.8.0/PEAR/Command/Registry.php100664 764 764 132374 100664 12005 +PEAR-1.9.0/PEAR/Command/Pickle.php100664 764 764 37207 100664 11364 * @author Greg Beaver - * @copyright 1997-2009 The Authors + * @copyright 2005-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Registry.php,v 1.88 2009/02/24 23:39:29 dufuz Exp $ + * @version CVS: $Id: Pickle.php 276383 2009-02-24 23:39:37Z dufuz $ * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 + * @since File available since Release 1.4.1 */ /** @@ -13533,97 +13542,575 @@ require_once 'PEAR/Command/Common.php'; /** - * PEAR commands for registry manipulation + * PEAR commands for login/logout * * @category pear * @package PEAR - * @author Stig Bakken * @author Greg Beaver - * @copyright 1997-2009 The Authors + * @copyright 2005-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 + * @since Class available since Release 1.4.1 */ -class PEAR_Command_Registry extends PEAR_Command_Common + +class PEAR_Command_Pickle extends PEAR_Command_Common { var $commands = array( - 'list' => array( - 'summary' => 'List Installed Packages In The Default Channel', - 'function' => 'doList', - 'shortcut' => 'l', + 'pickle' => array( + 'summary' => 'Build PECL Package', + 'function' => 'doPackage', + 'shortcut' => 'pi', 'options' => array( - 'channel' => array( - 'shortopt' => 'c', - 'doc' => 'list installed packages from this channel', - 'arg' => 'CHAN', - ), - 'allchannels' => array( - 'shortopt' => 'a', - 'doc' => 'list installed packages from all channels', + 'nocompress' => array( + 'shortopt' => 'Z', + 'doc' => 'Do not gzip the package file' ), - 'channelinfo' => array( - 'shortopt' => 'i', - 'doc' => 'output fully channel-aware data, even on failure', + 'showname' => array( + 'shortopt' => 'n', + 'doc' => 'Print the name of the packaged file.', ), ), - 'doc' => ' -If invoked without parameters, this command lists the PEAR packages -installed in your php_dir ({config php_dir}). With a parameter, it -lists the files in a package. -', - ), - 'list-files' => array( - 'summary' => 'List Files In Installed Package', - 'function' => 'doFileList', - 'shortcut' => 'fl', - 'options' => array(), - 'doc' => ' -List the files in an installed package. + 'doc' => '[descfile] +Creates a PECL package from its package2.xml file. + +An automatic conversion will be made to a package.xml 1.0 and written out to +disk in the current directory as "package.xml". Note that +only simple package.xml 2.0 will be converted. package.xml 2.0 with: + + - dependency types other than required/optional PECL package/ext/php/pearinstaller + - more than one extsrcrelease or zendextsrcrelease + - zendextbinrelease, extbinrelease, phprelease, or bundle release type + - dependency groups + - ignore tags in release filelist + - tasks other than replace + - custom roles + +will cause pickle to fail, and output an error message. If your package2.xml +uses any of these features, you are best off using PEAR_PackageFileManager to +generate both package.xml. ' ), - 'shell-test' => array( - 'summary' => 'Shell Script Test', - 'function' => 'doShellTest', - 'shortcut' => 'st', - 'options' => array(), - 'doc' => ' [[relation] version] -Tests if a package is installed in the system. Will exit(1) if it is not. - The version comparison operator. One of: - <, lt, <=, le, >, gt, >=, ge, ==, =, eq, !=, <>, ne - The version to compare with -'), - 'info' => array( - 'summary' => 'Display information about a package', - 'function' => 'doInfo', - 'shortcut' => 'in', - 'options' => array(), - 'doc' => ' -Displays information about a package. The package argument may be a -local package file, an URL to a package file, or the name of an -installed package.' - ) ); /** - * PEAR_Command_Registry constructor. + * PEAR_Command_Package constructor. * * @access public */ - function PEAR_Command_Registry(&$ui, &$config) + function PEAR_Command_Pickle(&$ui, &$config) { parent::PEAR_Command_Common($ui, $config); } - function _sortinfo($a, $b) + /** + * For unit-testing ease + * + * @return PEAR_Packager + */ + function &getPackager() { - $apackage = isset($a['package']) ? $a['package'] : $a['name']; - $bpackage = isset($b['package']) ? $b['package'] : $b['name']; - return strcmp($apackage, $bpackage); + if (!class_exists('PEAR_Packager')) { + require_once 'PEAR/Packager.php'; + } + + $a = &new PEAR_Packager; + return $a; } - function doList($command, $options, $params) - { + /** + * For unit-testing ease + * + * @param PEAR_Config $config + * @param bool $debug + * @param string|null $tmpdir + * @return PEAR_PackageFile + */ + function &getPackageFile($config, $debug = false, $tmpdir = null) + { + if (!class_exists('PEAR_Common')) { + require_once 'PEAR/Common.php'; + } + + if (!class_exists('PEAR_PackageFile')) { + require_once 'PEAR/PackageFile.php'; + } + + $a = &new PEAR_PackageFile($config, $debug, $tmpdir); + $common = new PEAR_Common; + $common->ui = $this->ui; + $a->setLogger($common); + return $a; + } + + function doPackage($command, $options, $params) + { + $this->output = ''; + $pkginfofile = isset($params[0]) ? $params[0] : 'package2.xml'; + $packager = &$this->getPackager(); + if (PEAR::isError($err = $this->_convertPackage($pkginfofile))) { + return $err; + } + + $compress = empty($options['nocompress']) ? true : false; + $result = $packager->package($pkginfofile, $compress, 'package.xml'); + if (PEAR::isError($result)) { + return $this->raiseError($result); + } + + // Don't want output, only the package file name just created + if (isset($options['showname'])) { + $this->ui->outputData($result, $command); + } + + return true; + } + + function _convertPackage($packagexml) + { + $pkg = &$this->getPackageFile($this->config); + $pf2 = &$pkg->fromPackageFile($packagexml, PEAR_VALIDATE_NORMAL); + if (!is_a($pf2, 'PEAR_PackageFile_v2')) { + return $this->raiseError('Cannot process "' . + $packagexml . '", is not a package.xml 2.0'); + } + + require_once 'PEAR/PackageFile/v1.php'; + $pf = new PEAR_PackageFile_v1; + $pf->setConfig($this->config); + if ($pf2->getPackageType() != 'extsrc' && $pf2->getPackageType() != 'zendextsrc') { + return $this->raiseError('Cannot safely convert "' . $packagexml . + '", is not an extension source package. Using a PEAR_PackageFileManager-based ' . + 'script is an option'); + } + + if (is_array($pf2->getUsesRole())) { + return $this->raiseError('Cannot safely convert "' . $packagexml . + '", contains custom roles. Using a PEAR_PackageFileManager-based script or ' . + 'the convert command is an option'); + } + + if (is_array($pf2->getUsesTask())) { + return $this->raiseError('Cannot safely convert "' . $packagexml . + '", contains custom tasks. Using a PEAR_PackageFileManager-based script or ' . + 'the convert command is an option'); + } + + $deps = $pf2->getDependencies(); + if (isset($deps['group'])) { + return $this->raiseError('Cannot safely convert "' . $packagexml . + '", contains dependency groups. Using a PEAR_PackageFileManager-based script ' . + 'or the convert command is an option'); + } + + if (isset($deps['required']['subpackage']) || + isset($deps['optional']['subpackage'])) { + return $this->raiseError('Cannot safely convert "' . $packagexml . + '", contains subpackage dependencies. Using a PEAR_PackageFileManager-based '. + 'script is an option'); + } + + if (isset($deps['required']['os'])) { + return $this->raiseError('Cannot safely convert "' . $packagexml . + '", contains os dependencies. Using a PEAR_PackageFileManager-based '. + 'script is an option'); + } + + if (isset($deps['required']['arch'])) { + return $this->raiseError('Cannot safely convert "' . $packagexml . + '", contains arch dependencies. Using a PEAR_PackageFileManager-based '. + 'script is an option'); + } + + $pf->setPackage($pf2->getPackage()); + $pf->setSummary($pf2->getSummary()); + $pf->setDescription($pf2->getDescription()); + foreach ($pf2->getMaintainers() as $maintainer) { + $pf->addMaintainer($maintainer['role'], $maintainer['handle'], + $maintainer['name'], $maintainer['email']); + } + + $pf->setVersion($pf2->getVersion()); + $pf->setDate($pf2->getDate()); + $pf->setLicense($pf2->getLicense()); + $pf->setState($pf2->getState()); + $pf->setNotes($pf2->getNotes()); + $pf->addPhpDep($deps['required']['php']['min'], 'ge'); + if (isset($deps['required']['php']['max'])) { + $pf->addPhpDep($deps['required']['php']['max'], 'le'); + } + + if (isset($deps['required']['package'])) { + if (!isset($deps['required']['package'][0])) { + $deps['required']['package'] = array($deps['required']['package']); + } + + foreach ($deps['required']['package'] as $dep) { + if (!isset($dep['channel'])) { + return $this->raiseError('Cannot safely convert "' . $packagexml . '"' . + ' contains uri-based dependency on a package. Using a ' . + 'PEAR_PackageFileManager-based script is an option'); + } + + if ($dep['channel'] != 'pear.php.net' + && $dep['channel'] != 'pecl.php.net' + && $dep['channel'] != 'doc.php.net') { + return $this->raiseError('Cannot safely convert "' . $packagexml . '"' . + ' contains dependency on a non-standard channel package. Using a ' . + 'PEAR_PackageFileManager-based script is an option'); + } + + if (isset($dep['conflicts'])) { + return $this->raiseError('Cannot safely convert "' . $packagexml . '"' . + ' contains conflicts dependency. Using a ' . + 'PEAR_PackageFileManager-based script is an option'); + } + + if (isset($dep['exclude'])) { + $this->ui->outputData('WARNING: exclude tags are ignored in conversion'); + } + + if (isset($dep['min'])) { + $pf->addPackageDep($dep['name'], $dep['min'], 'ge'); + } + + if (isset($dep['max'])) { + $pf->addPackageDep($dep['name'], $dep['max'], 'le'); + } + } + } + + if (isset($deps['required']['extension'])) { + if (!isset($deps['required']['extension'][0])) { + $deps['required']['extension'] = array($deps['required']['extension']); + } + + foreach ($deps['required']['extension'] as $dep) { + if (isset($dep['conflicts'])) { + return $this->raiseError('Cannot safely convert "' . $packagexml . '"' . + ' contains conflicts dependency. Using a ' . + 'PEAR_PackageFileManager-based script is an option'); + } + + if (isset($dep['exclude'])) { + $this->ui->outputData('WARNING: exclude tags are ignored in conversion'); + } + + if (isset($dep['min'])) { + $pf->addExtensionDep($dep['name'], $dep['min'], 'ge'); + } + + if (isset($dep['max'])) { + $pf->addExtensionDep($dep['name'], $dep['max'], 'le'); + } + } + } + + if (isset($deps['optional']['package'])) { + if (!isset($deps['optional']['package'][0])) { + $deps['optional']['package'] = array($deps['optional']['package']); + } + + foreach ($deps['optional']['package'] as $dep) { + if (!isset($dep['channel'])) { + return $this->raiseError('Cannot safely convert "' . $packagexml . '"' . + ' contains uri-based dependency on a package. Using a ' . + 'PEAR_PackageFileManager-based script is an option'); + } + + if ($dep['channel'] != 'pear.php.net' + && $dep['channel'] != 'pecl.php.net' + && $dep['channel'] != 'doc.php.net') { + return $this->raiseError('Cannot safely convert "' . $packagexml . '"' . + ' contains dependency on a non-standard channel package. Using a ' . + 'PEAR_PackageFileManager-based script is an option'); + } + + if (isset($dep['exclude'])) { + $this->ui->outputData('WARNING: exclude tags are ignored in conversion'); + } + + if (isset($dep['min'])) { + $pf->addPackageDep($dep['name'], $dep['min'], 'ge', 'yes'); + } + + if (isset($dep['max'])) { + $pf->addPackageDep($dep['name'], $dep['max'], 'le', 'yes'); + } + } + } + + if (isset($deps['optional']['extension'])) { + if (!isset($deps['optional']['extension'][0])) { + $deps['optional']['extension'] = array($deps['optional']['extension']); + } + + foreach ($deps['optional']['extension'] as $dep) { + if (isset($dep['exclude'])) { + $this->ui->outputData('WARNING: exclude tags are ignored in conversion'); + } + + if (isset($dep['min'])) { + $pf->addExtensionDep($dep['name'], $dep['min'], 'ge', 'yes'); + } + + if (isset($dep['max'])) { + $pf->addExtensionDep($dep['name'], $dep['max'], 'le', 'yes'); + } + } + } + + $contents = $pf2->getContents(); + $release = $pf2->getReleases(); + if (isset($releases[0])) { + return $this->raiseError('Cannot safely process "' . $packagexml . '" contains ' + . 'multiple extsrcrelease/zendextsrcrelease tags. Using a PEAR_PackageFileManager-based script ' . + 'or the convert command is an option'); + } + + if ($configoptions = $pf2->getConfigureOptions()) { + foreach ($configoptions as $option) { + $default = isset($option['default']) ? $option['default'] : false; + $pf->addConfigureOption($option['name'], $option['prompt'], $default); + } + } + + if (isset($release['filelist']['ignore'])) { + return $this->raiseError('Cannot safely process "' . $packagexml . '" contains ' + . 'ignore tags. Using a PEAR_PackageFileManager-based script or the convert' . + ' command is an option'); + } + + if (isset($release['filelist']['install']) && + !isset($release['filelist']['install'][0])) { + $release['filelist']['install'] = array($release['filelist']['install']); + } + + if (isset($contents['dir']['attribs']['baseinstalldir'])) { + $baseinstalldir = $contents['dir']['attribs']['baseinstalldir']; + } else { + $baseinstalldir = false; + } + + if (!isset($contents['dir']['file'][0])) { + $contents['dir']['file'] = array($contents['dir']['file']); + } + + foreach ($contents['dir']['file'] as $file) { + if ($baseinstalldir && !isset($file['attribs']['baseinstalldir'])) { + $file['attribs']['baseinstalldir'] = $baseinstalldir; + } + + $processFile = $file; + unset($processFile['attribs']); + if (count($processFile)) { + foreach ($processFile as $name => $task) { + if ($name != $pf2->getTasksNs() . ':replace') { + return $this->raiseError('Cannot safely process "' . $packagexml . + '" contains tasks other than replace. Using a ' . + 'PEAR_PackageFileManager-based script is an option.'); + } + $file['attribs']['replace'][] = $task; + } + } + + if (!in_array($file['attribs']['role'], PEAR_Common::getFileRoles())) { + return $this->raiseError('Cannot safely convert "' . $packagexml . + '", contains custom roles. Using a PEAR_PackageFileManager-based script ' . + 'or the convert command is an option'); + } + + if (isset($release['filelist']['install'])) { + foreach ($release['filelist']['install'] as $installas) { + if ($installas['attribs']['name'] == $file['attribs']['name']) { + $file['attribs']['install-as'] = $installas['attribs']['as']; + } + } + } + + $pf->addFile('/', $file['attribs']['name'], $file['attribs']); + } + + if ($pf2->getChangeLog()) { + $this->ui->outputData('WARNING: changelog is not translated to package.xml ' . + '1.0, use PEAR_PackageFileManager-based script if you need changelog-' . + 'translation for package.xml 1.0'); + } + + $gen = &$pf->getDefaultGenerator(); + $gen->toPackageFile('.'); + } +}PEAR-1.9.0/PEAR/Command/Registry.xml100664 764 764 3376 100664 11756 + + List Installed Packages In The Default Channel + doList + l + + + c + list installed packages from this channel + CHAN + + + a + list installed packages from all channels + + + i + output fully channel-aware data, even on failure + + + <package> +If invoked without parameters, this command lists the PEAR packages +installed in your php_dir ({config php_dir}). With a parameter, it +lists the files in a package. + + + + List Files In Installed Package + doFileList + fl + + <package> +List the files in an installed package. + + + + Shell Script Test + doShellTest + st + + <package> [[relation] version] +Tests if a package is installed in the system. Will exit(1) if it is not. + <relation> The version comparison operator. One of: + <, lt, <=, le, >, gt, >=, ge, ==, =, eq, !=, <>, ne + <version> The version to compare with + + + + Display information about a package + doInfo + in + + <package> +Displays information about a package. The package argument may be a +local package file, an URL to a package file, or the name of an +installed package. + +PEAR-1.9.0/PEAR/Command/Registry.php100664 764 764 132371 100664 12003 + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Registry.php 276383 2009-02-24 23:39:37Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * base class + */ +require_once 'PEAR/Command/Common.php'; + +/** + * PEAR commands for registry manipulation + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Command_Registry extends PEAR_Command_Common +{ + var $commands = array( + 'list' => array( + 'summary' => 'List Installed Packages In The Default Channel', + 'function' => 'doList', + 'shortcut' => 'l', + 'options' => array( + 'channel' => array( + 'shortopt' => 'c', + 'doc' => 'list installed packages from this channel', + 'arg' => 'CHAN', + ), + 'allchannels' => array( + 'shortopt' => 'a', + 'doc' => 'list installed packages from all channels', + ), + 'channelinfo' => array( + 'shortopt' => 'i', + 'doc' => 'output fully channel-aware data, even on failure', + ), + ), + 'doc' => ' +If invoked without parameters, this command lists the PEAR packages +installed in your php_dir ({config php_dir}). With a parameter, it +lists the files in a package. +', + ), + 'list-files' => array( + 'summary' => 'List Files In Installed Package', + 'function' => 'doFileList', + 'shortcut' => 'fl', + 'options' => array(), + 'doc' => ' +List the files in an installed package. +' + ), + 'shell-test' => array( + 'summary' => 'Shell Script Test', + 'function' => 'doShellTest', + 'shortcut' => 'st', + 'options' => array(), + 'doc' => ' [[relation] version] +Tests if a package is installed in the system. Will exit(1) if it is not. + The version comparison operator. One of: + <, lt, <=, le, >, gt, >=, ge, ==, =, eq, !=, <>, ne + The version to compare with +'), + 'info' => array( + 'summary' => 'Display information about a package', + 'function' => 'doInfo', + 'shortcut' => 'in', + 'options' => array(), + 'doc' => ' +Displays information about a package. The package argument may be a +local package file, an URL to a package file, or the name of an +installed package.' + ) + ); + + /** + * PEAR_Command_Registry constructor. + * + * @access public + */ + function PEAR_Command_Registry(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + function _sortinfo($a, $b) + { + $apackage = isset($a['package']) ? $a['package'] : $a['name']; + $bpackage = isset($b['package']) ? $b['package'] : $b['name']; + return strcmp($apackage, $bpackage); + } + + function doList($command, $options, $params) + { $reg = &$this->config->getRegistry(); $channelinfo = isset($options['channelinfo']); if (isset($options['allchannels']) && !$channelinfo) { @@ -14652,7 +15139,7 @@ $data['raw'] = $obj->getArray(); // no validation needed $this->ui->outputData($data, 'package-info'); } -}PEAR-1.8.0/PEAR/Command/Remote.xml100777 764 764 6357 100777 11414 +}PEAR-1.9.0/PEAR/Command/Remote.xml100664 764 764 6357 100664 11403 Information About Remote Packages doRemoteInfo @@ -14760,7 +15247,7 @@ parameter. -PEAR-1.8.0/PEAR/Command/Remote.php100664 764 764 72007 100664 11404 PEAR-1.9.0/PEAR/Command/Remote.php100664 764 764 72576 100664 11420 * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Remote.php,v 1.120 2009/03/09 01:33:20 dufuz Exp $ + * @version CVS: $Id: Remote.php 287477 2009-08-19 14:19:43Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since Release 0.1 */ @@ -14793,7 +15280,7 @@ * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 0.1 */ @@ -15426,9 +15913,22 @@ } $latest = array(); - if ($chan->supportsREST($this->config->get('preferred_mirror')) && - $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) { - $rest = &$this->config->getREST('1.0', array()); + $base2 = false; + $preferred_mirror = $this->config->get('preferred_mirror'); + if ($chan->supportsREST($preferred_mirror) && + ( + //($base2 = $chan->getBaseURL('REST1.4', $preferred_mirror)) || + ($base = $chan->getBaseURL('REST1.0', $preferred_mirror)) + ) + + ) { + if ($base2) { + $rest = &$this->config->getREST('1.4', array()); + $base = $base2; + } else { + $rest = &$this->config->getREST('1.0', array()); + } + if (empty($state) || $state == 'any') { $state = false; } else { @@ -15555,7 +16055,7 @@ $this->ui->outputData(rtrim($output), $command); return $num; } -}PEAR-1.8.0/PEAR/Command/Test.xml100777 764 764 3153 100777 11067 +}PEAR-1.9.0/PEAR/Command/Test.xml100664 764 764 3151 100664 11054 Run Regression Tests doRunTests @@ -15588,7 +16088,7 @@ u - Search parameters for AllTests.php, and use that to run phpunit-based tests + Search parameters for AllTests.php, and use that to run phpunit-based tests If none is found, all .phpt tests will be tried instead. @@ -15605,346 +16105,346 @@ Generate a code coverage report (requires Xdebug 2.0.0+) - [testfile|dir ...] + [testfile|dir ...] Run regression tests with PHP's regression testing script (run-tests.php). -PEAR-1.8.0/PEAR/Command/Test.php100664 764 764 30011 100664 11055 - * @author Martin Jansen - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Test.php,v 1.32 2009/04/04 00:06:17 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/** - * base class - */ -require_once 'PEAR/Command/Common.php'; - -/** - * PEAR commands for login/logout - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Martin Jansen - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 - */ - -class PEAR_Command_Test extends PEAR_Command_Common -{ - var $commands = array( - 'run-tests' => array( - 'summary' => 'Run Regression Tests', - 'function' => 'doRunTests', - 'shortcut' => 'rt', - 'options' => array( - 'recur' => array( - 'shortopt' => 'r', - 'doc' => 'Run tests in child directories, recursively. 4 dirs deep maximum', - ), - 'ini' => array( - 'shortopt' => 'i', - 'doc' => 'actual string of settings to pass to php in format " -d setting=blah"', - 'arg' => 'SETTINGS' - ), - 'realtimelog' => array( - 'shortopt' => 'l', - 'doc' => 'Log test runs/results as they are run', - ), - 'quiet' => array( - 'shortopt' => 'q', - 'doc' => 'Only display detail for failed tests', - ), - 'simple' => array( - 'shortopt' => 's', - 'doc' => 'Display simple output for all tests', - ), - 'package' => array( - 'shortopt' => 'p', - 'doc' => 'Treat parameters as installed packages from which to run tests', - ), - 'phpunit' => array( - 'shortopt' => 'u', - 'doc' => 'Search parameters for AllTests.php, and use that to run phpunit-based tests -If none is found, all .phpt tests will be tried instead.', - ), - 'tapoutput' => array( - 'shortopt' => 't', - 'doc' => 'Output run-tests.log in TAP-compliant format', - ), - 'cgi' => array( - 'shortopt' => 'c', - 'doc' => 'CGI php executable (needed for tests with POST/GET section)', - 'arg' => 'PHPCGI', - ), - 'coverage' => array( - 'shortopt' => 'x', - 'doc' => 'Generate a code coverage report (requires Xdebug 2.0.0+)', - ), - ), - 'doc' => '[testfile|dir ...] -Run regression tests with PHP\'s regression testing script (run-tests.php).', - ), - ); - - var $output; - - /** - * PEAR_Command_Test constructor. - * - * @access public - */ - function PEAR_Command_Test(&$ui, &$config) - { - parent::PEAR_Command_Common($ui, $config); - } - - function doRunTests($command, $options, $params) - { - if (isset($options['phpunit']) && isset($options['tapoutput'])) { - return $this->raiseError('ERROR: cannot use both --phpunit and --tapoutput at the same time'); - } - - require_once 'PEAR/Common.php'; - require_once 'System.php'; - $log = new PEAR_Common; - $log->ui = &$this->ui; // slightly hacky, but it will work - $tests = array(); - $depth = isset($options['recur']) ? 14 : 1; - - if (!count($params)) { - $params[] = '.'; - } - - if (isset($options['package'])) { - $oldparams = $params; - $params = array(); - $reg = &$this->config->getRegistry(); - foreach ($oldparams as $param) { - $pname = $reg->parsePackageName($param, $this->config->get('default_channel')); - if (PEAR::isError($pname)) { - return $this->raiseError($pname); - } - - $package = &$reg->getPackage($pname['package'], $pname['channel']); - if (!$package) { - return PEAR::raiseError('Unknown package "' . - $reg->parsedPackageNameToString($pname) . '"'); - } - - $filelist = $package->getFilelist(); - foreach ($filelist as $name => $atts) { - if (isset($atts['role']) && $atts['role'] != 'test') { - continue; - } - - if (isset($options['phpunit']) && preg_match('/AllTests\.php\\z/i', $name)) { - $params[] = $atts['installed_as']; - continue; - } elseif (!preg_match('/\.phpt\\z/', $name)) { - continue; - } - $params[] = $atts['installed_as']; - } - } - } - - foreach ($params as $p) { - if (is_dir($p)) { - if (isset($options['phpunit'])) { - $dir = System::find(array($p, '-type', 'f', - '-maxdepth', $depth, - '-name', 'AllTests.php')); - if (count($dir)) { - foreach ($dir as $p) { - $p = realpath($p); - if (!count($tests) || - (count($tests) && strlen($p) < strlen($tests[0]))) { - // this is in a higher-level directory, use this one instead. - $tests = array($p); - } - } - } - continue; - } - - $args = array($p, '-type', 'f', '-name', '*.phpt'); - } else { - if (isset($options['phpunit'])) { - if (preg_match('/AllTests\.php\\z/i', $p)) { - $p = realpath($p); - if (!count($tests) || - (count($tests) && strlen($p) < strlen($tests[0]))) { - // this is in a higher-level directory, use this one instead. - $tests = array($p); - } - } - continue; - } - - if (file_exists($p) && preg_match('/\.phpt$/', $p)) { - $tests[] = $p; - continue; - } - - if (!preg_match('/\.phpt\\z/', $p)) { - $p .= '.phpt'; - } - - $args = array(dirname($p), '-type', 'f', '-name', $p); - } - - if (!isset($options['recur'])) { - $args[] = '-maxdepth'; - $args[] = 1; - } - - $dir = System::find($args); - $tests = array_merge($tests, $dir); - } - - $ini_settings = ''; - if (isset($options['ini'])) { - $ini_settings .= $options['ini']; - } - - if (isset($_ENV['TEST_PHP_INCLUDE_PATH'])) { - $ini_settings .= " -d include_path={$_ENV['TEST_PHP_INCLUDE_PATH']}"; - } - - if ($ini_settings) { - $this->ui->outputData('Using INI settings: "' . $ini_settings . '"'); - } - - $skipped = $passed = $failed = array(); - $tests_count = count($tests); - $this->ui->outputData('Running ' . $tests_count . ' tests', $command); - $start = time(); - if (isset($options['realtimelog']) && file_exists('run-tests.log')) { - unlink('run-tests.log'); - } - - if (isset($options['tapoutput'])) { - $tap = '1..' . $tests_count . "\n"; - } - - require_once 'PEAR/RunTest.php'; - $run = new PEAR_RunTest($log, $options); - $run->tests_count = $tests_count; - - if (isset($options['coverage']) && extension_loaded('xdebug')){ - $run->xdebug_loaded = true; - } else { - $run->xdebug_loaded = false; - } - - $j = $i = 1; - foreach ($tests as $t) { - if (isset($options['realtimelog'])) { - $fp = @fopen('run-tests.log', 'a'); - if ($fp) { - fwrite($fp, "Running test [$i / $tests_count] $t..."); - fclose($fp); - } - } - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - if (isset($options['phpunit'])) { - $result = $run->runPHPUnit($t, $ini_settings); - } else { - $result = $run->run($t, $ini_settings, $j); - } - PEAR::staticPopErrorHandling(); - if (PEAR::isError($result)) { - $this->ui->log($result->getMessage()); - continue; - } - - if (isset($options['tapoutput'])) { - $tap .= $result[0] . ' ' . $i . $result[1] . "\n"; - continue; - } - - if (isset($options['realtimelog'])) { - $fp = @fopen('run-tests.log', 'a'); - if ($fp) { - fwrite($fp, "$result\n"); - fclose($fp); - } - } - - if ($result == 'FAILED') { - $failed[] = $t; - } - if ($result == 'PASSED') { - $passed[] = $t; - } - if ($result == 'SKIPPED') { - $skipped[] = $t; - } - - $j++; - } - - $total = date('i:s', time() - $start); - if (isset($options['tapoutput'])) { - $fp = @fopen('run-tests.log', 'w'); - if ($fp) { - fwrite($fp, $tap, strlen($tap)); - fclose($fp); - $this->ui->outputData('wrote TAP-format log to "' .realpath('run-tests.log') . - '"', $command); - } - } else { - if (count($failed)) { - $output = "TOTAL TIME: $total\n"; - $output .= count($passed) . " PASSED TESTS\n"; - $output .= count($skipped) . " SKIPPED TESTS\n"; - $output .= count($failed) . " FAILED TESTS:\n"; - foreach ($failed as $failure) { - $output .= $failure . "\n"; - } - - $mode = isset($options['realtimelog']) ? 'a' : 'w'; - $fp = @fopen('run-tests.log', $mode); - - if ($fp) { - fwrite($fp, $output, strlen($output)); - fclose($fp); - $this->ui->outputData('wrote log to "' . realpath('run-tests.log') . '"', $command); - } - } elseif (file_exists('run-tests.log') && !is_dir('run-tests.log')) { - @unlink('run-tests.log'); - } - } - $this->ui->outputData('TOTAL TIME: ' . $total); - $this->ui->outputData(count($passed) . ' PASSED TESTS', $command); - $this->ui->outputData(count($skipped) . ' SKIPPED TESTS', $command); - if (count($failed)) { - $this->ui->outputData(count($failed) . ' FAILED TESTS:', $command); - foreach ($failed as $failure) { - $this->ui->outputData($failure, $command); - } - } - - return true; - } -}PEAR-1.8.0/PEAR/Downloader/Package.php100664 764 764 225261 100664 12246 PEAR-1.9.0/PEAR/Command/Test.php100664 764 764 27267 100664 11101 + * @author Martin Jansen + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Test.php 279072 2009-04-20 19:57:41Z cellog $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * base class + */ +require_once 'PEAR/Command/Common.php'; + +/** + * PEAR commands for login/logout + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Martin Jansen + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ + +class PEAR_Command_Test extends PEAR_Command_Common +{ + var $commands = array( + 'run-tests' => array( + 'summary' => 'Run Regression Tests', + 'function' => 'doRunTests', + 'shortcut' => 'rt', + 'options' => array( + 'recur' => array( + 'shortopt' => 'r', + 'doc' => 'Run tests in child directories, recursively. 4 dirs deep maximum', + ), + 'ini' => array( + 'shortopt' => 'i', + 'doc' => 'actual string of settings to pass to php in format " -d setting=blah"', + 'arg' => 'SETTINGS' + ), + 'realtimelog' => array( + 'shortopt' => 'l', + 'doc' => 'Log test runs/results as they are run', + ), + 'quiet' => array( + 'shortopt' => 'q', + 'doc' => 'Only display detail for failed tests', + ), + 'simple' => array( + 'shortopt' => 's', + 'doc' => 'Display simple output for all tests', + ), + 'package' => array( + 'shortopt' => 'p', + 'doc' => 'Treat parameters as installed packages from which to run tests', + ), + 'phpunit' => array( + 'shortopt' => 'u', + 'doc' => 'Search parameters for AllTests.php, and use that to run phpunit-based tests +If none is found, all .phpt tests will be tried instead.', + ), + 'tapoutput' => array( + 'shortopt' => 't', + 'doc' => 'Output run-tests.log in TAP-compliant format', + ), + 'cgi' => array( + 'shortopt' => 'c', + 'doc' => 'CGI php executable (needed for tests with POST/GET section)', + 'arg' => 'PHPCGI', + ), + 'coverage' => array( + 'shortopt' => 'x', + 'doc' => 'Generate a code coverage report (requires Xdebug 2.0.0+)', + ), + ), + 'doc' => '[testfile|dir ...] +Run regression tests with PHP\'s regression testing script (run-tests.php).', + ), + ); + + var $output; + + /** + * PEAR_Command_Test constructor. + * + * @access public + */ + function PEAR_Command_Test(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + function doRunTests($command, $options, $params) + { + if (isset($options['phpunit']) && isset($options['tapoutput'])) { + return $this->raiseError('ERROR: cannot use both --phpunit and --tapoutput at the same time'); + } + + require_once 'PEAR/Common.php'; + require_once 'System.php'; + $log = new PEAR_Common; + $log->ui = &$this->ui; // slightly hacky, but it will work + $tests = array(); + $depth = isset($options['recur']) ? 14 : 1; + + if (!count($params)) { + $params[] = '.'; + } + + if (isset($options['package'])) { + $oldparams = $params; + $params = array(); + $reg = &$this->config->getRegistry(); + foreach ($oldparams as $param) { + $pname = $reg->parsePackageName($param, $this->config->get('default_channel')); + if (PEAR::isError($pname)) { + return $this->raiseError($pname); + } + + $package = &$reg->getPackage($pname['package'], $pname['channel']); + if (!$package) { + return PEAR::raiseError('Unknown package "' . + $reg->parsedPackageNameToString($pname) . '"'); + } + + $filelist = $package->getFilelist(); + foreach ($filelist as $name => $atts) { + if (isset($atts['role']) && $atts['role'] != 'test') { + continue; + } + + if (isset($options['phpunit']) && preg_match('/AllTests\.php\\z/i', $name)) { + $params[] = $atts['installed_as']; + continue; + } elseif (!preg_match('/\.phpt\\z/', $name)) { + continue; + } + $params[] = $atts['installed_as']; + } + } + } + + foreach ($params as $p) { + if (is_dir($p)) { + if (isset($options['phpunit'])) { + $dir = System::find(array($p, '-type', 'f', + '-maxdepth', $depth, + '-name', 'AllTests.php')); + if (count($dir)) { + foreach ($dir as $p) { + $p = realpath($p); + if (!count($tests) || + (count($tests) && strlen($p) < strlen($tests[0]))) { + // this is in a higher-level directory, use this one instead. + $tests = array($p); + } + } + } + continue; + } + + $args = array($p, '-type', 'f', '-name', '*.phpt'); + } else { + if (isset($options['phpunit'])) { + if (preg_match('/AllTests\.php\\z/i', $p)) { + $p = realpath($p); + if (!count($tests) || + (count($tests) && strlen($p) < strlen($tests[0]))) { + // this is in a higher-level directory, use this one instead. + $tests = array($p); + } + } + continue; + } + + if (file_exists($p) && preg_match('/\.phpt$/', $p)) { + $tests[] = $p; + continue; + } + + if (!preg_match('/\.phpt\\z/', $p)) { + $p .= '.phpt'; + } + + $args = array(dirname($p), '-type', 'f', '-name', $p); + } + + if (!isset($options['recur'])) { + $args[] = '-maxdepth'; + $args[] = 1; + } + + $dir = System::find($args); + $tests = array_merge($tests, $dir); + } + + $ini_settings = ''; + if (isset($options['ini'])) { + $ini_settings .= $options['ini']; + } + + if (isset($_ENV['TEST_PHP_INCLUDE_PATH'])) { + $ini_settings .= " -d include_path={$_ENV['TEST_PHP_INCLUDE_PATH']}"; + } + + if ($ini_settings) { + $this->ui->outputData('Using INI settings: "' . $ini_settings . '"'); + } + + $skipped = $passed = $failed = array(); + $tests_count = count($tests); + $this->ui->outputData('Running ' . $tests_count . ' tests', $command); + $start = time(); + if (isset($options['realtimelog']) && file_exists('run-tests.log')) { + unlink('run-tests.log'); + } + + if (isset($options['tapoutput'])) { + $tap = '1..' . $tests_count . "\n"; + } + + require_once 'PEAR/RunTest.php'; + $run = new PEAR_RunTest($log, $options); + $run->tests_count = $tests_count; + + if (isset($options['coverage']) && extension_loaded('xdebug')){ + $run->xdebug_loaded = true; + } else { + $run->xdebug_loaded = false; + } + + $j = $i = 1; + foreach ($tests as $t) { + if (isset($options['realtimelog'])) { + $fp = @fopen('run-tests.log', 'a'); + if ($fp) { + fwrite($fp, "Running test [$i / $tests_count] $t..."); + fclose($fp); + } + } + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + if (isset($options['phpunit'])) { + $result = $run->runPHPUnit($t, $ini_settings); + } else { + $result = $run->run($t, $ini_settings, $j); + } + PEAR::staticPopErrorHandling(); + if (PEAR::isError($result)) { + $this->ui->log($result->getMessage()); + continue; + } + + if (isset($options['tapoutput'])) { + $tap .= $result[0] . ' ' . $i . $result[1] . "\n"; + continue; + } + + if (isset($options['realtimelog'])) { + $fp = @fopen('run-tests.log', 'a'); + if ($fp) { + fwrite($fp, "$result\n"); + fclose($fp); + } + } + + if ($result == 'FAILED') { + $failed[] = $t; + } + if ($result == 'PASSED') { + $passed[] = $t; + } + if ($result == 'SKIPPED') { + $skipped[] = $t; + } + + $j++; + } + + $total = date('i:s', time() - $start); + if (isset($options['tapoutput'])) { + $fp = @fopen('run-tests.log', 'w'); + if ($fp) { + fwrite($fp, $tap, strlen($tap)); + fclose($fp); + $this->ui->outputData('wrote TAP-format log to "' .realpath('run-tests.log') . + '"', $command); + } + } else { + if (count($failed)) { + $output = "TOTAL TIME: $total\n"; + $output .= count($passed) . " PASSED TESTS\n"; + $output .= count($skipped) . " SKIPPED TESTS\n"; + $output .= count($failed) . " FAILED TESTS:\n"; + foreach ($failed as $failure) { + $output .= $failure . "\n"; + } + + $mode = isset($options['realtimelog']) ? 'a' : 'w'; + $fp = @fopen('run-tests.log', $mode); + + if ($fp) { + fwrite($fp, $output, strlen($output)); + fclose($fp); + $this->ui->outputData('wrote log to "' . realpath('run-tests.log') . '"', $command); + } + } elseif (file_exists('run-tests.log') && !is_dir('run-tests.log')) { + @unlink('run-tests.log'); + } + } + $this->ui->outputData('TOTAL TIME: ' . $total); + $this->ui->outputData(count($passed) . ' PASSED TESTS', $command); + $this->ui->outputData(count($skipped) . ' SKIPPED TESTS', $command); + if (count($failed)) { + $this->ui->outputData(count($failed) . ' FAILED TESTS:', $command); + foreach ($failed as $failure) { + $this->ui->outputData($failure, $command); + } + } + + return true; + } +}PEAR-1.9.0/PEAR/Downloader/Package.php100664 764 764 226171 100664 12250 * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Package.php,v 1.126 2009/03/07 21:51:52 dufuz Exp $ + * @version CVS: $Id: Package.php 287560 2009-08-21 22:36:18Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since Release 1.4.0a1 */ @@ -15996,7 +16496,7 @@ * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 1.4.0a1 */ @@ -16111,6 +16611,12 @@ $options = $this->_downloader->getOptions(); if (isset($options['offline'])) { if (PEAR::isError($origErr) && !isset($options['soft'])) { + foreach ($origErr->getUserInfo() as $userInfo) { + if (isset($userInfo['message'])) { + $this->_downloader->log(0, $userInfo['message']); + } + } + $this->_downloader->log(0, $origErr->getMessage()); } @@ -16208,8 +16714,15 @@ if ($info != $newinfo) { do { - if ($info['package'] == 'pecl.php.net' && $newinfo['package'] == 'pear.php.net') { - $info['package'] = 'pear.php.net'; + if ($info['channel'] == 'pecl.php.net' && $newinfo['channel'] == 'pear.php.net') { + $info['channel'] = 'pear.php.net'; + if ($info == $newinfo) { + // skip the channel check if a pecl package says it's a PEAR package + break; + } + } + if ($info['channel'] == 'pear.php.net' && $newinfo['channel'] == 'pecl.php.net') { + $info['channel'] = 'pecl.php.net'; if ($info == $newinfo) { // skip the channel check if a pecl package says it's a PEAR package break; @@ -16598,8 +17111,7 @@ // we can't determine whether upgrade is necessary until we know what // version would be downloaded if (!isset($options['force']) && $this->isInstalled($ret, $oper)) { - $version = $this->_installRegistry->packageInfo($dep['name'], 'version', - $dep['channel']); + $version = $this->_installRegistry->packageInfo($dep['name'], 'version', $dep['channel']); $dep['package'] = $dep['name']; if (!isset($options['soft'])) { $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group . @@ -16676,8 +17188,7 @@ $newdep = $newdep[0]; $newdep['channel'] = 'pecl.php.net'; $chan = 'pecl.php.net'; - $url = - $this->_downloader->_getDepPackageDownloadUrl($newdep, $pname); + $url = $this->_downloader->_getDepPackageDownloadUrl($newdep, $pname); $obj = &$this->_installRegistry->getPackage($dep['name']); if (PEAR::isError($url)) { PEAR::popErrorHandling(); @@ -16761,8 +17272,7 @@ 'optional'; $dep['package'] = $dep['name']; if (isset($newdep)) { - $version = $this->_installRegistry->packageInfo($newdep['name'], 'version', - $newdep['channel']); + $version = $this->_installRegistry->packageInfo($newdep['name'], 'version', $newdep['channel']); } else { $version = $this->_installRegistry->packageInfo($dep['name'], 'version'); } @@ -17081,6 +17591,7 @@ $channel = 'pear.php.net'; } } + return (strtolower($package) == strtolower($this->getPackage()) && $channel == $this->getChannel() && version_compare($newdep['min'], $this->getVersion(), '<=') && @@ -17225,13 +17736,9 @@ if (!$param) { continue; } - if ($param->getPackage()) { - if ($ignoreGroups) { - $group = ''; - } else { - $group = $param->getGroup(); - } + if ($param->getPackage()) { + $group = $ignoreGroups ? '' : $param->getGroup(); $pnames[$i] = $param->getChannel() . '/' . $param->getPackage() . '-' . $param->getVersion() . '#' . $group; } @@ -17761,7 +18268,7 @@ if ($info['version'] === $package_version) { if (!isset($options['soft'])) { $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] . - '/' . $pname['package'] . '-' . $pname['version'] . ', additionally the suggested version' . + '/' . $pname['package'] . '-' . $package_version. ', additionally the suggested version' . ' (' . $package_version . ') is the same as the locally installed one.'); } @@ -17771,7 +18278,7 @@ if (version_compare($info['version'], $package_version, '<=')) { if (!isset($options['soft'])) { $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] . - '/' . $pname['package'] . '-' . $pname['version'] . ', additionally the suggested version' . + '/' . $pname['package'] . '-' . $package_version . ', additionally the suggested version' . ' (' . $info['version'] . ') is a lower version than the locally installed one (' . $package_version . ').'); } @@ -17940,7 +18447,7 @@ return $info; } -}PEAR-1.8.0/PEAR/Frontend/CLI.php100664 764 764 60645 100664 10766 * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: CLI.php,v 1.76 2009/04/04 00:09:14 dufuz Exp $ + * @version CVS: $Id: CLI.php 278236 2009-04-04 00:09:14Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since Release 0.1 */ @@ -17969,7 +18476,7 @@ * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 0.1 */ @@ -18671,7 +19178,7 @@ { print $text; } -}PEAR-1.8.0/PEAR/Installer/Role/Common.php100664 764 764 14236 100664 12661 * @copyright 1997-2006 The PHP Group * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Common.php,v 1.13 2009/02/24 23:39:37 dufuz Exp $ + * @version CVS: $Id: Common.php 276383 2009-02-24 23:39:37Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since Release 1.4.0a1 */ @@ -18697,7 +19204,7 @@ * @author Greg Beaver * @copyright 1997-2006 The PHP Group * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 1.4.0a1 */ @@ -18844,7 +19351,7 @@ return $roleInfo['phpextension']; } } -?>PEAR-1.8.0/PEAR/Installer/Role/Cfg.xml100777 764 764 645 100777 12112 +?>PEAR-1.9.0/PEAR/Installer/Role/Cfg.xml100664 764 764 645 100664 12101 php extsrc extbin @@ -18858,7 +19365,7 @@ -PEAR-1.8.0/PEAR/Installer/Role/Cfg.php100664 764 764 7704 100664 12112 PEAR-1.9.0/PEAR/Installer/Role/Cfg.php100664 764 764 7702 100664 12111 * @copyright 2007-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Cfg.php,v 1.9 2009/02/24 23:39:37 dufuz Exp $ + * @version CVS: $Id: Cfg.php 276383 2009-02-24 23:39:37Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since Release 1.7.0 */ @@ -18880,7 +19387,7 @@ * @author Greg Beaver * @copyright 2007-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 1.7.0 */ @@ -18963,7 +19470,7 @@ return $test; } -}PEAR-1.8.0/PEAR/Installer/Role/Data.xml100777 764 764 622 100777 12257 +}PEAR-1.9.0/PEAR/Installer/Role/Data.xml100664 764 764 622 100664 12246 php extsrc extbin @@ -18977,34 +19484,34 @@ -PEAR-1.8.0/PEAR/Installer/Role/Data.php100664 764 764 1560 100664 12256 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Data.php,v 1.8 2009/02/24 23:39:37 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Installer_Role_Data extends PEAR_Installer_Role_Common {} -?>PEAR-1.8.0/PEAR/Installer/Role/Doc.xml100777 764 764 621 100777 12112 +PEAR-1.9.0/PEAR/Installer/Role/Data.php100664 764 764 1523 100664 12256 + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Data.php 276383 2009-02-24 23:39:37Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Installer_Role_Data extends PEAR_Installer_Role_Common {} +?>PEAR-1.9.0/PEAR/Installer/Role/Doc.xml100664 764 764 621 100664 12101 php extsrc extbin @@ -19018,34 +19525,34 @@ -PEAR-1.8.0/PEAR/Installer/Role/Doc.php100664 764 764 1555 100664 12116 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Doc.php,v 1.8 2009/02/24 23:39:37 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Installer_Role_Doc extends PEAR_Installer_Role_Common {} -?>PEAR-1.8.0/PEAR/Installer/Role/Ext.xml100777 764 764 502 100777 12143 +PEAR-1.9.0/PEAR/Installer/Role/Doc.php100664 764 764 1520 100664 12107 + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Doc.php 276383 2009-02-24 23:39:37Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Installer_Role_Doc extends PEAR_Installer_Role_Common {} +?>PEAR-1.9.0/PEAR/Installer/Role/Ext.xml100664 764 764 502 100664 12132 extbin zendextbin 1 @@ -19056,34 +19563,34 @@ 1 -PEAR-1.8.0/PEAR/Installer/Role/Ext.php100664 764 764 1555 100664 12151 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Ext.php,v 1.8 2009/02/24 23:39:37 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Installer_Role_Ext extends PEAR_Installer_Role_Common {} -?>PEAR-1.8.0/PEAR/Installer/Role/Php.xml100777 764 764 655 100777 12143 +PEAR-1.9.0/PEAR/Installer/Role/Ext.php100664 764 764 1520 100664 12142 + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Ext.php 276383 2009-02-24 23:39:37Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Installer_Role_Ext extends PEAR_Installer_Role_Common {} +?>PEAR-1.9.0/PEAR/Installer/Role/Php.xml100664 764 764 655 100664 12132 php extsrc extbin @@ -19097,34 +19604,34 @@ -PEAR-1.8.0/PEAR/Installer/Role/Php.php100664 764 764 1555 100664 12140 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Php.php,v 1.9 2009/02/24 23:39:37 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Installer_Role_Php extends PEAR_Installer_Role_Common {} -?>PEAR-1.8.0/PEAR/Installer/Role/Script.xml100777 764 764 660 100777 12654 +PEAR-1.9.0/PEAR/Installer/Role/Php.php100664 764 764 1520 100664 12131 + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Php.php 276383 2009-02-24 23:39:37Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Installer_Role_Php extends PEAR_Installer_Role_Common {} +?>PEAR-1.9.0/PEAR/Installer/Role/Script.xml100664 764 764 660 100664 12643 php extsrc extbin @@ -19138,78 +19645,78 @@ 1 -PEAR-1.8.0/PEAR/Installer/Role/Script.php100664 764 764 1566 100664 12657 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Script.php,v 1.8 2009/02/24 23:39:37 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Installer_Role_Script extends PEAR_Installer_Role_Common {} -?>PEAR-1.8.0/PEAR/Installer/Role/Src.xml100777 764 764 455 100777 12141 - extsrc - zendextsrc - 1 - temp_dir - - - - - - -PEAR-1.8.0/PEAR/Installer/Role/Src.php100664 764 764 1730 100664 12133 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Src.php,v 1.8 2009/02/24 23:39:37 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Installer_Role_Src extends PEAR_Installer_Role_Common -{ - function setup(&$installer, $pkg, $atts, $file) - { - $installer->source_files++; - } -} -?>PEAR-1.8.0/PEAR/Installer/Role/Test.xml100777 764 764 622 100777 12325 +PEAR-1.9.0/PEAR/Installer/Role/Script.php100664 764 764 1531 100664 12650 + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Script.php 276383 2009-02-24 23:39:37Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Installer_Role_Script extends PEAR_Installer_Role_Common {} +?>PEAR-1.9.0/PEAR/Installer/Role/Src.xml100664 764 764 442 100664 12124 + extsrc + zendextsrc + 1 + temp_dir + + + + + + +PEAR-1.9.0/PEAR/Installer/Role/Src.php100664 764 764 1665 100664 12143 + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Src.php 276383 2009-02-24 23:39:37Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Installer_Role_Src extends PEAR_Installer_Role_Common +{ + function setup(&$installer, $pkg, $atts, $file) + { + $installer->source_files++; + } +} +?>PEAR-1.9.0/PEAR/Installer/Role/Test.xml100664 764 764 622 100664 12314 php extsrc extbin @@ -19223,352 +19730,9 @@ -PEAR-1.8.0/PEAR/Installer/Role/Test.php100664 764 764 1560 100664 12324 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Test.php,v 1.8 2009/02/24 23:39:37 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Installer_Role_Test extends PEAR_Installer_Role_Common {} -?>PEAR-1.8.0/PEAR/Installer/Role/Www.xml100777 764 764 662 100777 12176 - php - extsrc - extbin - zendextsrc - zendextbin - 1 - www_dir - 1 - - - - - -PEAR-1.8.0/PEAR/Installer/Role/Www.php100664 764 764 1551 100664 12171 - * @copyright 2007-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Www.php,v 1.3 2009/02/24 23:39:37 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.7.0 - */ - -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 2007-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.7.0 - */ -class PEAR_Installer_Role_Www extends PEAR_Installer_Role_Common {} -?>PEAR-1.8.0/PEAR/Installer/Role.php100664 764 764 20112 100664 11417 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Role.php,v 1.22 2009/04/10 19:42:49 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * base class for installer roles - */ -require_once 'PEAR/Installer/Role/Common.php'; -require_once 'PEAR/XMLParser.php'; -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Installer_Role -{ - /** - * Set up any additional configuration variables that file roles require - * - * Never call this directly, it is called by the PEAR_Config constructor - * @param PEAR_Config - * @access private - * @static - */ - function initializeConfig(&$config) - { - if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { - PEAR_Installer_Role::registerRoles(); - } - - foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $class => $info) { - if (!$info['config_vars']) { - continue; - } - - $config->_addConfigVars($class, $info['config_vars']); - } - } - - /** - * @param PEAR_PackageFile_v2 - * @param string role name - * @param PEAR_Config - * @return PEAR_Installer_Role_Common - * @static - */ - function &factory($pkg, $role, &$config) - { - if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { - PEAR_Installer_Role::registerRoles(); - } - - if (!in_array($role, PEAR_Installer_Role::getValidRoles($pkg->getPackageType()))) { - $a = false; - return $a; - } - - $a = 'PEAR_Installer_Role_' . ucfirst($role); - if (!class_exists($a)) { - require_once str_replace('_', '/', $a) . '.php'; - } - - $b = new $a($config); - return $b; - } - - /** - * Get a list of file roles that are valid for the particular release type. - * - * For instance, src files serve no purpose in regular php releases. - * @param string - * @param bool clear cache - * @return array - * @static - */ - function getValidRoles($release, $clear = false) - { - if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { - PEAR_Installer_Role::registerRoles(); - } - - static $ret = array(); - if ($clear) { - $ret = array(); - } - - if (isset($ret[$release])) { - return $ret[$release]; - } - - $ret[$release] = array(); - foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) { - if (in_array($release, $okreleases['releasetypes'])) { - $ret[$release][] = strtolower(str_replace('PEAR_Installer_Role_', '', $role)); - } - } - - return $ret[$release]; - } - - /** - * Get a list of roles that require their files to be installed - * - * Most roles must be installed, but src and package roles, for instance - * are pseudo-roles. src files are compiled into a new extension. Package - * roles are actually fully bundled releases of a package - * @param bool clear cache - * @return array - * @static - */ - function getInstallableRoles($clear = false) - { - if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { - PEAR_Installer_Role::registerRoles(); - } - - static $ret; - if ($clear) { - unset($ret); - } - - if (isset($ret)) { - return $ret; - } - - $ret = array(); - foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) { - if ($okreleases['installable']) { - $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role)); - } - } - - return $ret; - } - - /** - * Return an array of roles that are affected by the baseinstalldir attribute - * - * Most roles ignore this attribute, and instead install directly into: - * PackageName/filepath - * so a tests file tests/file.phpt is installed into PackageName/tests/filepath.php - * @param bool clear cache - * @return array - * @static - */ - function getBaseinstallRoles($clear = false) - { - if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { - PEAR_Installer_Role::registerRoles(); - } - - static $ret; - if ($clear) { - unset($ret); - } - - if (isset($ret)) { - return $ret; - } - - $ret = array(); - foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) { - if ($okreleases['honorsbaseinstall']) { - $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role)); - } - } - - return $ret; - } - - /** - * Return an array of file roles that should be analyzed for PHP content at package time, - * like the "php" role. - * @param bool clear cache - * @return array - * @static - */ - function getPhpRoles($clear = false) - { - if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { - PEAR_Installer_Role::registerRoles(); - } - - static $ret; - if ($clear) { - unset($ret); - } - - if (isset($ret)) { - return $ret; - } - - $ret = array(); - foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) { - if ($okreleases['phpfile']) { - $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role)); - } - } - - return $ret; - } - - /** - * Scan through the Command directory looking for classes - * and see what commands they implement. - * @param string which directory to look for classes, defaults to - * the Installer/Roles subdirectory of - * the directory from where this file (__FILE__) is - * included. - * - * @return bool TRUE on success, a PEAR error on failure - * @access public - * @static - */ - function registerRoles($dir = null) - { - $GLOBALS['_PEAR_INSTALLER_ROLES'] = array(); - $parser = new PEAR_XMLParser; - if ($dir === null) { - $dir = dirname(__FILE__) . '/Role'; - } - - if (!file_exists($dir) || !is_dir($dir)) { - return PEAR::raiseError("registerRoles: opendir($dir) failed: does not exist/is not directory"); - } - - $dp = @opendir($dir); - if (empty($dp)) { - return PEAR::raiseError("registerRoles: opendir($dir) failed: $php_errmsg"); - } - - while ($entry = readdir($dp)) { - if ($entry{0} == '.' || substr($entry, -4) != '.xml') { - continue; - } - - $class = "PEAR_Installer_Role_".substr($entry, 0, -4); - // List of roles - if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'][$class])) { - $file = "$dir/$entry"; - $parser->parse(file_get_contents($file)); - $data = $parser->getData(); - if (!is_array($data['releasetypes'])) { - $data['releasetypes'] = array($data['releasetypes']); - } - - $GLOBALS['_PEAR_INSTALLER_ROLES'][$class] = $data; - } - } - - closedir($dp); - ksort($GLOBALS['_PEAR_INSTALLER_ROLES']); - PEAR_Installer_Role::getBaseinstallRoles(true); - PEAR_Installer_Role::getInstallableRoles(true); - PEAR_Installer_Role::getPhpRoles(true); - PEAR_Installer_Role::getValidRoles('****', true); - return true; - } -}PEAR-1.8.0/PEAR/PackageFile/Generator/v1.php100664 764 764 142407 100664 13224 PEAR-1.9.0/PEAR/Installer/Role/Test.php100664 764 764 1523 100664 12324 * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: v1.php,v 1.76 2009/02/24 23:45:26 dufuz Exp $ + * @version CVS: $Id: Test.php 276383 2009-02-24 23:39:37Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since Release 1.4.0a1 */ + /** - * needed for PEAR_VALIDATE_* constants + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 */ -require_once 'PEAR/Validate.php'; -require_once 'System.php'; -require_once 'PEAR/PackageFile/v2.php'; +class PEAR_Installer_Role_Test extends PEAR_Installer_Role_Common {} +?>PEAR-1.9.0/PEAR/Installer/Role/Www.xml100664 764 764 644 100664 12165 + php + extsrc + extbin + zendextsrc + zendextbin + 1 + www_dir + 1 + + + + + +PEAR-1.9.0/PEAR/Installer/Role/Www.php100664 764 764 1514 100664 12171 + * @copyright 2007-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Www.php 276383 2009-02-24 23:39:37Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.7.0 + */ + +/** + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 2007-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.7.0 + */ +class PEAR_Installer_Role_Www extends PEAR_Installer_Role_Common {} +?>PEAR-1.9.0/PEAR/Installer/Role.php100664 764 764 17464 100664 11440 + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Role.php 278552 2009-04-10 19:42:49Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * base class for installer roles + */ +require_once 'PEAR/Installer/Role/Common.php'; +require_once 'PEAR/XMLParser.php'; +/** * @category pear * @package PEAR * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 1.4.0a1 */ -class PEAR_PackageFile_Generator_v1 +class PEAR_Installer_Role { /** - * @var PEAR_PackageFile_v1 + * Set up any additional configuration variables that file roles require + * + * Never call this directly, it is called by the PEAR_Config constructor + * @param PEAR_Config + * @access private + * @static */ - var $_packagefile; - function PEAR_PackageFile_Generator_v1(&$packagefile) + function initializeConfig(&$config) { - $this->_packagefile = &$packagefile; + if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { + PEAR_Installer_Role::registerRoles(); + } + + foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $class => $info) { + if (!$info['config_vars']) { + continue; + } + + $config->_addConfigVars($class, $info['config_vars']); + } } - function getPackagerVersion() + /** + * @param PEAR_PackageFile_v2 + * @param string role name + * @param PEAR_Config + * @return PEAR_Installer_Role_Common + * @static + */ + function &factory($pkg, $role, &$config) { - return '1.8.0'; + if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { + PEAR_Installer_Role::registerRoles(); + } + + if (!in_array($role, PEAR_Installer_Role::getValidRoles($pkg->getPackageType()))) { + $a = false; + return $a; + } + + $a = 'PEAR_Installer_Role_' . ucfirst($role); + if (!class_exists($a)) { + require_once str_replace('_', '/', $a) . '.php'; + } + + $b = new $a($config); + return $b; } /** - * @param PEAR_Packager - * @param bool if true, a .tgz is written, otherwise a .tar is written - * @param string|null directory in which to save the .tgz - * @return string|PEAR_Error location of package or error object + * Get a list of file roles that are valid for the particular release type. + * + * For instance, src files serve no purpose in regular php releases. + * @param string + * @param bool clear cache + * @return array + * @static */ - function toTgz(&$packager, $compress = true, $where = null) + function getValidRoles($release, $clear = false) { - require_once 'Archive/Tar.php'; - if ($where === null) { - if (!($where = System::mktemp(array('-d')))) { - return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: mktemp failed'); - } - } elseif (!@System::mkDir(array('-p', $where))) { - return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: "' . $where . '" could' . - ' not be created'); + if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { + PEAR_Installer_Role::registerRoles(); } - if (file_exists($where . DIRECTORY_SEPARATOR . 'package.xml') && - !is_file($where . DIRECTORY_SEPARATOR . 'package.xml')) { - return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: unable to save package.xml as' . - ' "' . $where . DIRECTORY_SEPARATOR . 'package.xml"'); + + static $ret = array(); + if ($clear) { + $ret = array(); } - if (!$this->_packagefile->validate(PEAR_VALIDATE_PACKAGING)) { - return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: invalid package file'); + + if (isset($ret[$release])) { + return $ret[$release]; } - $pkginfo = $this->_packagefile->getArray(); - $ext = $compress ? '.tgz' : '.tar'; - $pkgver = $pkginfo['package'] . '-' . $pkginfo['version']; - $dest_package = getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext; + + $ret[$release] = array(); + foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) { + if (in_array($release, $okreleases['releasetypes'])) { + $ret[$release][] = strtolower(str_replace('PEAR_Installer_Role_', '', $role)); + } + } + + return $ret[$release]; + } + + /** + * Get a list of roles that require their files to be installed + * + * Most roles must be installed, but src and package roles, for instance + * are pseudo-roles. src files are compiled into a new extension. Package + * roles are actually fully bundled releases of a package + * @param bool clear cache + * @return array + * @static + */ + function getInstallableRoles($clear = false) + { + if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { + PEAR_Installer_Role::registerRoles(); + } + + static $ret; + if ($clear) { + unset($ret); + } + + if (isset($ret)) { + return $ret; + } + + $ret = array(); + foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) { + if ($okreleases['installable']) { + $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role)); + } + } + + return $ret; + } + + /** + * Return an array of roles that are affected by the baseinstalldir attribute + * + * Most roles ignore this attribute, and instead install directly into: + * PackageName/filepath + * so a tests file tests/file.phpt is installed into PackageName/tests/filepath.php + * @param bool clear cache + * @return array + * @static + */ + function getBaseinstallRoles($clear = false) + { + if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { + PEAR_Installer_Role::registerRoles(); + } + + static $ret; + if ($clear) { + unset($ret); + } + + if (isset($ret)) { + return $ret; + } + + $ret = array(); + foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) { + if ($okreleases['honorsbaseinstall']) { + $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role)); + } + } + + return $ret; + } + + /** + * Return an array of file roles that should be analyzed for PHP content at package time, + * like the "php" role. + * @param bool clear cache + * @return array + * @static + */ + function getPhpRoles($clear = false) + { + if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { + PEAR_Installer_Role::registerRoles(); + } + + static $ret; + if ($clear) { + unset($ret); + } + + if (isset($ret)) { + return $ret; + } + + $ret = array(); + foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) { + if ($okreleases['phpfile']) { + $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role)); + } + } + + return $ret; + } + + /** + * Scan through the Command directory looking for classes + * and see what commands they implement. + * @param string which directory to look for classes, defaults to + * the Installer/Roles subdirectory of + * the directory from where this file (__FILE__) is + * included. + * + * @return bool TRUE on success, a PEAR error on failure + * @access public + * @static + */ + function registerRoles($dir = null) + { + $GLOBALS['_PEAR_INSTALLER_ROLES'] = array(); + $parser = new PEAR_XMLParser; + if ($dir === null) { + $dir = dirname(__FILE__) . '/Role'; + } + + if (!file_exists($dir) || !is_dir($dir)) { + return PEAR::raiseError("registerRoles: opendir($dir) failed: does not exist/is not directory"); + } + + $dp = @opendir($dir); + if (empty($dp)) { + return PEAR::raiseError("registerRoles: opendir($dir) failed: $php_errmsg"); + } + + while ($entry = readdir($dp)) { + if ($entry{0} == '.' || substr($entry, -4) != '.xml') { + continue; + } + + $class = "PEAR_Installer_Role_".substr($entry, 0, -4); + // List of roles + if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'][$class])) { + $file = "$dir/$entry"; + $parser->parse(file_get_contents($file)); + $data = $parser->getData(); + if (!is_array($data['releasetypes'])) { + $data['releasetypes'] = array($data['releasetypes']); + } + + $GLOBALS['_PEAR_INSTALLER_ROLES'][$class] = $data; + } + } + + closedir($dp); + ksort($GLOBALS['_PEAR_INSTALLER_ROLES']); + PEAR_Installer_Role::getBaseinstallRoles(true); + PEAR_Installer_Role::getInstallableRoles(true); + PEAR_Installer_Role::getPhpRoles(true); + PEAR_Installer_Role::getValidRoles('****', true); + return true; + } +}PEAR-1.9.0/PEAR/PackageFile/Generator/v1.php100664 764 764 142342 100664 13223 + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: v1.php 286494 2009-07-29 06:57:11Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/** + * needed for PEAR_VALIDATE_* constants + */ +require_once 'PEAR/Validate.php'; +require_once 'System.php'; +require_once 'PEAR/PackageFile/v2.php'; +/** + * This class converts a PEAR_PackageFile_v1 object into any output format. + * + * Supported output formats include array, XML string, and a PEAR_PackageFile_v2 + * object, for converting package.xml 1.0 into package.xml 2.0 with no sweat. + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_PackageFile_Generator_v1 +{ + /** + * @var PEAR_PackageFile_v1 + */ + var $_packagefile; + function PEAR_PackageFile_Generator_v1(&$packagefile) + { + $this->_packagefile = &$packagefile; + } + + function getPackagerVersion() + { + return '1.9.0'; + } + + /** + * @param PEAR_Packager + * @param bool if true, a .tgz is written, otherwise a .tar is written + * @param string|null directory in which to save the .tgz + * @return string|PEAR_Error location of package or error object + */ + function toTgz(&$packager, $compress = true, $where = null) + { + require_once 'Archive/Tar.php'; + if ($where === null) { + if (!($where = System::mktemp(array('-d')))) { + return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: mktemp failed'); + } + } elseif (!@System::mkDir(array('-p', $where))) { + return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: "' . $where . '" could' . + ' not be created'); + } + if (file_exists($where . DIRECTORY_SEPARATOR . 'package.xml') && + !is_file($where . DIRECTORY_SEPARATOR . 'package.xml')) { + return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: unable to save package.xml as' . + ' "' . $where . DIRECTORY_SEPARATOR . 'package.xml"'); + } + if (!$this->_packagefile->validate(PEAR_VALIDATE_PACKAGING)) { + return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: invalid package file'); + } + $pkginfo = $this->_packagefile->getArray(); + $ext = $compress ? '.tgz' : '.tar'; + $pkgver = $pkginfo['package'] . '-' . $pkginfo['version']; + $dest_package = getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext; if (file_exists(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext) && !is_file(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext)) { return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: cannot create tgz file "' . @@ -19768,7 +20275,7 @@ ); $ret = "\n"; $ret .= "\n"; - $ret .= "\n" . + $ret .= "\n" . " $pkginfo[package]"; if (isset($pkginfo['extends'])) { $ret .= "\n$pkginfo[extends]"; @@ -20783,16 +21290,15 @@ */ function _processMultipleDepsName($deps) { - $tests = array(); + $ret = $tests = array(); foreach ($deps as $name => $dep) { foreach ($dep as $d) { $tests[$name][] = $this->_processDep($d); } } + foreach ($tests as $name => $test) { - $php = array(); - $min = array(); - $max = array(); + $max = $min = $php = array(); $php['name'] = $name; foreach ($test as $dep) { if (!$dep) { @@ -20850,7 +21356,7 @@ return $ret; } } -?>PEAR-1.8.0/PEAR/PackageFile/Generator/v2.php100664 764 764 101226 100664 13217 PEAR-1.9.0/PEAR/PackageFile/Generator/v2.php100664 764 764 101360 100664 13217 options['beautifyFilelist'] = true; } - $arr['attribs']['packagerversion'] = '1.8.0'; + $arr['attribs']['packagerversion'] = '1.9.0'; if ($this->serialize($arr, $options)) { return $this->_serializedData . "\n"; } @@ -21723,7 +22230,7 @@ if ($this->options['encoding'] == 'UTF-8' && version_compare(phpversion(), '5.0.0', 'lt') ) { - $tag = utf8_encode($tag); + $tag['content'] = utf8_encode($tag['content']); } if ($replaceEntities === true) { @@ -21741,7 +22248,7 @@ } return $tag; } -}PEAR-1.8.0/PEAR/PackageFile/Parser/v1.php100664 764 764 40317 100664 12507 * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: v1.php,v 1.30 2009/02/24 23:45:22 dufuz Exp $ + * @version CVS: $Id: v1.php 276385 2009-02-24 23:46:03Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since Release 1.4.0a1 */ @@ -22199,7 +22706,7 @@ // }}} } -?>PEAR-1.8.0/PEAR/PackageFile/Parser/v2.php100664 764 764 6220 100664 12463 PEAR-1.9.0/PEAR/PackageFile/Parser/v2.php100664 764 764 6215 100664 12470 * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: v2.php,v 1.24 2009/02/24 23:45:22 dufuz Exp $ + * @version CVS: $Id: v2.php 276385 2009-02-24 23:46:03Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since Release 1.4.0a1 */ @@ -22311,7 +22818,7 @@ $ret->setPackagefile($file, $archive); return $ret; } -}PEAR-1.8.0/PEAR/PackageFile/v2/rw.php100664 764 764 173213 100664 11726 * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: rw.php,v 1.25 2009/02/24 23:46:03 dufuz Exp $ + * @version CVS: $Id: rw.php 276385 2009-02-24 23:46:03Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since Release 1.4.0a8 */ @@ -22336,7 +22843,7 @@ * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 1.4.0a8 */ @@ -23914,7 +24421,7 @@ { unset($this->_packageInfo['changelog']); } -}PEAR-1.8.0/PEAR/PackageFile/v2/Validator.php100664 764 764 250045 100664 13222 * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Validator.php,v 1.110 2009/03/27 19:29:31 dufuz Exp $ + * @version CVS: $Id: Validator.php 277885 2009-03-27 19:29:31Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since Release 1.4.0a8 */ @@ -23937,7 +24444,7 @@ * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 1.4.0a8 * @access private @@ -24028,7 +24535,7 @@ isset($test['dependencies']['required']) && isset($test['dependencies']['required']['pearinstaller']) && isset($test['dependencies']['required']['pearinstaller']['min']) && - version_compare('1.8.0', + version_compare('1.9.0', $test['dependencies']['required']['pearinstaller']['min'], '<') ) { $this->_pearVersionTooLow($test['dependencies']['required']['pearinstaller']['min']); @@ -25267,7 +25774,7 @@ $this->_stack->push(__FUNCTION__, 'error', array('version' => $version), 'This package.xml requires PEAR version %version% to parse properly, we are ' . - 'version 1.8.0'); + 'version 1.9.0'); } function _invalidTagOrder($oktags, $actual, $root) @@ -26067,1621 +26574,9 @@ return $providesret; } -}PEAR-1.8.0/PEAR/PackageFile/v1.php100664 764 764 147077 100664 11306 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: v1.php,v 1.75 2009/02/24 23:39:16 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * For error handling - */ -require_once 'PEAR/ErrorStack.php'; - -/** - * Error code if parsing is attempted with no xml extension - */ -define('PEAR_PACKAGEFILE_ERROR_NO_XML_EXT', 3); - -/** - * Error code if creating the xml parser resource fails - */ -define('PEAR_PACKAGEFILE_ERROR_CANT_MAKE_PARSER', 4); - -/** - * Error code used for all sax xml parsing errors - */ -define('PEAR_PACKAGEFILE_ERROR_PARSER_ERROR', 5); - -/** - * Error code used when there is no name - */ -define('PEAR_PACKAGEFILE_ERROR_NO_NAME', 6); - -/** - * Error code when a package name is not valid - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_NAME', 7); - -/** - * Error code used when no summary is parsed - */ -define('PEAR_PACKAGEFILE_ERROR_NO_SUMMARY', 8); - -/** - * Error code for summaries that are more than 1 line - */ -define('PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY', 9); - -/** - * Error code used when no description is present - */ -define('PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION', 10); - -/** - * Error code used when no license is present - */ -define('PEAR_PACKAGEFILE_ERROR_NO_LICENSE', 11); - -/** - * Error code used when a version number is not present - */ -define('PEAR_PACKAGEFILE_ERROR_NO_VERSION', 12); - -/** - * Error code used when a version number is invalid - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_VERSION', 13); - -/** - * Error code when release state is missing - */ -define('PEAR_PACKAGEFILE_ERROR_NO_STATE', 14); - -/** - * Error code when release state is invalid - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_STATE', 15); - -/** - * Error code when release state is missing - */ -define('PEAR_PACKAGEFILE_ERROR_NO_DATE', 16); - -/** - * Error code when release state is invalid - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_DATE', 17); - -/** - * Error code when no release notes are found - */ -define('PEAR_PACKAGEFILE_ERROR_NO_NOTES', 18); - -/** - * Error code when no maintainers are found - */ -define('PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS', 19); - -/** - * Error code when a maintainer has no handle - */ -define('PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE', 20); - -/** - * Error code when a maintainer has no handle - */ -define('PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE', 21); - -/** - * Error code when a maintainer has no name - */ -define('PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME', 22); - -/** - * Error code when a maintainer has no email - */ -define('PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL', 23); - -/** - * Error code when a maintainer has no handle - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_MAINTROLE', 24); - -/** - * Error code when a dependency is not a PHP dependency, but has no name - */ -define('PEAR_PACKAGEFILE_ERROR_NO_DEPNAME', 25); - -/** - * Error code when a dependency has no type (pkg, php, etc.) - */ -define('PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE', 26); - -/** - * Error code when a dependency has no relation (lt, ge, has, etc.) - */ -define('PEAR_PACKAGEFILE_ERROR_NO_DEPREL', 27); - -/** - * Error code when a dependency is not a 'has' relation, but has no version - */ -define('PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION', 28); - -/** - * Error code when a dependency has an invalid relation - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPREL', 29); - -/** - * Error code when a dependency has an invalid type - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPTYPE', 30); - -/** - * Error code when a dependency has an invalid optional option - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL', 31); - -/** - * Error code when a dependency is a pkg dependency, and has an invalid package name - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPNAME', 32); - -/** - * Error code when a dependency has a channel="foo" attribute, and foo is not a registered channel - */ -define('PEAR_PACKAGEFILE_ERROR_UNKNOWN_DEPCHANNEL', 33); - -/** - * Error code when rel="has" and version attribute is present. - */ -define('PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED', 34); - -/** - * Error code when type="php" and dependency name is present - */ -define('PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED', 35); - -/** - * Error code when a configure option has no name - */ -define('PEAR_PACKAGEFILE_ERROR_NO_CONFNAME', 36); - -/** - * Error code when a configure option has no name - */ -define('PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT', 37); - -/** - * Error code when a file in the filelist has an invalid role - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE', 38); - -/** - * Error code when a file in the filelist has no role - */ -define('PEAR_PACKAGEFILE_ERROR_NO_FILEROLE', 39); - -/** - * Error code when analyzing a php source file that has parse errors - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE', 40); - -/** - * Error code when analyzing a php source file reveals a source element - * without a package name prefix - */ -define('PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX', 41); - -/** - * Error code when an unknown channel is specified - */ -define('PEAR_PACKAGEFILE_ERROR_UNKNOWN_CHANNEL', 42); - -/** - * Error code when no files are found in the filelist - */ -define('PEAR_PACKAGEFILE_ERROR_NO_FILES', 43); - -/** - * Error code when a file is not valid php according to _analyzeSourceCode() - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_FILE', 44); - -/** - * Error code when the channel validator returns an error or warning - */ -define('PEAR_PACKAGEFILE_ERROR_CHANNELVAL', 45); - -/** - * Error code when a php5 package is packaged in php4 (analysis doesn't work) - */ -define('PEAR_PACKAGEFILE_ERROR_PHP5', 46); - -/** - * Error code when a file is listed in package.xml but does not exist - */ -define('PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND', 47); - -/** - * Error code when a - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_PackageFile_v1 -{ - /** - * @access private - * @var PEAR_ErrorStack - * @access private - */ - var $_stack; - - /** - * A registry object, used to access the package name validation regex for non-standard channels - * @var PEAR_Registry - * @access private - */ - var $_registry; - - /** - * An object that contains a log method that matches PEAR_Common::log's signature - * @var object - * @access private - */ - var $_logger; - - /** - * Parsed package information - * @var array - * @access private - */ - var $_packageInfo; - - /** - * path to package.xml - * @var string - * @access private - */ - var $_packageFile; - - /** - * path to package .tgz or false if this is a local/extracted package.xml - * @var string - * @access private - */ - var $_archiveFile; - - /** - * @var int - * @access private - */ - var $_isValid = 0; - - /** - * Determines whether this packagefile was initialized only with partial package info - * - * If this package file was constructed via parsing REST, it will only contain - * - * - package name - * - channel name - * - dependencies - * @var boolean - * @access private - */ - var $_incomplete = true; - - /** - * @param bool determines whether to return a PEAR_Error object, or use the PEAR_ErrorStack - * @param string Name of Error Stack class to use. - */ - function PEAR_PackageFile_v1() - { - $this->_stack = &new PEAR_ErrorStack('PEAR_PackageFile_v1'); - $this->_stack->setErrorMessageTemplate($this->_getErrorMessage()); - $this->_isValid = 0; - } - - function installBinary($installer) - { - return false; - } - - function isExtension($name) - { - return false; - } - - function setConfig(&$config) - { - $this->_config = &$config; - $this->_registry = &$config->getRegistry(); - } - - function setRequestedGroup() - { - // placeholder - } - - /** - * For saving in the registry. - * - * Set the last version that was installed - * @param string - */ - function setLastInstalledVersion($version) - { - $this->_packageInfo['_lastversion'] = $version; - } - - /** - * @return string|false - */ - function getLastInstalledVersion() - { - if (isset($this->_packageInfo['_lastversion'])) { - return $this->_packageInfo['_lastversion']; - } - return false; - } - - function getInstalledBinary() - { - return false; - } - - function listPostinstallScripts() - { - return false; - } - - function initPostinstallScripts() - { - return false; - } - - function setLogger(&$logger) - { - if ($logger && (!is_object($logger) || !method_exists($logger, 'log'))) { - return PEAR::raiseError('Logger must be compatible with PEAR_Common::log'); - } - $this->_logger = &$logger; - } - - function setPackagefile($file, $archive = false) - { - $this->_packageFile = $file; - $this->_archiveFile = $archive ? $archive : $file; - } - - function getPackageFile() - { - return isset($this->_packageFile) ? $this->_packageFile : false; - } - - function getPackageType() - { - return 'php'; - } - - function getArchiveFile() - { - return $this->_archiveFile; - } - - function packageInfo($field) - { - if (!is_string($field) || empty($field) || - !isset($this->_packageInfo[$field])) { - return false; - } - return $this->_packageInfo[$field]; - } - - function setDirtree($path) - { - if (!isset($this->_packageInfo['dirtree'])) { - $this->_packageInfo['dirtree'] = array(); - } - $this->_packageInfo['dirtree'][$path] = true; - } - - function getDirtree() - { - if (isset($this->_packageInfo['dirtree']) && count($this->_packageInfo['dirtree'])) { - return $this->_packageInfo['dirtree']; - } - return false; - } - - function resetDirtree() - { - unset($this->_packageInfo['dirtree']); - } - - function fromArray($pinfo) - { - $this->_incomplete = false; - $this->_packageInfo = $pinfo; - } - - function isIncomplete() - { - return $this->_incomplete; - } - - function getChannel() - { - return 'pear.php.net'; - } - - function getUri() - { - return false; - } - - function getTime() - { - return false; - } - - function getExtends() - { - if (isset($this->_packageInfo['extends'])) { - return $this->_packageInfo['extends']; - } - return false; - } - - /** - * @return array - */ - function toArray() - { - if (!$this->validate(PEAR_VALIDATE_NORMAL)) { - return false; - } - return $this->getArray(); - } - - function getArray() - { - return $this->_packageInfo; - } - - function getName() - { - return $this->getPackage(); - } - - function getPackage() - { - if (isset($this->_packageInfo['package'])) { - return $this->_packageInfo['package']; - } - return false; - } - - /** - * WARNING - don't use this unless you know what you are doing - */ - function setRawPackage($package) - { - $this->_packageInfo['package'] = $package; - } - - function setPackage($package) - { - $this->_packageInfo['package'] = $package; - $this->_isValid = false; - } - - function getVersion() - { - if (isset($this->_packageInfo['version'])) { - return $this->_packageInfo['version']; - } - return false; - } - - function setVersion($version) - { - $this->_packageInfo['version'] = $version; - $this->_isValid = false; - } - - function clearMaintainers() - { - unset($this->_packageInfo['maintainers']); - } - - function getMaintainers() - { - if (isset($this->_packageInfo['maintainers'])) { - return $this->_packageInfo['maintainers']; - } - return false; - } - - /** - * Adds a new maintainer - no checking of duplicates is performed, use - * updatemaintainer for that purpose. - */ - function addMaintainer($role, $handle, $name, $email) - { - $this->_packageInfo['maintainers'][] = - array('handle' => $handle, 'role' => $role, 'email' => $email, 'name' => $name); - $this->_isValid = false; - } - - function updateMaintainer($role, $handle, $name, $email) - { - $found = false; - if (!isset($this->_packageInfo['maintainers']) || - !is_array($this->_packageInfo['maintainers'])) { - return $this->addMaintainer($role, $handle, $name, $email); - } - foreach ($this->_packageInfo['maintainers'] as $i => $maintainer) { - if ($maintainer['handle'] == $handle) { - $found = $i; - break; - } - } - if ($found !== false) { - unset($this->_packageInfo['maintainers'][$found]); - $this->_packageInfo['maintainers'] = - array_values($this->_packageInfo['maintainers']); - } - $this->addMaintainer($role, $handle, $name, $email); - } - - function deleteMaintainer($handle) - { - $found = false; - foreach ($this->_packageInfo['maintainers'] as $i => $maintainer) { - if ($maintainer['handle'] == $handle) { - $found = $i; - break; - } - } - if ($found !== false) { - unset($this->_packageInfo['maintainers'][$found]); - $this->_packageInfo['maintainers'] = - array_values($this->_packageInfo['maintainers']); - return true; - } - return false; - } - - function getState() - { - if (isset($this->_packageInfo['release_state'])) { - return $this->_packageInfo['release_state']; - } - return false; - } - - function setRawState($state) - { - $this->_packageInfo['release_state'] = $state; - } - - function setState($state) - { - $this->_packageInfo['release_state'] = $state; - $this->_isValid = false; - } - - function getDate() - { - if (isset($this->_packageInfo['release_date'])) { - return $this->_packageInfo['release_date']; - } - return false; - } - - function setDate($date) - { - $this->_packageInfo['release_date'] = $date; - $this->_isValid = false; - } - - function getLicense() - { - if (isset($this->_packageInfo['release_license'])) { - return $this->_packageInfo['release_license']; - } - return false; - } - - function setLicense($date) - { - $this->_packageInfo['release_license'] = $date; - $this->_isValid = false; - } - - function getSummary() - { - if (isset($this->_packageInfo['summary'])) { - return $this->_packageInfo['summary']; - } - return false; - } - - function setSummary($summary) - { - $this->_packageInfo['summary'] = $summary; - $this->_isValid = false; - } - - function getDescription() - { - if (isset($this->_packageInfo['description'])) { - return $this->_packageInfo['description']; - } - return false; - } - - function setDescription($desc) - { - $this->_packageInfo['description'] = $desc; - $this->_isValid = false; - } - - function getNotes() - { - if (isset($this->_packageInfo['release_notes'])) { - return $this->_packageInfo['release_notes']; - } - return false; - } - - function setNotes($notes) - { - $this->_packageInfo['release_notes'] = $notes; - $this->_isValid = false; - } - - function getDeps() - { - if (isset($this->_packageInfo['release_deps'])) { - return $this->_packageInfo['release_deps']; - } - return false; - } - - /** - * Reset dependencies prior to adding new ones - */ - function clearDeps() - { - unset($this->_packageInfo['release_deps']); - } - - function addPhpDep($version, $rel) - { - $this->_isValid = false; - $this->_packageInfo['release_deps'][] = - array('type' => 'php', - 'rel' => $rel, - 'version' => $version); - } - - function addPackageDep($name, $version, $rel, $optional = 'no') - { - $this->_isValid = false; - $dep = - array('type' => 'pkg', - 'name' => $name, - 'rel' => $rel, - 'optional' => $optional); - if ($rel != 'has' && $rel != 'not') { - $dep['version'] = $version; - } - $this->_packageInfo['release_deps'][] = $dep; - } - - function addExtensionDep($name, $version, $rel, $optional = 'no') - { - $this->_isValid = false; - $this->_packageInfo['release_deps'][] = - array('type' => 'ext', - 'name' => $name, - 'rel' => $rel, - 'version' => $version, - 'optional' => $optional); - } - - /** - * WARNING - do not use this function directly unless you know what you're doing - */ - function setDeps($deps) - { - $this->_packageInfo['release_deps'] = $deps; - } - - function hasDeps() - { - return isset($this->_packageInfo['release_deps']) && - count($this->_packageInfo['release_deps']); - } - - function getDependencyGroup($group) - { - return false; - } - - function isCompatible($pf) - { - return false; - } - - function isSubpackageOf($p) - { - return $p->isSubpackage($this); - } - - function isSubpackage($p) - { - return false; - } - - function dependsOn($package, $channel) - { - if (strtolower($channel) != 'pear.php.net') { - return false; - } - if (!($deps = $this->getDeps())) { - return false; - } - foreach ($deps as $dep) { - if ($dep['type'] != 'pkg') { - continue; - } - if (strtolower($dep['name']) == strtolower($package)) { - return true; - } - } - return false; - } - - function getConfigureOptions() - { - if (isset($this->_packageInfo['configure_options'])) { - return $this->_packageInfo['configure_options']; - } - return false; - } - - function hasConfigureOptions() - { - return isset($this->_packageInfo['configure_options']) && - count($this->_packageInfo['configure_options']); - } - - function addConfigureOption($name, $prompt, $default = false) - { - $o = array('name' => $name, 'prompt' => $prompt); - if ($default !== false) { - $o['default'] = $default; - } - if (!isset($this->_packageInfo['configure_options'])) { - $this->_packageInfo['configure_options'] = array(); - } - $this->_packageInfo['configure_options'][] = $o; - } - - function clearConfigureOptions() - { - unset($this->_packageInfo['configure_options']); - } - - function getProvides() - { - if (isset($this->_packageInfo['provides'])) { - return $this->_packageInfo['provides']; - } - return false; - } - - function getProvidesExtension() - { - return false; - } - - function addFile($dir, $file, $attrs) - { - $dir = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), $dir); - if ($dir == '/' || $dir == '') { - $dir = ''; - } else { - $dir .= '/'; - } - $file = $dir . $file; - $file = preg_replace('![\\/]+!', '/', $file); - $this->_packageInfo['filelist'][$file] = $attrs; - } - - function getInstallationFilelist() - { - return $this->getFilelist(); - } - - function getFilelist() - { - if (isset($this->_packageInfo['filelist'])) { - return $this->_packageInfo['filelist']; - } - return false; - } - - function setFileAttribute($file, $attr, $value) - { - $this->_packageInfo['filelist'][$file][$attr] = $value; - } - - function resetFilelist() - { - $this->_packageInfo['filelist'] = array(); - } - - function setInstalledAs($file, $path) - { - if ($path) { - return $this->_packageInfo['filelist'][$file]['installed_as'] = $path; - } - unset($this->_packageInfo['filelist'][$file]['installed_as']); - } - - function installedFile($file, $atts) - { - if (isset($this->_packageInfo['filelist'][$file])) { - $this->_packageInfo['filelist'][$file] = - array_merge($this->_packageInfo['filelist'][$file], $atts); - } else { - $this->_packageInfo['filelist'][$file] = $atts; - } - } - - function getChangelog() - { - if (isset($this->_packageInfo['changelog'])) { - return $this->_packageInfo['changelog']; - } - return false; - } - - function getPackagexmlVersion() - { - return '1.0'; - } - - /** - * Wrapper to {@link PEAR_ErrorStack::getErrors()} - * @param boolean determines whether to purge the error stack after retrieving - * @return array - */ - function getValidationWarnings($purge = true) - { - return $this->_stack->getErrors($purge); - } - - // }}} - /** - * Validation error. Also marks the object contents as invalid - * @param error code - * @param array error information - * @access private - */ - function _validateError($code, $params = array()) - { - $this->_stack->push($code, 'error', $params, false, false, debug_backtrace()); - $this->_isValid = false; - } - - /** - * Validation warning. Does not mark the object contents invalid. - * @param error code - * @param array error information - * @access private - */ - function _validateWarning($code, $params = array()) - { - $this->_stack->push($code, 'warning', $params, false, false, debug_backtrace()); - } - - /** - * @param integer error code - * @access protected - */ - function _getErrorMessage() - { - return array( - PEAR_PACKAGEFILE_ERROR_NO_NAME => - 'Missing Package Name', - PEAR_PACKAGEFILE_ERROR_NO_SUMMARY => - 'No summary found', - PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY => - 'Summary should be on one line', - PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION => - 'Missing description', - PEAR_PACKAGEFILE_ERROR_NO_LICENSE => - 'Missing license', - PEAR_PACKAGEFILE_ERROR_NO_VERSION => - 'No release version found', - PEAR_PACKAGEFILE_ERROR_NO_STATE => - 'No release state found', - PEAR_PACKAGEFILE_ERROR_NO_DATE => - 'No release date found', - PEAR_PACKAGEFILE_ERROR_NO_NOTES => - 'No release notes found', - PEAR_PACKAGEFILE_ERROR_NO_LEAD => - 'Package must have at least one lead maintainer', - PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS => - 'No maintainers found, at least one must be defined', - PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE => - 'Maintainer %index% has no handle (user ID at channel server)', - PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE => - 'Maintainer %index% has no role', - PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME => - 'Maintainer %index% has no name', - PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL => - 'Maintainer %index% has no email', - PEAR_PACKAGEFILE_ERROR_NO_DEPNAME => - 'Dependency %index% is not a php dependency, and has no name', - PEAR_PACKAGEFILE_ERROR_NO_DEPREL => - 'Dependency %index% has no relation (rel)', - PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE => - 'Dependency %index% has no type', - PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED => - 'PHP Dependency %index% has a name attribute of "%name%" which will be' . - ' ignored!', - PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION => - 'Dependency %index% is not a rel="has" or rel="not" dependency, ' . - 'and has no version', - PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION => - 'Dependency %index% is a type="php" dependency, ' . - 'and has no version', - PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED => - 'Dependency %index% is a rel="%rel%" dependency, versioning is ignored', - PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL => - 'Dependency %index% has invalid optional value "%opt%", should be yes or no', - PEAR_PACKAGEFILE_PHP_NO_NOT => - 'Dependency %index%: php dependencies cannot use "not" rel, use "ne"' . - ' to exclude specific versions', - PEAR_PACKAGEFILE_ERROR_NO_CONFNAME => - 'Configure Option %index% has no name', - PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT => - 'Configure Option %index% has no prompt', - PEAR_PACKAGEFILE_ERROR_NO_FILES => - 'No files in section of package.xml', - PEAR_PACKAGEFILE_ERROR_NO_FILEROLE => - 'File "%file%" has no role, expecting one of "%roles%"', - PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE => - 'File "%file%" has invalid role "%role%", expecting one of "%roles%"', - PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME => - 'File "%file%" cannot start with ".", cannot package or install', - PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE => - 'Parser error: invalid PHP found in file "%file%"', - PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX => - 'in %file%: %type% "%name%" not prefixed with package name "%package%"', - PEAR_PACKAGEFILE_ERROR_INVALID_FILE => - 'Parser error: invalid PHP file "%file%"', - PEAR_PACKAGEFILE_ERROR_CHANNELVAL => - 'Channel validator error: field "%field%" - %reason%', - PEAR_PACKAGEFILE_ERROR_PHP5 => - 'Error, PHP5 token encountered in %file%, analysis should be in PHP5', - PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND => - 'File "%file%" in package.xml does not exist', - PEAR_PACKAGEFILE_ERROR_NON_ISO_CHARS => - 'Package.xml contains non-ISO-8859-1 characters, and may not validate', - ); - } - - /** - * Validate XML package definition file. - * - * @access public - * @return boolean - */ - function validate($state = PEAR_VALIDATE_NORMAL, $nofilechecking = false) - { - if (($this->_isValid & $state) == $state) { - return true; - } - $this->_isValid = true; - $info = $this->_packageInfo; - if (empty($info['package'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_NAME); - $this->_packageName = $pn = 'unknown'; - } else { - $this->_packageName = $pn = $info['package']; - } - - if (empty($info['summary'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_SUMMARY); - } elseif (strpos(trim($info['summary']), "\n") !== false) { - $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY, - array('summary' => $info['summary'])); - } - if (empty($info['description'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION); - } - if (empty($info['release_license'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_LICENSE); - } - if (empty($info['version'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_VERSION); - } - if (empty($info['release_state'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_STATE); - } - if (empty($info['release_date'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DATE); - } - if (empty($info['release_notes'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_NOTES); - } - if (empty($info['maintainers'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS); - } else { - $haslead = false; - $i = 1; - foreach ($info['maintainers'] as $m) { - if (empty($m['handle'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE, - array('index' => $i)); - } - if (empty($m['role'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE, - array('index' => $i, 'roles' => PEAR_Common::getUserRoles())); - } elseif ($m['role'] == 'lead') { - $haslead = true; - } - if (empty($m['name'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME, - array('index' => $i)); - } - if (empty($m['email'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL, - array('index' => $i)); - } - $i++; - } - if (!$haslead) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_LEAD); - } - } - if (!empty($info['release_deps'])) { - $i = 1; - foreach ($info['release_deps'] as $d) { - if (!isset($d['type']) || empty($d['type'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE, - array('index' => $i, 'types' => PEAR_Common::getDependencyTypes())); - continue; - } - if (!isset($d['rel']) || empty($d['rel'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPREL, - array('index' => $i, 'rels' => PEAR_Common::getDependencyRelations())); - continue; - } - if (!empty($d['optional'])) { - if (!in_array($d['optional'], array('yes', 'no'))) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL, - array('index' => $i, 'opt' => $d['optional'])); - } - } - if ($d['rel'] != 'has' && $d['rel'] != 'not' && empty($d['version'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION, - array('index' => $i)); - } elseif (($d['rel'] == 'has' || $d['rel'] == 'not') && !empty($d['version'])) { - $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED, - array('index' => $i, 'rel' => $d['rel'])); - } - if ($d['type'] == 'php' && !empty($d['name'])) { - $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED, - array('index' => $i, 'name' => $d['name'])); - } elseif ($d['type'] != 'php' && empty($d['name'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPNAME, - array('index' => $i)); - } - if ($d['type'] == 'php' && empty($d['version'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION, - array('index' => $i)); - } - if (($d['rel'] == 'not') && ($d['type'] == 'php')) { - $this->_validateError(PEAR_PACKAGEFILE_PHP_NO_NOT, - array('index' => $i)); - } - $i++; - } - } - if (!empty($info['configure_options'])) { - $i = 1; - foreach ($info['configure_options'] as $c) { - if (empty($c['name'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_CONFNAME, - array('index' => $i)); - } - if (empty($c['prompt'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT, - array('index' => $i)); - } - $i++; - } - } - if (empty($info['filelist'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_FILES); - $errors[] = 'no files'; - } else { - foreach ($info['filelist'] as $file => $fa) { - if (empty($fa['role'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_FILEROLE, - array('file' => $file, 'roles' => PEAR_Common::getFileRoles())); - continue; - } elseif (!in_array($fa['role'], PEAR_Common::getFileRoles())) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE, - array('file' => $file, 'role' => $fa['role'], 'roles' => PEAR_Common::getFileRoles())); - } - if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~', str_replace('\\', '/', $file))) { - // file contains .. parent directory or . cur directory references - $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME, - array('file' => $file)); - } - if (isset($fa['install-as']) && - preg_match('~/\.\.?(/|\\z)|^\.\.?/~', - str_replace('\\', '/', $fa['install-as']))) { - // install-as contains .. parent directory or . cur directory references - $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME, - array('file' => $file . ' [installed as ' . $fa['install-as'] . ']')); - } - if (isset($fa['baseinstalldir']) && - preg_match('~/\.\.?(/|\\z)|^\.\.?/~', - str_replace('\\', '/', $fa['baseinstalldir']))) { - // install-as contains .. parent directory or . cur directory references - $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME, - array('file' => $file . ' [baseinstalldir ' . $fa['baseinstalldir'] . ']')); - } - } - } - if (isset($this->_registry) && $this->_isValid) { - $chan = $this->_registry->getChannel('pear.php.net'); - if (PEAR::isError($chan)) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $chan->getMessage()); - return $this->_isValid = 0; - } - $validator = $chan->getValidationObject(); - $validator->setPackageFile($this); - $validator->validate($state); - $failures = $validator->getFailures(); - foreach ($failures['errors'] as $error) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $error); - } - foreach ($failures['warnings'] as $warning) { - $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $warning); - } - } - if ($this->_isValid && $state == PEAR_VALIDATE_PACKAGING && !$nofilechecking) { - if ($this->_analyzePhpFiles()) { - $this->_isValid = true; - } - } - if ($this->_isValid) { - return $this->_isValid = $state; - } - return $this->_isValid = 0; - } - - function _analyzePhpFiles() - { - if (!$this->_isValid) { - return false; - } - if (!isset($this->_packageFile)) { - return false; - } - $dir_prefix = dirname($this->_packageFile); - $common = new PEAR_Common; - $log = isset($this->_logger) ? array(&$this->_logger, 'log') : - array($common, 'log'); - $info = $this->getFilelist(); - foreach ($info as $file => $fa) { - if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $file)) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND, - array('file' => realpath($dir_prefix) . DIRECTORY_SEPARATOR . $file)); - continue; - } - if ($fa['role'] == 'php' && $dir_prefix) { - call_user_func_array($log, array(1, "Analyzing $file")); - $srcinfo = $this->_analyzeSourceCode($dir_prefix . DIRECTORY_SEPARATOR . $file); - if ($srcinfo) { - $this->_buildProvidesArray($srcinfo); - } - } - } - $this->_packageName = $pn = $this->getPackage(); - $pnl = strlen($pn); - if (isset($this->_packageInfo['provides'])) { - foreach ((array) $this->_packageInfo['provides'] as $key => $what) { - if (isset($what['explicit'])) { - // skip conformance checks if the provides entry is - // specified in the package.xml file - continue; - } - extract($what); - if ($type == 'class') { - if (!strncasecmp($name, $pn, $pnl)) { - continue; - } - $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX, - array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn)); - } elseif ($type == 'function') { - if (strstr($name, '::') || !strncasecmp($name, $pn, $pnl)) { - continue; - } - $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX, - array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn)); - } - } - } - return $this->_isValid; - } - - /** - * Get the default xml generator object - * - * @return PEAR_PackageFile_Generator_v1 - */ - function &getDefaultGenerator() - { - if (!class_exists('PEAR_PackageFile_Generator_v1')) { - require_once 'PEAR/PackageFile/Generator/v1.php'; - } - $a = &new PEAR_PackageFile_Generator_v1($this); - return $a; - } - - /** - * Get the contents of a file listed within the package.xml - * @param string - * @return string - */ - function getFileContents($file) - { - if ($this->_archiveFile == $this->_packageFile) { // unpacked - $dir = dirname($this->_packageFile); - $file = $dir . DIRECTORY_SEPARATOR . $file; - $file = str_replace(array('/', '\\'), - array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), $file); - if (file_exists($file) && is_readable($file)) { - return implode('', file($file)); - } - } else { // tgz - if (!class_exists('Archive_Tar')) { - require_once 'Archive/Tar.php'; - } - $tar = &new Archive_Tar($this->_archiveFile); - $tar->pushErrorHandling(PEAR_ERROR_RETURN); - if ($file != 'package.xml' && $file != 'package2.xml') { - $file = $this->getPackage() . '-' . $this->getVersion() . '/' . $file; - } - $file = $tar->extractInString($file); - $tar->popErrorHandling(); - if (PEAR::isError($file)) { - return PEAR::raiseError("Cannot locate file '$file' in archive"); - } - return $file; - } - } - - // {{{ analyzeSourceCode() - /** - * Analyze the source code of the given PHP file - * - * @param string Filename of the PHP file - * @return mixed - * @access private - */ - function _analyzeSourceCode($file) - { - if (!function_exists("token_get_all")) { - return false; - } - if (!defined('T_DOC_COMMENT')) { - define('T_DOC_COMMENT', T_COMMENT); - } - if (!defined('T_INTERFACE')) { - define('T_INTERFACE', -1); - } - if (!defined('T_IMPLEMENTS')) { - define('T_IMPLEMENTS', -1); - } - if (!$fp = @fopen($file, "r")) { - return false; - } - fclose($fp); - $contents = file_get_contents($file); - $tokens = token_get_all($contents); -/* - for ($i = 0; $i < sizeof($tokens); $i++) { - @list($token, $data) = $tokens[$i]; - if (is_string($token)) { - var_dump($token); - } else { - print token_name($token) . ' '; - var_dump(rtrim($data)); - } - } -*/ - $look_for = 0; - $paren_level = 0; - $bracket_level = 0; - $brace_level = 0; - $lastphpdoc = ''; - $current_class = ''; - $current_interface = ''; - $current_class_level = -1; - $current_function = ''; - $current_function_level = -1; - $declared_classes = array(); - $declared_interfaces = array(); - $declared_functions = array(); - $declared_methods = array(); - $used_classes = array(); - $used_functions = array(); - $extends = array(); - $implements = array(); - $nodeps = array(); - $inquote = false; - $interface = false; - for ($i = 0; $i < sizeof($tokens); $i++) { - if (is_array($tokens[$i])) { - list($token, $data) = $tokens[$i]; - } else { - $token = $tokens[$i]; - $data = ''; - } - if ($inquote) { - if ($token != '"' && $token != T_END_HEREDOC) { - continue; - } else { - $inquote = false; - continue; - } - } - switch ($token) { - case T_WHITESPACE : - continue; - case ';': - if ($interface) { - $current_function = ''; - $current_function_level = -1; - } - break; - case '"': - case T_START_HEREDOC: - $inquote = true; - break; - case T_CURLY_OPEN: - case T_DOLLAR_OPEN_CURLY_BRACES: - case '{': $brace_level++; continue 2; - case '}': - $brace_level--; - if ($current_class_level == $brace_level) { - $current_class = ''; - $current_class_level = -1; - } - if ($current_function_level == $brace_level) { - $current_function = ''; - $current_function_level = -1; - } - continue 2; - case '[': $bracket_level++; continue 2; - case ']': $bracket_level--; continue 2; - case '(': $paren_level++; continue 2; - case ')': $paren_level--; continue 2; - case T_INTERFACE: - $interface = true; - case T_CLASS: - if (($current_class_level != -1) || ($current_function_level != -1)) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE, - array('file' => $file)); - return false; - } - case T_FUNCTION: - case T_NEW: - case T_EXTENDS: - case T_IMPLEMENTS: - $look_for = $token; - continue 2; - case T_STRING: - if (version_compare(zend_version(), '2.0', '<')) { - if (in_array(strtolower($data), - array('public', 'private', 'protected', 'abstract', - 'interface', 'implements', 'throw') - )) { - $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_PHP5, - array($file)); - } - } - if ($look_for == T_CLASS) { - $current_class = $data; - $current_class_level = $brace_level; - $declared_classes[] = $current_class; - } elseif ($look_for == T_INTERFACE) { - $current_interface = $data; - $current_class_level = $brace_level; - $declared_interfaces[] = $current_interface; - } elseif ($look_for == T_IMPLEMENTS) { - $implements[$current_class] = $data; - } elseif ($look_for == T_EXTENDS) { - $extends[$current_class] = $data; - } elseif ($look_for == T_FUNCTION) { - if ($current_class) { - $current_function = "$current_class::$data"; - $declared_methods[$current_class][] = $data; - } elseif ($current_interface) { - $current_function = "$current_interface::$data"; - $declared_methods[$current_interface][] = $data; - } else { - $current_function = $data; - $declared_functions[] = $current_function; - } - $current_function_level = $brace_level; - $m = array(); - } elseif ($look_for == T_NEW) { - $used_classes[$data] = true; - } - $look_for = 0; - continue 2; - case T_VARIABLE: - $look_for = 0; - continue 2; - case T_DOC_COMMENT: - case T_COMMENT: - if (preg_match('!^/\*\*\s!', $data)) { - $lastphpdoc = $data; - if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m)) { - $nodeps = array_merge($nodeps, $m[1]); - } - } - continue 2; - case T_DOUBLE_COLON: - if (!($tokens[$i - 1][0] == T_WHITESPACE || $tokens[$i - 1][0] == T_STRING)) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE, - array('file' => $file)); - return false; - } - $class = $tokens[$i - 1][1]; - if (strtolower($class) != 'parent') { - $used_classes[$class] = true; - } - continue 2; - } - } - return array( - "source_file" => $file, - "declared_classes" => $declared_classes, - "declared_interfaces" => $declared_interfaces, - "declared_methods" => $declared_methods, - "declared_functions" => $declared_functions, - "used_classes" => array_diff(array_keys($used_classes), $nodeps), - "inheritance" => $extends, - "implements" => $implements, - ); - } - - /** - * Build a "provides" array from data returned by - * analyzeSourceCode(). The format of the built array is like - * this: - * - * array( - * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'), - * ... - * ) - * - * - * @param array $srcinfo array with information about a source file - * as returned by the analyzeSourceCode() method. - * - * @return void - * - * @access private - * - */ - function _buildProvidesArray($srcinfo) - { - if (!$this->_isValid) { - return false; - } - $file = basename($srcinfo['source_file']); - $pn = $this->getPackage(); - $pnl = strlen($pn); - foreach ($srcinfo['declared_classes'] as $class) { - $key = "class;$class"; - if (isset($this->_packageInfo['provides'][$key])) { - continue; - } - $this->_packageInfo['provides'][$key] = - array('file'=> $file, 'type' => 'class', 'name' => $class); - if (isset($srcinfo['inheritance'][$class])) { - $this->_packageInfo['provides'][$key]['extends'] = - $srcinfo['inheritance'][$class]; - } - } - foreach ($srcinfo['declared_methods'] as $class => $methods) { - foreach ($methods as $method) { - $function = "$class::$method"; - $key = "function;$function"; - if ($method{0} == '_' || !strcasecmp($method, $class) || - isset($this->_packageInfo['provides'][$key])) { - continue; - } - $this->_packageInfo['provides'][$key] = - array('file'=> $file, 'type' => 'function', 'name' => $function); - } - } - - foreach ($srcinfo['declared_functions'] as $function) { - $key = "function;$function"; - if ($function{0} == '_' || isset($this->_packageInfo['provides'][$key])) { - continue; - } - if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) { - $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\""; - } - $this->_packageInfo['provides'][$key] = - array('file'=> $file, 'type' => 'function', 'name' => $function); - } - } - - // }}} -} -?> -PEAR-1.8.0/PEAR/PackageFile/v2.php100664 764 764 207602 100664 11276 * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: v2.php,v 1.145 2009/02/24 23:39:16 dufuz Exp $ + * @version CVS: $Id: v1.php 276383 2009-02-24 23:39:37Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since Release 1.4.0a1 */ @@ -27698,96 +26593,317 @@ * For error handling */ require_once 'PEAR/ErrorStack.php'; + +/** + * Error code if parsing is attempted with no xml extension + */ +define('PEAR_PACKAGEFILE_ERROR_NO_XML_EXT', 3); + +/** + * Error code if creating the xml parser resource fails + */ +define('PEAR_PACKAGEFILE_ERROR_CANT_MAKE_PARSER', 4); + +/** + * Error code used for all sax xml parsing errors + */ +define('PEAR_PACKAGEFILE_ERROR_PARSER_ERROR', 5); + +/** + * Error code used when there is no name + */ +define('PEAR_PACKAGEFILE_ERROR_NO_NAME', 6); + +/** + * Error code when a package name is not valid + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_NAME', 7); + +/** + * Error code used when no summary is parsed + */ +define('PEAR_PACKAGEFILE_ERROR_NO_SUMMARY', 8); + +/** + * Error code for summaries that are more than 1 line + */ +define('PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY', 9); + +/** + * Error code used when no description is present + */ +define('PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION', 10); + +/** + * Error code used when no license is present + */ +define('PEAR_PACKAGEFILE_ERROR_NO_LICENSE', 11); + +/** + * Error code used when a version number is not present + */ +define('PEAR_PACKAGEFILE_ERROR_NO_VERSION', 12); + +/** + * Error code used when a version number is invalid + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_VERSION', 13); + +/** + * Error code when release state is missing + */ +define('PEAR_PACKAGEFILE_ERROR_NO_STATE', 14); + +/** + * Error code when release state is invalid + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_STATE', 15); + +/** + * Error code when release state is missing + */ +define('PEAR_PACKAGEFILE_ERROR_NO_DATE', 16); + +/** + * Error code when release state is invalid + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_DATE', 17); + +/** + * Error code when no release notes are found + */ +define('PEAR_PACKAGEFILE_ERROR_NO_NOTES', 18); + +/** + * Error code when no maintainers are found + */ +define('PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS', 19); + +/** + * Error code when a maintainer has no handle + */ +define('PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE', 20); + +/** + * Error code when a maintainer has no handle + */ +define('PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE', 21); + +/** + * Error code when a maintainer has no name + */ +define('PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME', 22); + +/** + * Error code when a maintainer has no email + */ +define('PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL', 23); + +/** + * Error code when a maintainer has no handle + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_MAINTROLE', 24); + +/** + * Error code when a dependency is not a PHP dependency, but has no name + */ +define('PEAR_PACKAGEFILE_ERROR_NO_DEPNAME', 25); + +/** + * Error code when a dependency has no type (pkg, php, etc.) + */ +define('PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE', 26); + +/** + * Error code when a dependency has no relation (lt, ge, has, etc.) + */ +define('PEAR_PACKAGEFILE_ERROR_NO_DEPREL', 27); + +/** + * Error code when a dependency is not a 'has' relation, but has no version + */ +define('PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION', 28); + +/** + * Error code when a dependency has an invalid relation + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPREL', 29); + +/** + * Error code when a dependency has an invalid type + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPTYPE', 30); + +/** + * Error code when a dependency has an invalid optional option + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL', 31); + +/** + * Error code when a dependency is a pkg dependency, and has an invalid package name + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPNAME', 32); + +/** + * Error code when a dependency has a channel="foo" attribute, and foo is not a registered channel + */ +define('PEAR_PACKAGEFILE_ERROR_UNKNOWN_DEPCHANNEL', 33); + +/** + * Error code when rel="has" and version attribute is present. + */ +define('PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED', 34); + +/** + * Error code when type="php" and dependency name is present + */ +define('PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED', 35); + +/** + * Error code when a configure option has no name + */ +define('PEAR_PACKAGEFILE_ERROR_NO_CONFNAME', 36); + +/** + * Error code when a configure option has no name + */ +define('PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT', 37); + +/** + * Error code when a file in the filelist has an invalid role + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE', 38); + +/** + * Error code when a file in the filelist has no role + */ +define('PEAR_PACKAGEFILE_ERROR_NO_FILEROLE', 39); + +/** + * Error code when analyzing a php source file that has parse errors + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE', 40); + +/** + * Error code when analyzing a php source file reveals a source element + * without a package name prefix + */ +define('PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX', 41); + /** + * Error code when an unknown channel is specified + */ +define('PEAR_PACKAGEFILE_ERROR_UNKNOWN_CHANNEL', 42); + +/** + * Error code when no files are found in the filelist + */ +define('PEAR_PACKAGEFILE_ERROR_NO_FILES', 43); + +/** + * Error code when a file is not valid php according to _analyzeSourceCode() + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_FILE', 44); + +/** + * Error code when the channel validator returns an error or warning + */ +define('PEAR_PACKAGEFILE_ERROR_CHANNELVAL', 45); + +/** + * Error code when a php5 package is packaged in php4 (analysis doesn't work) + */ +define('PEAR_PACKAGEFILE_ERROR_PHP5', 46); + +/** + * Error code when a file is listed in package.xml but does not exist + */ +define('PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND', 47); + +/** + * Error code when a * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 1.4.0a1 */ -class PEAR_PackageFile_v2 +class PEAR_PackageFile_v1 { + /** + * @access private + * @var PEAR_ErrorStack + * @access private + */ + var $_stack; /** - * Parsed package information - * @var array + * A registry object, used to access the package name validation regex for non-standard channels + * @var PEAR_Registry * @access private */ - var $_packageInfo = array(); + var $_registry; /** - * path to package .tgz or false if this is a local/extracted package.xml - * @var string|false + * An object that contains a log method that matches PEAR_Common::log's signature + * @var object * @access private */ - var $_archiveFile; + var $_logger; /** - * path to package .xml or false if this is an abstract parsed-from-string xml - * @var string|false + * Parsed package information + * @var array * @access private */ - var $_packageFile; + var $_packageInfo; /** - * This is used by file analysis routines to log progress information - * @var PEAR_Common - * @access protected + * path to package.xml + * @var string + * @access private */ - var $_logger; + var $_packageFile; /** - * This is set to the highest validation level that has been validated - * - * If the package.xml is invalid or unknown, this is set to 0. If - * normal validation has occurred, this is set to PEAR_VALIDATE_NORMAL. If - * downloading/installation validation has occurred it is set to PEAR_VALIDATE_DOWNLOADING - * or INSTALLING, and so on up to PEAR_VALIDATE_PACKAGING. This allows validation - * "caching" to occur, which is particularly important for package validation, so - * that PHP files are not validated twice - * @var int - * @access private - */ - var $_isValid = 0; - - /** - * True if the filelist has been validated - * @param bool - */ - var $_filesValid = false; - - /** - * @var PEAR_Registry - * @access protected - */ - var $_registry; - - /** - * @var PEAR_Config - * @access protected - */ - var $_config; - - /** - * Optional Dependency group requested for installation + * path to package .tgz or false if this is a local/extracted package.xml * @var string * @access private */ - var $_requestedGroup = false; - - /** - * @var PEAR_ErrorStack - * @access protected - */ - var $_stack; + var $_archiveFile; /** - * Namespace prefix used for tasks in this package.xml - use tasks: whenever possible + * @var int + * @access private */ - var $_tasksNs; + var $_isValid = 0; /** * Determines whether this packagefile was initialized only with partial package info @@ -27796,5335 +26912,3328 @@ * * - package name * - channel name - * - dependencies + * - dependencies * @var boolean * @access private */ var $_incomplete = true; /** - * @var PEAR_PackageFile_v2_Validator + * @param bool determines whether to return a PEAR_Error object, or use the PEAR_ErrorStack + * @param string Name of Error Stack class to use. */ - var $_v2Validator; + function PEAR_PackageFile_v1() + { + $this->_stack = &new PEAR_ErrorStack('PEAR_PackageFile_v1'); + $this->_stack->setErrorMessageTemplate($this->_getErrorMessage()); + $this->_isValid = 0; + } - /** - * The constructor merely sets up the private error stack - */ - function PEAR_PackageFile_v2() + function installBinary($installer) { - $this->_stack = new PEAR_ErrorStack('PEAR_PackageFile_v2', false, null); - $this->_isValid = false; + return false; } - /** - * To make unit-testing easier - * @param PEAR_Frontend_* - * @param array options - * @param PEAR_Config - * @return PEAR_Downloader - * @access protected - */ - function &getPEARDownloader(&$i, $o, &$c) + function isExtension($name) { - $z = &new PEAR_Downloader($i, $o, $c); - return $z; + return false; } - /** - * To make unit-testing easier - * @param PEAR_Config - * @param array options - * @param array package name as returned from {@link PEAR_Registry::parsePackageName()} - * @param int PEAR_VALIDATE_* constant - * @return PEAR_Dependency2 - * @access protected - */ - function &getPEARDependency2(&$c, $o, $p, $s = PEAR_VALIDATE_INSTALLING) + function setConfig(&$config) { - if (!class_exists('PEAR_Dependency2')) { - require_once 'PEAR/Dependency2.php'; - } - $z = &new PEAR_Dependency2($c, $o, $p, $s); - return $z; + $this->_config = &$config; + $this->_registry = &$config->getRegistry(); } - function getInstalledBinary() + function setRequestedGroup() { - return isset($this->_packageInfo['#binarypackage']) ? $this->_packageInfo['#binarypackage'] : - false; + // placeholder } /** - * Installation of source package has failed, attempt to download and install the - * binary version of this package. - * @param PEAR_Installer - * @return array|false + * For saving in the registry. + * + * Set the last version that was installed + * @param string */ - function installBinary(&$installer) + function setLastInstalledVersion($version) { - if (!OS_WINDOWS) { - $a = false; - return $a; - } - if ($this->getPackageType() == 'extsrc' || $this->getPackageType() == 'zendextsrc') { - $releasetype = $this->getPackageType() . 'release'; - if (!is_array($installer->getInstallPackages())) { - $a = false; - return $a; - } - foreach ($installer->getInstallPackages() as $p) { - if ($p->isExtension($this->_packageInfo['providesextension'])) { - if ($p->getPackageType() != 'extsrc' && $p->getPackageType() != 'zendextsrc') { - $a = false; - return $a; // the user probably downloaded it separately - } - } - } - if (isset($this->_packageInfo[$releasetype]['binarypackage'])) { - $installer->log(0, 'Attempting to download binary version of extension "' . - $this->_packageInfo['providesextension'] . '"'); - $params = $this->_packageInfo[$releasetype]['binarypackage']; - if (!is_array($params) || !isset($params[0])) { - $params = array($params); - } - if (isset($this->_packageInfo['channel'])) { - foreach ($params as $i => $param) { - $params[$i] = array('channel' => $this->_packageInfo['channel'], - 'package' => $param, 'version' => $this->getVersion()); - } - } - $dl = &$this->getPEARDownloader($installer->ui, $installer->getOptions(), - $installer->config); - $verbose = $dl->config->get('verbose'); - $dl->config->set('verbose', -1); - foreach ($params as $param) { - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $ret = $dl->download(array($param)); - PEAR::popErrorHandling(); - if (is_array($ret) && count($ret)) { - break; - } - } - $dl->config->set('verbose', $verbose); - if (is_array($ret)) { - if (count($ret) == 1) { - $pf = $ret[0]->getPackageFile(); - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $err = $installer->install($ret[0]); - PEAR::popErrorHandling(); - if (is_array($err)) { - $this->_packageInfo['#binarypackage'] = $ret[0]->getPackage(); - // "install" self, so all dependencies will work transparently - $this->_registry->addPackage2($this); - $installer->log(0, 'Download and install of binary extension "' . - $this->_registry->parsedPackageNameToString( - array('channel' => $pf->getChannel(), - 'package' => $pf->getPackage()), true) . '" successful'); - $a = array($ret[0], $err); - return $a; - } - $installer->log(0, 'Download and install of binary extension "' . - $this->_registry->parsedPackageNameToString( - array('channel' => $pf->getChannel(), - 'package' => $pf->getPackage()), true) . '" failed'); - } - } - } - } - $a = false; - return $a; + $this->_packageInfo['_lastversion'] = $version; } /** - * @return string|false Extension name + * @return string|false */ - function getProvidesExtension() + function getLastInstalledVersion() { - if (in_array($this->getPackageType(), - array('extsrc', 'extbin', 'zendextsrc', 'zendextbin'))) { - if (isset($this->_packageInfo['providesextension'])) { - return $this->_packageInfo['providesextension']; - } + if (isset($this->_packageInfo['_lastversion'])) { + return $this->_packageInfo['_lastversion']; } return false; } - /** - * @param string Extension name - * @return bool - */ - function isExtension($extension) + function getInstalledBinary() { - if (in_array($this->getPackageType(), - array('extsrc', 'extbin', 'zendextsrc', 'zendextbin'))) { - return $this->_packageInfo['providesextension'] == $extension; - } return false; } - /** - * Tests whether every part of the package.xml 1.0 is represented in - * this package.xml 2.0 - * @param PEAR_PackageFile_v1 - * @return bool - */ - function isEquivalent($pf1) + function listPostinstallScripts() { - if (!$pf1) { - return true; - } - if ($this->getPackageType() == 'bundle') { - return false; - } - $this->_stack->getErrors(true); - if (!$pf1->validate(PEAR_VALIDATE_NORMAL)) { - return false; - } - $pass = true; - if ($pf1->getPackage() != $this->getPackage()) { - $this->_differentPackage($pf1->getPackage()); - $pass = false; - } - if ($pf1->getVersion() != $this->getVersion()) { - $this->_differentVersion($pf1->getVersion()); - $pass = false; - } - if (trim($pf1->getSummary()) != $this->getSummary()) { - $this->_differentSummary($pf1->getSummary()); - $pass = false; - } - if (preg_replace('/\s+/', '', $pf1->getDescription()) != - preg_replace('/\s+/', '', $this->getDescription())) { - $this->_differentDescription($pf1->getDescription()); - $pass = false; - } - if ($pf1->getState() != $this->getState()) { - $this->_differentState($pf1->getState()); - $pass = false; - } - if (!strstr(preg_replace('/\s+/', '', $this->getNotes()), - preg_replace('/\s+/', '', $pf1->getNotes()))) { - $this->_differentNotes($pf1->getNotes()); - $pass = false; - } - $mymaintainers = $this->getMaintainers(); - $yourmaintainers = $pf1->getMaintainers(); - for ($i1 = 0; $i1 < count($yourmaintainers); $i1++) { - $reset = false; - for ($i2 = 0; $i2 < count($mymaintainers); $i2++) { - if ($mymaintainers[$i2]['handle'] == $yourmaintainers[$i1]['handle']) { - if ($mymaintainers[$i2]['role'] != $yourmaintainers[$i1]['role']) { - $this->_differentRole($mymaintainers[$i2]['handle'], - $yourmaintainers[$i1]['role'], $mymaintainers[$i2]['role']); - $pass = false; - } - if ($mymaintainers[$i2]['email'] != $yourmaintainers[$i1]['email']) { - $this->_differentEmail($mymaintainers[$i2]['handle'], - $yourmaintainers[$i1]['email'], $mymaintainers[$i2]['email']); - $pass = false; - } - if ($mymaintainers[$i2]['name'] != $yourmaintainers[$i1]['name']) { - $this->_differentName($mymaintainers[$i2]['handle'], - $yourmaintainers[$i1]['name'], $mymaintainers[$i2]['name']); - $pass = false; - } - unset($mymaintainers[$i2]); - $mymaintainers = array_values($mymaintainers); - unset($yourmaintainers[$i1]); - $yourmaintainers = array_values($yourmaintainers); - $reset = true; - break; - } - } - if ($reset) { - $i1 = -1; - } - } - $this->_unmatchedMaintainers($mymaintainers, $yourmaintainers); - $filelist = $this->getFilelist(); - foreach ($pf1->getFilelist() as $file => $atts) { - if (!isset($filelist[$file])) { - $this->_missingFile($file); - $pass = false; - } - } - return $pass; + return false; } - function _differentPackage($package) + function initPostinstallScripts() { - $this->_stack->push(__FUNCTION__, 'error', array('package' => $package, - 'self' => $this->getPackage()), - 'package.xml 1.0 package "%package%" does not match "%self%"'); + return false; } - function _differentVersion($version) + function setLogger(&$logger) { - $this->_stack->push(__FUNCTION__, 'error', array('version' => $version, - 'self' => $this->getVersion()), - 'package.xml 1.0 version "%version%" does not match "%self%"'); + if ($logger && (!is_object($logger) || !method_exists($logger, 'log'))) { + return PEAR::raiseError('Logger must be compatible with PEAR_Common::log'); + } + $this->_logger = &$logger; } - function _differentState($state) + function setPackagefile($file, $archive = false) { - $this->_stack->push(__FUNCTION__, 'error', array('state' => $state, - 'self' => $this->getState()), - 'package.xml 1.0 state "%state%" does not match "%self%"'); + $this->_packageFile = $file; + $this->_archiveFile = $archive ? $archive : $file; } - function _differentRole($handle, $role, $selfrole) + function getPackageFile() { - $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle, - 'role' => $role, 'self' => $selfrole), - 'package.xml 1.0 maintainer "%handle%" role "%role%" does not match "%self%"'); + return isset($this->_packageFile) ? $this->_packageFile : false; } - function _differentEmail($handle, $email, $selfemail) + function getPackageType() { - $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle, - 'email' => $email, 'self' => $selfemail), - 'package.xml 1.0 maintainer "%handle%" email "%email%" does not match "%self%"'); + return 'php'; } - function _differentName($handle, $name, $selfname) + function getArchiveFile() { - $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle, - 'name' => $name, 'self' => $selfname), - 'package.xml 1.0 maintainer "%handle%" name "%name%" does not match "%self%"'); + return $this->_archiveFile; } - function _unmatchedMaintainers($my, $yours) + function packageInfo($field) { - if ($my) { - array_walk($my, create_function('&$i, $k', '$i = $i["handle"];')); - $this->_stack->push(__FUNCTION__, 'error', array('handles' => $my), - 'package.xml 2.0 has unmatched extra maintainers "%handles%"'); + if (!is_string($field) || empty($field) || + !isset($this->_packageInfo[$field])) { + return false; } - if ($yours) { - array_walk($yours, create_function('&$i, $k', '$i = $i["handle"];')); - $this->_stack->push(__FUNCTION__, 'error', array('handles' => $yours), - 'package.xml 1.0 has unmatched extra maintainers "%handles%"'); + return $this->_packageInfo[$field]; + } + + function setDirtree($path) + { + if (!isset($this->_packageInfo['dirtree'])) { + $this->_packageInfo['dirtree'] = array(); } + $this->_packageInfo['dirtree'][$path] = true; } - function _differentNotes($notes) + function getDirtree() { - $truncnotes = strlen($notes) < 25 ? $notes : substr($notes, 0, 24) . '...'; - $truncmynotes = strlen($this->getNotes()) < 25 ? $this->getNotes() : - substr($this->getNotes(), 0, 24) . '...'; - $this->_stack->push(__FUNCTION__, 'error', array('notes' => $truncnotes, - 'self' => $truncmynotes), - 'package.xml 1.0 release notes "%notes%" do not match "%self%"'); + if (isset($this->_packageInfo['dirtree']) && count($this->_packageInfo['dirtree'])) { + return $this->_packageInfo['dirtree']; + } + return false; } - function _differentSummary($summary) + function resetDirtree() { - $truncsummary = strlen($summary) < 25 ? $summary : substr($summary, 0, 24) . '...'; - $truncmysummary = strlen($this->getsummary()) < 25 ? $this->getSummary() : - substr($this->getsummary(), 0, 24) . '...'; - $this->_stack->push(__FUNCTION__, 'error', array('summary' => $truncsummary, - 'self' => $truncmysummary), - 'package.xml 1.0 summary "%summary%" does not match "%self%"'); + unset($this->_packageInfo['dirtree']); } - function _differentDescription($description) + function fromArray($pinfo) { - $truncdescription = trim(strlen($description) < 25 ? $description : substr($description, 0, 24) . '...'); - $truncmydescription = trim(strlen($this->getDescription()) < 25 ? $this->getDescription() : - substr($this->getdescription(), 0, 24) . '...'); - $this->_stack->push(__FUNCTION__, 'error', array('description' => $truncdescription, - 'self' => $truncmydescription), - 'package.xml 1.0 description "%description%" does not match "%self%"'); + $this->_incomplete = false; + $this->_packageInfo = $pinfo; } - function _missingFile($file) + function isIncomplete() { - $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), - 'package.xml 1.0 file "%file%" is not present in '); + return $this->_incomplete; } - /** - * WARNING - do not use this function unless you know what you're doing - */ - function setRawState($state) + function getChannel() { - if (!isset($this->_packageInfo['stability'])) { - $this->_packageInfo['stability'] = array(); + return 'pear.php.net'; + } + + function getUri() + { + return false; + } + + function getTime() + { + return false; + } + + function getExtends() + { + if (isset($this->_packageInfo['extends'])) { + return $this->_packageInfo['extends']; } - $this->_packageInfo['stability']['release'] = $state; + return false; } /** - * WARNING - do not use this function unless you know what you're doing + * @return array */ - function setRawCompatible($compatible) + function toArray() { - $this->_packageInfo['compatible'] = $compatible; + if (!$this->validate(PEAR_VALIDATE_NORMAL)) { + return false; + } + return $this->getArray(); } - /** - * WARNING - do not use this function unless you know what you're doing - */ - function setRawPackage($package) + function getArray() { - $this->_packageInfo['name'] = $package; + return $this->_packageInfo; + } + + function getName() + { + return $this->getPackage(); + } + + function getPackage() + { + if (isset($this->_packageInfo['package'])) { + return $this->_packageInfo['package']; + } + return false; } /** - * WARNING - do not use this function unless you know what you're doing + * WARNING - don't use this unless you know what you are doing */ - function setRawChannel($channel) + function setRawPackage($package) { - $this->_packageInfo['channel'] = $channel; + $this->_packageInfo['package'] = $package; } - function setRequestedGroup($group) + function setPackage($package) { - $this->_requestedGroup = $group; + $this->_packageInfo['package'] = $package; + $this->_isValid = false; } - function getRequestedGroup() + function getVersion() { - if (isset($this->_requestedGroup)) { - return $this->_requestedGroup; + if (isset($this->_packageInfo['version'])) { + return $this->_packageInfo['version']; } return false; } - /** - * For saving in the registry. - * - * Set the last version that was installed - * @param string - */ - function setLastInstalledVersion($version) + function setVersion($version) { - $this->_packageInfo['_lastversion'] = $version; + $this->_packageInfo['version'] = $version; + $this->_isValid = false; } - /** - * @return string|false - */ - function getLastInstalledVersion() + function clearMaintainers() { - if (isset($this->_packageInfo['_lastversion'])) { - return $this->_packageInfo['_lastversion']; + unset($this->_packageInfo['maintainers']); + } + + function getMaintainers() + { + if (isset($this->_packageInfo['maintainers'])) { + return $this->_packageInfo['maintainers']; } return false; } /** - * Determines whether this package.xml has post-install scripts or not - * @return array|false + * Adds a new maintainer - no checking of duplicates is performed, use + * updatemaintainer for that purpose. */ - function listPostinstallScripts() + function addMaintainer($role, $handle, $name, $email) { - $filelist = $this->getFilelist(); - $contents = $this->getContents(); - $contents = $contents['dir']['file']; - if (!is_array($contents) || !isset($contents[0])) { - $contents = array($contents); - } - $taskfiles = array(); - foreach ($contents as $file) { - $atts = $file['attribs']; - unset($file['attribs']); - if (count($file)) { - $taskfiles[$atts['name']] = $file; + $this->_packageInfo['maintainers'][] = + array('handle' => $handle, 'role' => $role, 'email' => $email, 'name' => $name); + $this->_isValid = false; + } + + function updateMaintainer($role, $handle, $name, $email) + { + $found = false; + if (!isset($this->_packageInfo['maintainers']) || + !is_array($this->_packageInfo['maintainers'])) { + return $this->addMaintainer($role, $handle, $name, $email); + } + foreach ($this->_packageInfo['maintainers'] as $i => $maintainer) { + if ($maintainer['handle'] == $handle) { + $found = $i; + break; } } - $common = new PEAR_Common; - $common->debug = $this->_config->get('verbose'); - $this->_scripts = array(); - $ret = array(); - foreach ($taskfiles as $name => $tasks) { - if (!isset($filelist[$name])) { - // ignored files will not be in the filelist - continue; - } - $atts = $filelist[$name]; - foreach ($tasks as $tag => $raw) { - $task = $this->getTask($tag); - $task = &new $task($this->_config, $common, PEAR_TASK_INSTALL); - if ($task->isScript()) { - $ret[] = $filelist[$name]['installed_as']; - } + if ($found !== false) { + unset($this->_packageInfo['maintainers'][$found]); + $this->_packageInfo['maintainers'] = + array_values($this->_packageInfo['maintainers']); + } + $this->addMaintainer($role, $handle, $name, $email); + } + + function deleteMaintainer($handle) + { + $found = false; + foreach ($this->_packageInfo['maintainers'] as $i => $maintainer) { + if ($maintainer['handle'] == $handle) { + $found = $i; + break; } } - if (count($ret)) { - return $ret; + if ($found !== false) { + unset($this->_packageInfo['maintainers'][$found]); + $this->_packageInfo['maintainers'] = + array_values($this->_packageInfo['maintainers']); + return true; } return false; } - /** - * Initialize post-install scripts for running - * - * This method can be used to detect post-install scripts, as the return value - * indicates whether any exist - * @return bool - */ - function initPostinstallScripts() + function getState() { - $filelist = $this->getFilelist(); - $contents = $this->getContents(); - $contents = $contents['dir']['file']; - if (!is_array($contents) || !isset($contents[0])) { - $contents = array($contents); - } - $taskfiles = array(); - foreach ($contents as $file) { - $atts = $file['attribs']; - unset($file['attribs']); - if (count($file)) { - $taskfiles[$atts['name']] = $file; - } - } - $common = new PEAR_Common; - $common->debug = $this->_config->get('verbose'); - $this->_scripts = array(); - foreach ($taskfiles as $name => $tasks) { - if (!isset($filelist[$name])) { - // file was not installed due to installconditions - continue; - } - $atts = $filelist[$name]; - foreach ($tasks as $tag => $raw) { - $taskname = $this->getTask($tag); - $task = &new $taskname($this->_config, $common, PEAR_TASK_INSTALL); - if (!$task->isScript()) { - continue; // scripts are only handled after installation - } - $lastversion = isset($this->_packageInfo['_lastversion']) ? - $this->_packageInfo['_lastversion'] : null; - $task->init($raw, $atts, $lastversion); - $res = $task->startSession($this, $atts['installed_as']); - if (!$res) { - continue; // skip this file - } - if (PEAR::isError($res)) { - return $res; - } - $assign = &$task; - $this->_scripts[] = &$assign; - } - } - if (count($this->_scripts)) { - return true; + if (isset($this->_packageInfo['release_state'])) { + return $this->_packageInfo['release_state']; } return false; } - function runPostinstallScripts() + function setRawState($state) { - if ($this->initPostinstallScripts()) { - $ui = &PEAR_Frontend::singleton(); - if ($ui) { - $ui->runPostinstallScripts($this->_scripts, $this); - } - } + $this->_packageInfo['release_state'] = $state; } - - /** - * Convert a recursive set of and tags into a single tag with - * tags. - */ - function flattenFilelist() + function setState($state) { - if (isset($this->_packageInfo['bundle'])) { - return; - } - $filelist = array(); - if (isset($this->_packageInfo['contents']['dir']['dir'])) { - $this->_getFlattenedFilelist($filelist, $this->_packageInfo['contents']['dir']); - if (!isset($filelist[1])) { - $filelist = $filelist[0]; - } - $this->_packageInfo['contents']['dir']['file'] = $filelist; - unset($this->_packageInfo['contents']['dir']['dir']); - } else { - // else already flattened but check for baseinstalldir propagation - if (isset($this->_packageInfo['contents']['dir']['attribs']['baseinstalldir'])) { - if (isset($this->_packageInfo['contents']['dir']['file'][0])) { - foreach ($this->_packageInfo['contents']['dir']['file'] as $i => $file) { - if (isset($file['attribs']['baseinstalldir'])) { - continue; - } - $this->_packageInfo['contents']['dir']['file'][$i]['attribs']['baseinstalldir'] - = $this->_packageInfo['contents']['dir']['attribs']['baseinstalldir']; - } - } else { - if (!isset($this->_packageInfo['contents']['dir']['file']['attribs']['baseinstalldir'])) { - $this->_packageInfo['contents']['dir']['file']['attribs']['baseinstalldir'] - = $this->_packageInfo['contents']['dir']['attribs']['baseinstalldir']; - } - } - } - } + $this->_packageInfo['release_state'] = $state; + $this->_isValid = false; } - /** - * @param array the final flattened file list - * @param array the current directory being processed - * @param string|false any recursively inherited baeinstalldir attribute - * @param string private recursion variable - * @return array - * @access protected - */ - function _getFlattenedFilelist(&$files, $dir, $baseinstall = false, $path = '') + function getDate() { - if (isset($dir['attribs']) && isset($dir['attribs']['baseinstalldir'])) { - $baseinstall = $dir['attribs']['baseinstalldir']; - } - if (isset($dir['dir'])) { - if (!isset($dir['dir'][0])) { - $dir['dir'] = array($dir['dir']); - } - foreach ($dir['dir'] as $subdir) { - if (!isset($subdir['attribs']) || !isset($subdir['attribs']['name'])) { - $name = '*unknown*'; - } else { - $name = $subdir['attribs']['name']; - } - $newpath = empty($path) ? $name : - $path . '/' . $name; - $this->_getFlattenedFilelist($files, $subdir, - $baseinstall, $newpath); - } - } - if (isset($dir['file'])) { - if (!isset($dir['file'][0])) { - $dir['file'] = array($dir['file']); - } - foreach ($dir['file'] as $file) { - $attrs = $file['attribs']; - $name = $attrs['name']; - if ($baseinstall && !isset($attrs['baseinstalldir'])) { - $attrs['baseinstalldir'] = $baseinstall; - } - $attrs['name'] = empty($path) ? $name : $path . '/' . $name; - $attrs['name'] = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), - $attrs['name']); - $file['attribs'] = $attrs; - $files[] = $file; - } + if (isset($this->_packageInfo['release_date'])) { + return $this->_packageInfo['release_date']; } + return false; } - function setConfig(&$config) + function setDate($date) { - $this->_config = &$config; - $this->_registry = &$config->getRegistry(); + $this->_packageInfo['release_date'] = $date; + $this->_isValid = false; } - function setLogger(&$logger) + function getLicense() { - if (!is_object($logger) || !method_exists($logger, 'log')) { - return PEAR::raiseError('Logger must be compatible with PEAR_Common::log'); + if (isset($this->_packageInfo['release_license'])) { + return $this->_packageInfo['release_license']; } - $this->_logger = &$logger; + return false; } - /** - * WARNING - do not use this function directly unless you know what you're doing - */ - function setDeps($deps) + function setLicense($date) { - $this->_packageInfo['dependencies'] = $deps; + $this->_packageInfo['release_license'] = $date; + $this->_isValid = false; } - /** - * WARNING - do not use this function directly unless you know what you're doing - */ - function setCompatible($compat) + function getSummary() { - $this->_packageInfo['compatible'] = $compat; + if (isset($this->_packageInfo['summary'])) { + return $this->_packageInfo['summary']; + } + return false; } - function setPackagefile($file, $archive = false) + function setSummary($summary) { - $this->_packageFile = $file; - $this->_archiveFile = $archive ? $archive : $file; + $this->_packageInfo['summary'] = $summary; + $this->_isValid = false; } - /** - * Wrapper to {@link PEAR_ErrorStack::getErrors()} - * @param boolean determines whether to purge the error stack after retrieving - * @return array - */ - function getValidationWarnings($purge = true) + function getDescription() { - return $this->_stack->getErrors($purge); + if (isset($this->_packageInfo['description'])) { + return $this->_packageInfo['description']; + } + return false; } - function getPackageFile() + function setDescription($desc) { - return $this->_packageFile; + $this->_packageInfo['description'] = $desc; + $this->_isValid = false; } - function getArchiveFile() + function getNotes() { - return $this->_archiveFile; + if (isset($this->_packageInfo['release_notes'])) { + return $this->_packageInfo['release_notes']; + } + return false; } - - /** - * Directly set the array that defines this packagefile - * - * WARNING: no validation. This should only be performed by internal methods - * inside PEAR or by inputting an array saved from an existing PEAR_PackageFile_v2 - * @param array - */ - function fromArray($pinfo) + function setNotes($notes) { - unset($pinfo['old']); - unset($pinfo['xsdversion']); - $this->_incomplete = false; - $this->_packageInfo = $pinfo; + $this->_packageInfo['release_notes'] = $notes; + $this->_isValid = false; } - function isIncomplete() + function getDeps() { - return $this->_incomplete; + if (isset($this->_packageInfo['release_deps'])) { + return $this->_packageInfo['release_deps']; + } + return false; } /** - * @return array + * Reset dependencies prior to adding new ones */ - function toArray($forreg = false) + function clearDeps() { - if (!$this->validate(PEAR_VALIDATE_NORMAL)) { - return false; - } - return $this->getArray($forreg); + unset($this->_packageInfo['release_deps']); } - function getArray($forReg = false) + function addPhpDep($version, $rel) { - if ($forReg) { - $arr = $this->_packageInfo; - $arr['old'] = array(); - $arr['old']['version'] = $this->getVersion(); - $arr['old']['release_date'] = $this->getDate(); - $arr['old']['release_state'] = $this->getState(); - $arr['old']['release_license'] = $this->getLicense(); - $arr['old']['release_notes'] = $this->getNotes(); - $arr['old']['release_deps'] = $this->getDeps(); - $arr['old']['maintainers'] = $this->getMaintainers(); - $arr['xsdversion'] = '2.0'; - return $arr; - } else { - $info = $this->_packageInfo; - unset($info['dirtree']); - if (isset($info['_lastversion'])) { - unset($info['_lastversion']); - } - if (isset($info['#binarypackage'])) { - unset($info['#binarypackage']); - } - return $info; - } + $this->_isValid = false; + $this->_packageInfo['release_deps'][] = + array('type' => 'php', + 'rel' => $rel, + 'version' => $version); } - function packageInfo($field) + function addPackageDep($name, $version, $rel, $optional = 'no') { - $arr = $this->getArray(true); - if ($field == 'state') { - return $arr['stability']['release']; - } - if ($field == 'api-version') { - return $arr['version']['api']; - } - if ($field == 'api-state') { - return $arr['stability']['api']; - } - if (isset($arr['old'][$field])) { - if (!is_string($arr['old'][$field])) { - return null; - } - return $arr['old'][$field]; - } - if (isset($arr[$field])) { - if (!is_string($arr[$field])) { - return null; - } - return $arr[$field]; + $this->_isValid = false; + $dep = + array('type' => 'pkg', + 'name' => $name, + 'rel' => $rel, + 'optional' => $optional); + if ($rel != 'has' && $rel != 'not') { + $dep['version'] = $version; } - return null; + $this->_packageInfo['release_deps'][] = $dep; } - function getName() + function addExtensionDep($name, $version, $rel, $optional = 'no') { - return $this->getPackage(); + $this->_isValid = false; + $this->_packageInfo['release_deps'][] = + array('type' => 'ext', + 'name' => $name, + 'rel' => $rel, + 'version' => $version, + 'optional' => $optional); } - function getPackage() + /** + * WARNING - do not use this function directly unless you know what you're doing + */ + function setDeps($deps) { - if (isset($this->_packageInfo['name'])) { - return $this->_packageInfo['name']; - } - return false; + $this->_packageInfo['release_deps'] = $deps; } - function getChannel() + function hasDeps() { - if (isset($this->_packageInfo['uri'])) { - return '__uri'; - } - if (isset($this->_packageInfo['channel'])) { - return strtolower($this->_packageInfo['channel']); - } - return false; + return isset($this->_packageInfo['release_deps']) && + count($this->_packageInfo['release_deps']); } - function getUri() + function getDependencyGroup($group) { - if (isset($this->_packageInfo['uri'])) { - return $this->_packageInfo['uri']; - } return false; } - function getExtends() + function isCompatible($pf) { - if (isset($this->_packageInfo['extends'])) { - return $this->_packageInfo['extends']; - } return false; } - function getSummary() + function isSubpackageOf($p) { - if (isset($this->_packageInfo['summary'])) { - return $this->_packageInfo['summary']; - } - return false; + return $p->isSubpackage($this); } - function getDescription() + function isSubpackage($p) { - if (isset($this->_packageInfo['description'])) { - return $this->_packageInfo['description']; - } return false; } - function getMaintainers($raw = false) + function dependsOn($package, $channel) { - if (!isset($this->_packageInfo['lead'])) { + if (strtolower($channel) != 'pear.php.net') { return false; } - if ($raw) { - $ret = array('lead' => $this->_packageInfo['lead']); - (isset($this->_packageInfo['developer'])) ? - $ret['developer'] = $this->_packageInfo['developer'] :null; - (isset($this->_packageInfo['contributor'])) ? - $ret['contributor'] = $this->_packageInfo['contributor'] :null; - (isset($this->_packageInfo['helper'])) ? - $ret['helper'] = $this->_packageInfo['helper'] :null; - return $ret; - } else { - $ret = array(); - $leads = isset($this->_packageInfo['lead'][0]) ? $this->_packageInfo['lead'] : - array($this->_packageInfo['lead']); - foreach ($leads as $lead) { - $s = $lead; - $s['handle'] = $s['user']; - unset($s['user']); - $s['role'] = 'lead'; - $ret[] = $s; - } - if (isset($this->_packageInfo['developer'])) { - $leads = isset($this->_packageInfo['developer'][0]) ? - $this->_packageInfo['developer'] : - array($this->_packageInfo['developer']); - foreach ($leads as $maintainer) { - $s = $maintainer; - $s['handle'] = $s['user']; - unset($s['user']); - $s['role'] = 'developer'; - $ret[] = $s; - } - } - if (isset($this->_packageInfo['contributor'])) { - $leads = isset($this->_packageInfo['contributor'][0]) ? - $this->_packageInfo['contributor'] : - array($this->_packageInfo['contributor']); - foreach ($leads as $maintainer) { - $s = $maintainer; - $s['handle'] = $s['user']; - unset($s['user']); - $s['role'] = 'contributor'; - $ret[] = $s; - } + if (!($deps = $this->getDeps())) { + return false; + } + foreach ($deps as $dep) { + if ($dep['type'] != 'pkg') { + continue; } - if (isset($this->_packageInfo['helper'])) { - $leads = isset($this->_packageInfo['helper'][0]) ? - $this->_packageInfo['helper'] : - array($this->_packageInfo['helper']); - foreach ($leads as $maintainer) { - $s = $maintainer; - $s['handle'] = $s['user']; - unset($s['user']); - $s['role'] = 'helper'; - $ret[] = $s; - } + if (strtolower($dep['name']) == strtolower($package)) { + return true; } - return $ret; } return false; } - function getLeads() + function getConfigureOptions() { - if (isset($this->_packageInfo['lead'])) { - return $this->_packageInfo['lead']; + if (isset($this->_packageInfo['configure_options'])) { + return $this->_packageInfo['configure_options']; } return false; } - function getDevelopers() + function hasConfigureOptions() { - if (isset($this->_packageInfo['developer'])) { - return $this->_packageInfo['developer']; - } - return false; + return isset($this->_packageInfo['configure_options']) && + count($this->_packageInfo['configure_options']); } - function getContributors() + function addConfigureOption($name, $prompt, $default = false) { - if (isset($this->_packageInfo['contributor'])) { - return $this->_packageInfo['contributor']; + $o = array('name' => $name, 'prompt' => $prompt); + if ($default !== false) { + $o['default'] = $default; } - return false; + if (!isset($this->_packageInfo['configure_options'])) { + $this->_packageInfo['configure_options'] = array(); + } + $this->_packageInfo['configure_options'][] = $o; } - function getHelpers() + function clearConfigureOptions() { - if (isset($this->_packageInfo['helper'])) { - return $this->_packageInfo['helper']; - } - return false; + unset($this->_packageInfo['configure_options']); } - function setDate($date) + function getProvides() { - if (!isset($this->_packageInfo['date'])) { - // ensure that the extends tag is set up in the right location - $this->_packageInfo = $this->_insertBefore($this->_packageInfo, - array('time', 'version', - 'stability', 'license', 'notes', 'contents', 'compatible', - 'dependencies', 'providesextension', 'srcpackage', 'srcuri', - 'phprelease', 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease', - 'zendextbinrelease', 'bundle', 'changelog'), array(), 'date'); + if (isset($this->_packageInfo['provides'])) { + return $this->_packageInfo['provides']; } - $this->_packageInfo['date'] = $date; - $this->_isValid = 0; + return false; } - function setTime($time) + function getProvidesExtension() { - $this->_isValid = 0; - if (!isset($this->_packageInfo['time'])) { - // ensure that the time tag is set up in the right location - $this->_packageInfo = $this->_insertBefore($this->_packageInfo, - array('version', - 'stability', 'license', 'notes', 'contents', 'compatible', - 'dependencies', 'providesextension', 'srcpackage', 'srcuri', - 'phprelease', 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease', - 'zendextbinrelease', 'bundle', 'changelog'), $time, 'time'); - } - $this->_packageInfo['time'] = $time; + return false; } - function getDate() + function addFile($dir, $file, $attrs) { - if (isset($this->_packageInfo['date'])) { - return $this->_packageInfo['date']; + $dir = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), $dir); + if ($dir == '/' || $dir == '') { + $dir = ''; + } else { + $dir .= '/'; } - return false; + $file = $dir . $file; + $file = preg_replace('![\\/]+!', '/', $file); + $this->_packageInfo['filelist'][$file] = $attrs; } - function getTime() + function getInstallationFilelist() { - if (isset($this->_packageInfo['time'])) { - return $this->_packageInfo['time']; - } - return false; + return $this->getFilelist(); } - /** - * @param package|api version category to return - */ - function getVersion($key = 'release') + function getFilelist() { - if (isset($this->_packageInfo['version'][$key])) { - return $this->_packageInfo['version'][$key]; + if (isset($this->_packageInfo['filelist'])) { + return $this->_packageInfo['filelist']; } return false; } - function getStability() + function setFileAttribute($file, $attr, $value) { - if (isset($this->_packageInfo['stability'])) { - return $this->_packageInfo['stability']; - } - return false; + $this->_packageInfo['filelist'][$file][$attr] = $value; } - function getState($key = 'release') + function resetFilelist() { - if (isset($this->_packageInfo['stability'][$key])) { - return $this->_packageInfo['stability'][$key]; - } - return false; + $this->_packageInfo['filelist'] = array(); } - function getLicense($raw = false) + function setInstalledAs($file, $path) { - if (isset($this->_packageInfo['license'])) { - if ($raw) { - return $this->_packageInfo['license']; - } - if (is_array($this->_packageInfo['license'])) { - return $this->_packageInfo['license']['_content']; - } else { - return $this->_packageInfo['license']; - } + if ($path) { + return $this->_packageInfo['filelist'][$file]['installed_as'] = $path; } - return false; + unset($this->_packageInfo['filelist'][$file]['installed_as']); } - function getLicenseLocation() + function installedFile($file, $atts) { - if (!isset($this->_packageInfo['license']) || !is_array($this->_packageInfo['license'])) { - return false; + if (isset($this->_packageInfo['filelist'][$file])) { + $this->_packageInfo['filelist'][$file] = + array_merge($this->_packageInfo['filelist'][$file], $atts); + } else { + $this->_packageInfo['filelist'][$file] = $atts; } - return $this->_packageInfo['license']['attribs']; } - function getNotes() + function getChangelog() { - if (isset($this->_packageInfo['notes'])) { - return $this->_packageInfo['notes']; + if (isset($this->_packageInfo['changelog'])) { + return $this->_packageInfo['changelog']; } return false; } - /** - * Return the tag contents, if any - * @return array|false - */ - function getUsesrole() + function getPackagexmlVersion() { - if (isset($this->_packageInfo['usesrole'])) { - return $this->_packageInfo['usesrole']; - } - return false; + return '1.0'; } /** - * Return the tag contents, if any - * @return array|false + * Wrapper to {@link PEAR_ErrorStack::getErrors()} + * @param boolean determines whether to purge the error stack after retrieving + * @return array */ - function getUsestask() + function getValidationWarnings($purge = true) { - if (isset($this->_packageInfo['usestask'])) { - return $this->_packageInfo['usestask']; - } - return false; + return $this->_stack->getErrors($purge); } + // }}} /** - * This should only be used to retrieve filenames and install attributes + * Validation error. Also marks the object contents as invalid + * @param error code + * @param array error information + * @access private */ - function getFilelist($preserve = false) + function _validateError($code, $params = array()) { - if (isset($this->_packageInfo['filelist']) && !$preserve) { - return $this->_packageInfo['filelist']; - } - $this->flattenFilelist(); - if ($contents = $this->getContents()) { - $ret = array(); - if (!isset($contents['dir'])) { - return false; - } - if (!isset($contents['dir']['file'][0])) { - $contents['dir']['file'] = array($contents['dir']['file']); - } - foreach ($contents['dir']['file'] as $file) { - $name = $file['attribs']['name']; - if (!$preserve) { - $file = $file['attribs']; - } - $ret[$name] = $file; - } - if (!$preserve) { - $this->_packageInfo['filelist'] = $ret; - } - return $ret; - } - return false; + $this->_stack->push($code, 'error', $params, false, false, debug_backtrace()); + $this->_isValid = false; } /** - * Return configure options array, if any - * - * @return array|false + * Validation warning. Does not mark the object contents invalid. + * @param error code + * @param array error information + * @access private */ - function getConfigureOptions() + function _validateWarning($code, $params = array()) { - if ($this->getPackageType() != 'extsrc' && $this->getPackageType() != 'zendextsrc') { - return false; - } - - $releases = $this->getReleases(); - if (isset($releases[0])) { - $releases = $releases[0]; - } - - if (isset($releases['configureoption'])) { - if (!isset($releases['configureoption'][0])) { - $releases['configureoption'] = array($releases['configureoption']); - } - - for ($i = 0; $i < count($releases['configureoption']); $i++) { - $releases['configureoption'][$i] = $releases['configureoption'][$i]['attribs']; - } - - return $releases['configureoption']; - } - - return false; + $this->_stack->push($code, 'warning', $params, false, false, debug_backtrace()); } /** - * This is only used at install-time, after all serialization - * is over. + * @param integer error code + * @access protected */ - function resetFilelist() + function _getErrorMessage() { - $this->_packageInfo['filelist'] = array(); + return array( + PEAR_PACKAGEFILE_ERROR_NO_NAME => + 'Missing Package Name', + PEAR_PACKAGEFILE_ERROR_NO_SUMMARY => + 'No summary found', + PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY => + 'Summary should be on one line', + PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION => + 'Missing description', + PEAR_PACKAGEFILE_ERROR_NO_LICENSE => + 'Missing license', + PEAR_PACKAGEFILE_ERROR_NO_VERSION => + 'No release version found', + PEAR_PACKAGEFILE_ERROR_NO_STATE => + 'No release state found', + PEAR_PACKAGEFILE_ERROR_NO_DATE => + 'No release date found', + PEAR_PACKAGEFILE_ERROR_NO_NOTES => + 'No release notes found', + PEAR_PACKAGEFILE_ERROR_NO_LEAD => + 'Package must have at least one lead maintainer', + PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS => + 'No maintainers found, at least one must be defined', + PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE => + 'Maintainer %index% has no handle (user ID at channel server)', + PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE => + 'Maintainer %index% has no role', + PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME => + 'Maintainer %index% has no name', + PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL => + 'Maintainer %index% has no email', + PEAR_PACKAGEFILE_ERROR_NO_DEPNAME => + 'Dependency %index% is not a php dependency, and has no name', + PEAR_PACKAGEFILE_ERROR_NO_DEPREL => + 'Dependency %index% has no relation (rel)', + PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE => + 'Dependency %index% has no type', + PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED => + 'PHP Dependency %index% has a name attribute of "%name%" which will be' . + ' ignored!', + PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION => + 'Dependency %index% is not a rel="has" or rel="not" dependency, ' . + 'and has no version', + PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION => + 'Dependency %index% is a type="php" dependency, ' . + 'and has no version', + PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED => + 'Dependency %index% is a rel="%rel%" dependency, versioning is ignored', + PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL => + 'Dependency %index% has invalid optional value "%opt%", should be yes or no', + PEAR_PACKAGEFILE_PHP_NO_NOT => + 'Dependency %index%: php dependencies cannot use "not" rel, use "ne"' . + ' to exclude specific versions', + PEAR_PACKAGEFILE_ERROR_NO_CONFNAME => + 'Configure Option %index% has no name', + PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT => + 'Configure Option %index% has no prompt', + PEAR_PACKAGEFILE_ERROR_NO_FILES => + 'No files in section of package.xml', + PEAR_PACKAGEFILE_ERROR_NO_FILEROLE => + 'File "%file%" has no role, expecting one of "%roles%"', + PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE => + 'File "%file%" has invalid role "%role%", expecting one of "%roles%"', + PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME => + 'File "%file%" cannot start with ".", cannot package or install', + PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE => + 'Parser error: invalid PHP found in file "%file%"', + PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX => + 'in %file%: %type% "%name%" not prefixed with package name "%package%"', + PEAR_PACKAGEFILE_ERROR_INVALID_FILE => + 'Parser error: invalid PHP file "%file%"', + PEAR_PACKAGEFILE_ERROR_CHANNELVAL => + 'Channel validator error: field "%field%" - %reason%', + PEAR_PACKAGEFILE_ERROR_PHP5 => + 'Error, PHP5 token encountered in %file%, analysis should be in PHP5', + PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND => + 'File "%file%" in package.xml does not exist', + PEAR_PACKAGEFILE_ERROR_NON_ISO_CHARS => + 'Package.xml contains non-ISO-8859-1 characters, and may not validate', + ); } /** - * Retrieve a list of files that should be installed on this computer - * @return array + * Validate XML package definition file. + * + * @access public + * @return boolean */ - function getInstallationFilelist($forfilecheck = false) + function validate($state = PEAR_VALIDATE_NORMAL, $nofilechecking = false) { - $contents = $this->getFilelist(true); - if (isset($contents['dir']['attribs']['baseinstalldir'])) { - $base = $contents['dir']['attribs']['baseinstalldir']; - } - if (isset($this->_packageInfo['bundle'])) { - return PEAR::raiseError( - 'Exception: bundles should be handled in download code only'); + if (($this->_isValid & $state) == $state) { + return true; } - $release = $this->getReleases(); - if ($release) { - if (!isset($release[0])) { - if (!isset($release['installconditions']) && !isset($release['filelist'])) { - if ($forfilecheck) { - return $this->getFilelist(); - } - return $contents; - } - $release = array($release); - } - $depchecker = &$this->getPEARDependency2($this->_config, array(), - array('channel' => $this->getChannel(), 'package' => $this->getPackage()), - PEAR_VALIDATE_INSTALLING); - foreach ($release as $instance) { - if (isset($instance['installconditions'])) { - $installconditions = $instance['installconditions']; - if (is_array($installconditions)) { - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - foreach ($installconditions as $type => $conditions) { - if (!isset($conditions[0])) { - $conditions = array($conditions); - } - foreach ($conditions as $condition) { - $ret = $depchecker->{"validate{$type}Dependency"}($condition); - if (PEAR::isError($ret)) { - PEAR::popErrorHandling(); - continue 3; // skip this release - } - } - } - PEAR::popErrorHandling(); - } - } - // this is the release to use - if (isset($instance['filelist'])) { - // ignore files - if (isset($instance['filelist']['ignore'])) { - $ignore = isset($instance['filelist']['ignore'][0]) ? - $instance['filelist']['ignore'] : - array($instance['filelist']['ignore']); - foreach ($ignore as $ig) { - unset ($contents[$ig['attribs']['name']]); - } - } - // install files as this name - if (isset($instance['filelist']['install'])) { - $installas = isset($instance['filelist']['install'][0]) ? - $instance['filelist']['install'] : - array($instance['filelist']['install']); - foreach ($installas as $as) { - $contents[$as['attribs']['name']]['attribs']['install-as'] = - $as['attribs']['as']; - } - } - } - if ($forfilecheck) { - foreach ($contents as $file => $attrs) { - $contents[$file] = $attrs['attribs']; - } - } - return $contents; - } - } else { // simple release - no installconditions or install-as - if ($forfilecheck) { - return $this->getFilelist(); - } - return $contents; + $this->_isValid = true; + $info = $this->_packageInfo; + if (empty($info['package'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_NAME); + $this->_packageName = $pn = 'unknown'; + } else { + $this->_packageName = $pn = $info['package']; } - // no releases matched - return PEAR::raiseError('No releases in package.xml matched the existing operating ' . - 'system, extensions installed, or architecture, cannot install'); - } - /** - * This is only used at install-time, after all serialization - * is over. - * @param string file name - * @param string installed path - */ - function setInstalledAs($file, $path) - { - if ($path) { - return $this->_packageInfo['filelist'][$file]['installed_as'] = $path; + if (empty($info['summary'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_SUMMARY); + } elseif (strpos(trim($info['summary']), "\n") !== false) { + $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY, + array('summary' => $info['summary'])); } - unset($this->_packageInfo['filelist'][$file]['installed_as']); - } - - function getInstalledLocation($file) - { - if (isset($this->_packageInfo['filelist'][$file]['installed_as'])) { - return $this->_packageInfo['filelist'][$file]['installed_as']; + if (empty($info['description'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION); } - return false; - } - - /** - * This is only used at install-time, after all serialization - * is over. - */ - function installedFile($file, $atts) - { - if (isset($this->_packageInfo['filelist'][$file])) { - $this->_packageInfo['filelist'][$file] = - array_merge($this->_packageInfo['filelist'][$file], $atts['attribs']); - } else { - $this->_packageInfo['filelist'][$file] = $atts['attribs']; + if (empty($info['release_license'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_LICENSE); } - } - - /** - * Retrieve the contents tag - */ - function getContents() - { - if (isset($this->_packageInfo['contents'])) { - return $this->_packageInfo['contents']; + if (empty($info['version'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_VERSION); } - return false; - } - - /** - * @param string full path to file - * @param string attribute name - * @param string attribute value - * @param int risky but fast - use this to choose a file based on its position in the list - * of files. Index is zero-based like PHP arrays. - * @return bool success of operation - */ - function setFileAttribute($filename, $attr, $value, $index = false) - { - $this->_isValid = 0; - if (in_array($attr, array('role', 'name', 'baseinstalldir'))) { - $this->_filesValid = false; + if (empty($info['release_state'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_STATE); } - if ($index !== false && - isset($this->_packageInfo['contents']['dir']['file'][$index]['attribs'])) { - $this->_packageInfo['contents']['dir']['file'][$index]['attribs'][$attr] = $value; - return true; + if (empty($info['release_date'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DATE); } - if (!isset($this->_packageInfo['contents']['dir']['file'])) { - return false; + if (empty($info['release_notes'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_NOTES); } - $files = $this->_packageInfo['contents']['dir']['file']; - if (!isset($files[0])) { - $files = array($files); - $ind = false; + if (empty($info['maintainers'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS); } else { - $ind = true; + $haslead = false; + $i = 1; + foreach ($info['maintainers'] as $m) { + if (empty($m['handle'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE, + array('index' => $i)); + } + if (empty($m['role'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE, + array('index' => $i, 'roles' => PEAR_Common::getUserRoles())); + } elseif ($m['role'] == 'lead') { + $haslead = true; + } + if (empty($m['name'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME, + array('index' => $i)); + } + if (empty($m['email'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL, + array('index' => $i)); + } + $i++; + } + if (!$haslead) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_LEAD); + } } - foreach ($files as $i => $file) { - if (isset($file['attribs'])) { - if ($file['attribs']['name'] == $filename) { - if ($ind) { - $this->_packageInfo['contents']['dir']['file'][$i]['attribs'][$attr] = $value; - } else { - $this->_packageInfo['contents']['dir']['file']['attribs'][$attr] = $value; - } - return true; + if (!empty($info['release_deps'])) { + $i = 1; + foreach ($info['release_deps'] as $d) { + if (!isset($d['type']) || empty($d['type'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE, + array('index' => $i, 'types' => PEAR_Common::getDependencyTypes())); + continue; + } + if (!isset($d['rel']) || empty($d['rel'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPREL, + array('index' => $i, 'rels' => PEAR_Common::getDependencyRelations())); + continue; + } + if (!empty($d['optional'])) { + if (!in_array($d['optional'], array('yes', 'no'))) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL, + array('index' => $i, 'opt' => $d['optional'])); + } + } + if ($d['rel'] != 'has' && $d['rel'] != 'not' && empty($d['version'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION, + array('index' => $i)); + } elseif (($d['rel'] == 'has' || $d['rel'] == 'not') && !empty($d['version'])) { + $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED, + array('index' => $i, 'rel' => $d['rel'])); + } + if ($d['type'] == 'php' && !empty($d['name'])) { + $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED, + array('index' => $i, 'name' => $d['name'])); + } elseif ($d['type'] != 'php' && empty($d['name'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPNAME, + array('index' => $i)); + } + if ($d['type'] == 'php' && empty($d['version'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION, + array('index' => $i)); + } + if (($d['rel'] == 'not') && ($d['type'] == 'php')) { + $this->_validateError(PEAR_PACKAGEFILE_PHP_NO_NOT, + array('index' => $i)); + } + $i++; + } + } + if (!empty($info['configure_options'])) { + $i = 1; + foreach ($info['configure_options'] as $c) { + if (empty($c['name'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_CONFNAME, + array('index' => $i)); + } + if (empty($c['prompt'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT, + array('index' => $i)); + } + $i++; + } + } + if (empty($info['filelist'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_FILES); + $errors[] = 'no files'; + } else { + foreach ($info['filelist'] as $file => $fa) { + if (empty($fa['role'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_FILEROLE, + array('file' => $file, 'roles' => PEAR_Common::getFileRoles())); + continue; + } elseif (!in_array($fa['role'], PEAR_Common::getFileRoles())) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE, + array('file' => $file, 'role' => $fa['role'], 'roles' => PEAR_Common::getFileRoles())); + } + if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~', str_replace('\\', '/', $file))) { + // file contains .. parent directory or . cur directory references + $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME, + array('file' => $file)); + } + if (isset($fa['install-as']) && + preg_match('~/\.\.?(/|\\z)|^\.\.?/~', + str_replace('\\', '/', $fa['install-as']))) { + // install-as contains .. parent directory or . cur directory references + $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME, + array('file' => $file . ' [installed as ' . $fa['install-as'] . ']')); + } + if (isset($fa['baseinstalldir']) && + preg_match('~/\.\.?(/|\\z)|^\.\.?/~', + str_replace('\\', '/', $fa['baseinstalldir']))) { + // install-as contains .. parent directory or . cur directory references + $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME, + array('file' => $file . ' [baseinstalldir ' . $fa['baseinstalldir'] . ']')); } } } - return false; - } - - function setDirtree($path) - { - if (!isset($this->_packageInfo['dirtree'])) { - $this->_packageInfo['dirtree'] = array(); + if (isset($this->_registry) && $this->_isValid) { + $chan = $this->_registry->getChannel('pear.php.net'); + if (PEAR::isError($chan)) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $chan->getMessage()); + return $this->_isValid = 0; + } + $validator = $chan->getValidationObject(); + $validator->setPackageFile($this); + $validator->validate($state); + $failures = $validator->getFailures(); + foreach ($failures['errors'] as $error) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $error); + } + foreach ($failures['warnings'] as $warning) { + $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $warning); + } + } + if ($this->_isValid && $state == PEAR_VALIDATE_PACKAGING && !$nofilechecking) { + if ($this->_analyzePhpFiles()) { + $this->_isValid = true; + } } - $this->_packageInfo['dirtree'][$path] = true; - } - - function getDirtree() - { - if (isset($this->_packageInfo['dirtree']) && count($this->_packageInfo['dirtree'])) { - return $this->_packageInfo['dirtree']; + if ($this->_isValid) { + return $this->_isValid = $state; } - return false; - } - - function resetDirtree() - { - unset($this->_packageInfo['dirtree']); + return $this->_isValid = 0; } - /** - * Determines whether this package claims it is compatible with the version of - * the package that has a recommended version dependency - * @param PEAR_PackageFile_v2|PEAR_PackageFile_v1|PEAR_Downloader_Package - * @return boolean - */ - function isCompatible($pf) + function _analyzePhpFiles() { - if (!isset($this->_packageInfo['compatible'])) { + if (!$this->_isValid) { return false; } - if (!isset($this->_packageInfo['channel'])) { + if (!isset($this->_packageFile)) { return false; } - $me = $pf->getVersion(); - $compatible = $this->_packageInfo['compatible']; - if (!isset($compatible[0])) { - $compatible = array($compatible); - } - $found = false; - foreach ($compatible as $info) { - if (strtolower($info['name']) == strtolower($pf->getPackage())) { - if (strtolower($info['channel']) == strtolower($pf->getChannel())) { - $found = true; - break; + $dir_prefix = dirname($this->_packageFile); + $common = new PEAR_Common; + $log = isset($this->_logger) ? array(&$this->_logger, 'log') : + array($common, 'log'); + $info = $this->getFilelist(); + foreach ($info as $file => $fa) { + if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $file)) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND, + array('file' => realpath($dir_prefix) . DIRECTORY_SEPARATOR . $file)); + continue; + } + if ($fa['role'] == 'php' && $dir_prefix) { + call_user_func_array($log, array(1, "Analyzing $file")); + $srcinfo = $this->_analyzeSourceCode($dir_prefix . DIRECTORY_SEPARATOR . $file); + if ($srcinfo) { + $this->_buildProvidesArray($srcinfo); } } } - if (!$found) { - return false; - } - if (isset($info['exclude'])) { - if (!isset($info['exclude'][0])) { - $info['exclude'] = array($info['exclude']); - } - foreach ($info['exclude'] as $exclude) { - if (version_compare($me, $exclude, '==')) { - return false; + $this->_packageName = $pn = $this->getPackage(); + $pnl = strlen($pn); + if (isset($this->_packageInfo['provides'])) { + foreach ((array) $this->_packageInfo['provides'] as $key => $what) { + if (isset($what['explicit'])) { + // skip conformance checks if the provides entry is + // specified in the package.xml file + continue; + } + extract($what); + if ($type == 'class') { + if (!strncasecmp($name, $pn, $pnl)) { + continue; + } + $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX, + array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn)); + } elseif ($type == 'function') { + if (strstr($name, '::') || !strncasecmp($name, $pn, $pnl)) { + continue; + } + $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX, + array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn)); } } } - if (version_compare($me, $info['min'], '>=') && version_compare($me, $info['max'], '<=')) { - return true; - } - return false; + return $this->_isValid; } /** - * @return array|false + * Get the default xml generator object + * + * @return PEAR_PackageFile_Generator_v1 */ - function getCompatible() - { - if (isset($this->_packageInfo['compatible'])) { - return $this->_packageInfo['compatible']; - } - return false; - } - - function getDependencies() + function &getDefaultGenerator() { - if (isset($this->_packageInfo['dependencies'])) { - return $this->_packageInfo['dependencies']; + if (!class_exists('PEAR_PackageFile_Generator_v1')) { + require_once 'PEAR/PackageFile/Generator/v1.php'; } - return false; - } - - function isSubpackageOf($p) - { - return $p->isSubpackage($this); + $a = &new PEAR_PackageFile_Generator_v1($this); + return $a; } /** - * Determines whether the passed in package is a subpackage of this package. - * - * No version checking is done, only name verification. - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @return bool + * Get the contents of a file listed within the package.xml + * @param string + * @return string */ - function isSubpackage($p) + function getFileContents($file) { - $sub = array(); - if (isset($this->_packageInfo['dependencies']['required']['subpackage'])) { - $sub = $this->_packageInfo['dependencies']['required']['subpackage']; - if (!isset($sub[0])) { - $sub = array($sub); - } - } - if (isset($this->_packageInfo['dependencies']['optional']['subpackage'])) { - $sub1 = $this->_packageInfo['dependencies']['optional']['subpackage']; - if (!isset($sub1[0])) { - $sub1 = array($sub1); - } - $sub = array_merge($sub, $sub1); - } - if (isset($this->_packageInfo['dependencies']['group'])) { - $group = $this->_packageInfo['dependencies']['group']; - if (!isset($group[0])) { - $group = array($group); - } - foreach ($group as $deps) { - if (isset($deps['subpackage'])) { - $sub2 = $deps['subpackage']; - if (!isset($sub2[0])) { - $sub2 = array($sub2); - } - $sub = array_merge($sub, $sub2); - } + if ($this->_archiveFile == $this->_packageFile) { // unpacked + $dir = dirname($this->_packageFile); + $file = $dir . DIRECTORY_SEPARATOR . $file; + $file = str_replace(array('/', '\\'), + array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), $file); + if (file_exists($file) && is_readable($file)) { + return implode('', file($file)); } - } - foreach ($sub as $dep) { - if (strtolower($dep['name']) == strtolower($p->getPackage())) { - if (isset($dep['channel'])) { - if (strtolower($dep['channel']) == strtolower($p->getChannel())) { - return true; - } - } else { - if ($dep['uri'] == $p->getURI()) { - return true; - } - } + } else { // tgz + if (!class_exists('Archive_Tar')) { + require_once 'Archive/Tar.php'; } - } - return false; - } - - function dependsOn($package, $channel) - { - if (!($deps = $this->getDependencies())) { - return false; - } - foreach (array('package', 'subpackage') as $type) { - foreach (array('required', 'optional') as $needed) { - if (isset($deps[$needed][$type])) { - if (!isset($deps[$needed][$type][0])) { - $deps[$needed][$type] = array($deps[$needed][$type]); - } - foreach ($deps[$needed][$type] as $dep) { - $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri'; - if (strtolower($dep['name']) == strtolower($package) && - $depchannel == $channel) { - return true; - } - } - } + $tar = &new Archive_Tar($this->_archiveFile); + $tar->pushErrorHandling(PEAR_ERROR_RETURN); + if ($file != 'package.xml' && $file != 'package2.xml') { + $file = $this->getPackage() . '-' . $this->getVersion() . '/' . $file; } - if (isset($deps['group'])) { - if (!isset($deps['group'][0])) { - $dep['group'] = array($deps['group']); - } - foreach ($deps['group'] as $group) { - if (isset($group[$type])) { - if (!is_array($group[$type])) { - $group[$type] = array($group[$type]); - } - foreach ($group[$type] as $dep) { - $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri'; - if (strtolower($dep['name']) == strtolower($package) && - $depchannel == $channel) { - return true; - } - } - } - } + $file = $tar->extractInString($file); + $tar->popErrorHandling(); + if (PEAR::isError($file)) { + return PEAR::raiseError("Cannot locate file '$file' in archive"); } + return $file; } - return false; } + // {{{ analyzeSourceCode() /** - * Get the contents of a dependency group - * @param string - * @return array|false + * Analyze the source code of the given PHP file + * + * @param string Filename of the PHP file + * @return mixed + * @access private */ - function getDependencyGroup($name) + function _analyzeSourceCode($file) { - $name = strtolower($name); - if (!isset($this->_packageInfo['dependencies']['group'])) { + if (!function_exists("token_get_all")) { return false; } - $groups = $this->_packageInfo['dependencies']['group']; - if (!isset($groups[0])) { - $groups = array($groups); + if (!defined('T_DOC_COMMENT')) { + define('T_DOC_COMMENT', T_COMMENT); } - foreach ($groups as $group) { - if (strtolower($group['attribs']['name']) == $name) { - return $group; - } + if (!defined('T_INTERFACE')) { + define('T_INTERFACE', -1); } - return false; - } - - /** - * Retrieve a partial package.xml 1.0 representation of dependencies - * - * a very limited representation of dependencies is returned by this method. - * The tag for excluding certain versions of a dependency is - * completely ignored. In addition, dependency groups are ignored, with the - * assumption that all dependencies in dependency groups are also listed in - * the optional group that work with all dependency groups - * @param boolean return package.xml 2.0 tag - * @return array|false - */ - function getDeps($raw = false, $nopearinstaller = false) - { - if (isset($this->_packageInfo['dependencies'])) { - if ($raw) { - return $this->_packageInfo['dependencies']; + if (!defined('T_IMPLEMENTS')) { + define('T_IMPLEMENTS', -1); + } + if (!$fp = @fopen($file, "r")) { + return false; + } + fclose($fp); + $contents = file_get_contents($file); + $tokens = token_get_all($contents); +/* + for ($i = 0; $i < sizeof($tokens); $i++) { + @list($token, $data) = $tokens[$i]; + if (is_string($token)) { + var_dump($token); + } else { + print token_name($token) . ' '; + var_dump(rtrim($data)); } - $ret = array(); - $map = array( - 'php' => 'php', - 'package' => 'pkg', - 'subpackage' => 'pkg', - 'extension' => 'ext', - 'os' => 'os', - 'pearinstaller' => 'pkg', - ); - foreach (array('required', 'optional') as $type) { - $optional = ($type == 'optional') ? 'yes' : 'no'; - if (!isset($this->_packageInfo['dependencies'][$type]) - || empty($this->_packageInfo['dependencies'][$type])) { + } +*/ + $look_for = 0; + $paren_level = 0; + $bracket_level = 0; + $brace_level = 0; + $lastphpdoc = ''; + $current_class = ''; + $current_interface = ''; + $current_class_level = -1; + $current_function = ''; + $current_function_level = -1; + $declared_classes = array(); + $declared_interfaces = array(); + $declared_functions = array(); + $declared_methods = array(); + $used_classes = array(); + $used_functions = array(); + $extends = array(); + $implements = array(); + $nodeps = array(); + $inquote = false; + $interface = false; + for ($i = 0; $i < sizeof($tokens); $i++) { + if (is_array($tokens[$i])) { + list($token, $data) = $tokens[$i]; + } else { + $token = $tokens[$i]; + $data = ''; + } + if ($inquote) { + if ($token != '"' && $token != T_END_HEREDOC) { + continue; + } else { + $inquote = false; continue; } - foreach ($this->_packageInfo['dependencies'][$type] as $dtype => $deps) { - if ($dtype == 'pearinstaller' && $nopearinstaller) { - continue; + } + switch ($token) { + case T_WHITESPACE : + continue; + case ';': + if ($interface) { + $current_function = ''; + $current_function_level = -1; } - if (!isset($deps[0])) { - $deps = array($deps); + break; + case '"': + case T_START_HEREDOC: + $inquote = true; + break; + case T_CURLY_OPEN: + case T_DOLLAR_OPEN_CURLY_BRACES: + case '{': $brace_level++; continue 2; + case '}': + $brace_level--; + if ($current_class_level == $brace_level) { + $current_class = ''; + $current_class_level = -1; } - foreach ($deps as $dep) { - if (!isset($map[$dtype])) { - // no support for arch type - continue; - } - if ($dtype == 'pearinstaller') { - $dep['name'] = 'PEAR'; - $dep['channel'] = 'pear.php.net'; - } - $s = array('type' => $map[$dtype]); - if (isset($dep['channel'])) { - $s['channel'] = $dep['channel']; - } - if (isset($dep['uri'])) { - $s['uri'] = $dep['uri']; - } - if (isset($dep['name'])) { - $s['name'] = $dep['name']; + if ($current_function_level == $brace_level) { + $current_function = ''; + $current_function_level = -1; + } + continue 2; + case '[': $bracket_level++; continue 2; + case ']': $bracket_level--; continue 2; + case '(': $paren_level++; continue 2; + case ')': $paren_level--; continue 2; + case T_INTERFACE: + $interface = true; + case T_CLASS: + if (($current_class_level != -1) || ($current_function_level != -1)) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE, + array('file' => $file)); + return false; + } + case T_FUNCTION: + case T_NEW: + case T_EXTENDS: + case T_IMPLEMENTS: + $look_for = $token; + continue 2; + case T_STRING: + if (version_compare(zend_version(), '2.0', '<')) { + if (in_array(strtolower($data), + array('public', 'private', 'protected', 'abstract', + 'interface', 'implements', 'throw') + )) { + $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_PHP5, + array($file)); } - if (isset($dep['conflicts'])) { - $s['rel'] = 'not'; + } + if ($look_for == T_CLASS) { + $current_class = $data; + $current_class_level = $brace_level; + $declared_classes[] = $current_class; + } elseif ($look_for == T_INTERFACE) { + $current_interface = $data; + $current_class_level = $brace_level; + $declared_interfaces[] = $current_interface; + } elseif ($look_for == T_IMPLEMENTS) { + $implements[$current_class] = $data; + } elseif ($look_for == T_EXTENDS) { + $extends[$current_class] = $data; + } elseif ($look_for == T_FUNCTION) { + if ($current_class) { + $current_function = "$current_class::$data"; + $declared_methods[$current_class][] = $data; + } elseif ($current_interface) { + $current_function = "$current_interface::$data"; + $declared_methods[$current_interface][] = $data; } else { - if (!isset($dep['min']) && - !isset($dep['max'])) { - $s['rel'] = 'has'; - $s['optional'] = $optional; - } elseif (isset($dep['min']) && - isset($dep['max'])) { - $s['rel'] = 'ge'; - $s1 = $s; - $s1['rel'] = 'le'; - $s['version'] = $dep['min']; - $s1['version'] = $dep['max']; - if (isset($dep['channel'])) { - $s1['channel'] = $dep['channel']; - } - if ($dtype != 'php') { - $s['name'] = $dep['name']; - $s1['name'] = $dep['name']; - } - $s['optional'] = $optional; - $s1['optional'] = $optional; - $ret[] = $s1; - } elseif (isset($dep['min'])) { - if (isset($dep['exclude']) && - $dep['exclude'] == $dep['min']) { - $s['rel'] = 'gt'; - } else { - $s['rel'] = 'ge'; - } - $s['version'] = $dep['min']; - $s['optional'] = $optional; - if ($dtype != 'php') { - $s['name'] = $dep['name']; - } - } elseif (isset($dep['max'])) { - if (isset($dep['exclude']) && - $dep['exclude'] == $dep['max']) { - $s['rel'] = 'lt'; - } else { - $s['rel'] = 'le'; - } - $s['version'] = $dep['max']; - $s['optional'] = $optional; - if ($dtype != 'php') { - $s['name'] = $dep['name']; - } - } + $current_function = $data; + $declared_functions[] = $current_function; } - $ret[] = $s; + $current_function_level = $brace_level; + $m = array(); + } elseif ($look_for == T_NEW) { + $used_classes[$data] = true; } - } - } - if (count($ret)) { - return $ret; + $look_for = 0; + continue 2; + case T_VARIABLE: + $look_for = 0; + continue 2; + case T_DOC_COMMENT: + case T_COMMENT: + if (preg_match('!^/\*\*\s!', $data)) { + $lastphpdoc = $data; + if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m)) { + $nodeps = array_merge($nodeps, $m[1]); + } + } + continue 2; + case T_DOUBLE_COLON: + if (!($tokens[$i - 1][0] == T_WHITESPACE || $tokens[$i - 1][0] == T_STRING)) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE, + array('file' => $file)); + return false; + } + $class = $tokens[$i - 1][1]; + if (strtolower($class) != 'parent') { + $used_classes[$class] = true; + } + continue 2; } } - return false; + return array( + "source_file" => $file, + "declared_classes" => $declared_classes, + "declared_interfaces" => $declared_interfaces, + "declared_methods" => $declared_methods, + "declared_functions" => $declared_functions, + "used_classes" => array_diff(array_keys($used_classes), $nodeps), + "inheritance" => $extends, + "implements" => $implements, + ); } /** - * @return php|extsrc|extbin|zendextsrc|zendextbin|bundle|false + * Build a "provides" array from data returned by + * analyzeSourceCode(). The format of the built array is like + * this: + * + * array( + * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'), + * ... + * ) + * + * + * @param array $srcinfo array with information about a source file + * as returned by the analyzeSourceCode() method. + * + * @return void + * + * @access private + * */ - function getPackageType() + function _buildProvidesArray($srcinfo) { - if (isset($this->_packageInfo['phprelease'])) { - return 'php'; - } - if (isset($this->_packageInfo['extsrcrelease'])) { - return 'extsrc'; - } - if (isset($this->_packageInfo['extbinrelease'])) { - return 'extbin'; + if (!$this->_isValid) { + return false; } - if (isset($this->_packageInfo['zendextsrcrelease'])) { - return 'zendextsrc'; + $file = basename($srcinfo['source_file']); + $pn = $this->getPackage(); + $pnl = strlen($pn); + foreach ($srcinfo['declared_classes'] as $class) { + $key = "class;$class"; + if (isset($this->_packageInfo['provides'][$key])) { + continue; + } + $this->_packageInfo['provides'][$key] = + array('file'=> $file, 'type' => 'class', 'name' => $class); + if (isset($srcinfo['inheritance'][$class])) { + $this->_packageInfo['provides'][$key]['extends'] = + $srcinfo['inheritance'][$class]; + } } - if (isset($this->_packageInfo['zendextbinrelease'])) { - return 'zendextbin'; + foreach ($srcinfo['declared_methods'] as $class => $methods) { + foreach ($methods as $method) { + $function = "$class::$method"; + $key = "function;$function"; + if ($method{0} == '_' || !strcasecmp($method, $class) || + isset($this->_packageInfo['provides'][$key])) { + continue; + } + $this->_packageInfo['provides'][$key] = + array('file'=> $file, 'type' => 'function', 'name' => $function); + } } - if (isset($this->_packageInfo['bundle'])) { - return 'bundle'; + + foreach ($srcinfo['declared_functions'] as $function) { + $key = "function;$function"; + if ($function{0} == '_' || isset($this->_packageInfo['provides'][$key])) { + continue; + } + if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) { + $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\""; + } + $this->_packageInfo['provides'][$key] = + array('file'=> $file, 'type' => 'function', 'name' => $function); } - return false; } + // }}} +} +?> +PEAR-1.9.0/PEAR/PackageFile/v2.php100664 764 764 207576 100664 11311 + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: v2.php 276383 2009-02-24 23:39:37Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/** + * For error handling + */ +require_once 'PEAR/ErrorStack.php'; +/** + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_PackageFile_v2 +{ + /** - * @return array|false + * Parsed package information + * @var array + * @access private */ - function getReleases() - { - $type = $this->getPackageType(); - if ($type != 'bundle') { - $type .= 'release'; - } - if ($this->getPackageType() && isset($this->_packageInfo[$type])) { - return $this->_packageInfo[$type]; - } - return false; - } + var $_packageInfo = array(); /** - * @return array + * path to package .tgz or false if this is a local/extracted package.xml + * @var string|false + * @access private */ - function getChangelog() - { - if (isset($this->_packageInfo['changelog'])) { - return $this->_packageInfo['changelog']; - } - return false; - } + var $_archiveFile; - function hasDeps() - { - return isset($this->_packageInfo['dependencies']); - } + /** + * path to package .xml or false if this is an abstract parsed-from-string xml + * @var string|false + * @access private + */ + var $_packageFile; - function getPackagexmlVersion() + /** + * This is used by file analysis routines to log progress information + * @var PEAR_Common + * @access protected + */ + var $_logger; + + /** + * This is set to the highest validation level that has been validated + * + * If the package.xml is invalid or unknown, this is set to 0. If + * normal validation has occurred, this is set to PEAR_VALIDATE_NORMAL. If + * downloading/installation validation has occurred it is set to PEAR_VALIDATE_DOWNLOADING + * or INSTALLING, and so on up to PEAR_VALIDATE_PACKAGING. This allows validation + * "caching" to occur, which is particularly important for package validation, so + * that PHP files are not validated twice + * @var int + * @access private + */ + var $_isValid = 0; + + /** + * True if the filelist has been validated + * @param bool + */ + var $_filesValid = false; + + /** + * @var PEAR_Registry + * @access protected + */ + var $_registry; + + /** + * @var PEAR_Config + * @access protected + */ + var $_config; + + /** + * Optional Dependency group requested for installation + * @var string + * @access private + */ + var $_requestedGroup = false; + + /** + * @var PEAR_ErrorStack + * @access protected + */ + var $_stack; + + /** + * Namespace prefix used for tasks in this package.xml - use tasks: whenever possible + */ + var $_tasksNs; + + /** + * Determines whether this packagefile was initialized only with partial package info + * + * If this package file was constructed via parsing REST, it will only contain + * + * - package name + * - channel name + * - dependencies + * @var boolean + * @access private + */ + var $_incomplete = true; + + /** + * @var PEAR_PackageFile_v2_Validator + */ + var $_v2Validator; + + /** + * The constructor merely sets up the private error stack + */ + function PEAR_PackageFile_v2() { - if (isset($this->_packageInfo['zendextsrcrelease'])) { - return '2.1'; - } - if (isset($this->_packageInfo['zendextbinrelease'])) { - return '2.1'; - } - return '2.0'; + $this->_stack = new PEAR_ErrorStack('PEAR_PackageFile_v2', false, null); + $this->_isValid = false; } /** - * @return array|false + * To make unit-testing easier + * @param PEAR_Frontend_* + * @param array options + * @param PEAR_Config + * @return PEAR_Downloader + * @access protected */ - function getSourcePackage() + function &getPEARDownloader(&$i, $o, &$c) { - if (isset($this->_packageInfo['extbinrelease']) || - isset($this->_packageInfo['zendextbinrelease'])) { - return array('channel' => $this->_packageInfo['srcchannel'], - 'package' => $this->_packageInfo['srcpackage']); - } - return false; + $z = &new PEAR_Downloader($i, $o, $c); + return $z; } - function getBundledPackages() + /** + * To make unit-testing easier + * @param PEAR_Config + * @param array options + * @param array package name as returned from {@link PEAR_Registry::parsePackageName()} + * @param int PEAR_VALIDATE_* constant + * @return PEAR_Dependency2 + * @access protected + */ + function &getPEARDependency2(&$c, $o, $p, $s = PEAR_VALIDATE_INSTALLING) { - if (isset($this->_packageInfo['bundle'])) { - return $this->_packageInfo['contents']['bundledpackage']; + if (!class_exists('PEAR_Dependency2')) { + require_once 'PEAR/Dependency2.php'; } - return false; + $z = &new PEAR_Dependency2($c, $o, $p, $s); + return $z; } - function getLastModified() + function getInstalledBinary() { - if (isset($this->_packageInfo['_lastmodified'])) { - return $this->_packageInfo['_lastmodified']; - } - return false; + return isset($this->_packageInfo['#binarypackage']) ? $this->_packageInfo['#binarypackage'] : + false; } /** - * Get the contents of a file listed within the package.xml - * @param string - * @return string + * Installation of source package has failed, attempt to download and install the + * binary version of this package. + * @param PEAR_Installer + * @return array|false */ - function getFileContents($file) + function installBinary(&$installer) { - if ($this->_archiveFile == $this->_packageFile) { // unpacked - $dir = dirname($this->_packageFile); - $file = $dir . DIRECTORY_SEPARATOR . $file; - $file = str_replace(array('/', '\\'), - array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), $file); - if (file_exists($file) && is_readable($file)) { - return implode('', file($file)); - } - } else { // tgz - $tar = &new Archive_Tar($this->_archiveFile); - $tar->pushErrorHandling(PEAR_ERROR_RETURN); - if ($file != 'package.xml' && $file != 'package2.xml') { - $file = $this->getPackage() . '-' . $this->getVersion() . '/' . $file; - } - $file = $tar->extractInString($file); - $tar->popErrorHandling(); - if (PEAR::isError($file)) { - return PEAR::raiseError("Cannot locate file '$file' in archive"); - } - return $file; - } - } - - function &getRW() - { - if (!class_exists('PEAR_PackageFile_v2_rw')) { - require_once 'PEAR/PackageFile/v2/rw.php'; + if (!OS_WINDOWS) { + $a = false; + return $a; } - $a = new PEAR_PackageFile_v2_rw; - foreach (get_object_vars($this) as $name => $unused) { - if (!isset($this->$name)) { - continue; + if ($this->getPackageType() == 'extsrc' || $this->getPackageType() == 'zendextsrc') { + $releasetype = $this->getPackageType() . 'release'; + if (!is_array($installer->getInstallPackages())) { + $a = false; + return $a; } - if ($name == '_config' || $name == '_logger'|| $name == '_registry' || - $name == '_stack') { - $a->$name = &$this->$name; - } else { - $a->$name = $this->$name; + foreach ($installer->getInstallPackages() as $p) { + if ($p->isExtension($this->_packageInfo['providesextension'])) { + if ($p->getPackageType() != 'extsrc' && $p->getPackageType() != 'zendextsrc') { + $a = false; + return $a; // the user probably downloaded it separately + } + } + } + if (isset($this->_packageInfo[$releasetype]['binarypackage'])) { + $installer->log(0, 'Attempting to download binary version of extension "' . + $this->_packageInfo['providesextension'] . '"'); + $params = $this->_packageInfo[$releasetype]['binarypackage']; + if (!is_array($params) || !isset($params[0])) { + $params = array($params); + } + if (isset($this->_packageInfo['channel'])) { + foreach ($params as $i => $param) { + $params[$i] = array('channel' => $this->_packageInfo['channel'], + 'package' => $param, 'version' => $this->getVersion()); + } + } + $dl = &$this->getPEARDownloader($installer->ui, $installer->getOptions(), + $installer->config); + $verbose = $dl->config->get('verbose'); + $dl->config->set('verbose', -1); + foreach ($params as $param) { + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $ret = $dl->download(array($param)); + PEAR::popErrorHandling(); + if (is_array($ret) && count($ret)) { + break; + } + } + $dl->config->set('verbose', $verbose); + if (is_array($ret)) { + if (count($ret) == 1) { + $pf = $ret[0]->getPackageFile(); + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $err = $installer->install($ret[0]); + PEAR::popErrorHandling(); + if (is_array($err)) { + $this->_packageInfo['#binarypackage'] = $ret[0]->getPackage(); + // "install" self, so all dependencies will work transparently + $this->_registry->addPackage2($this); + $installer->log(0, 'Download and install of binary extension "' . + $this->_registry->parsedPackageNameToString( + array('channel' => $pf->getChannel(), + 'package' => $pf->getPackage()), true) . '" successful'); + $a = array($ret[0], $err); + return $a; + } + $installer->log(0, 'Download and install of binary extension "' . + $this->_registry->parsedPackageNameToString( + array('channel' => $pf->getChannel(), + 'package' => $pf->getPackage()), true) . '" failed'); + } + } } } + $a = false; return $a; } - function &getDefaultGenerator() + /** + * @return string|false Extension name + */ + function getProvidesExtension() { - if (!class_exists('PEAR_PackageFile_Generator_v2')) { - require_once 'PEAR/PackageFile/Generator/v2.php'; + if (in_array($this->getPackageType(), + array('extsrc', 'extbin', 'zendextsrc', 'zendextbin'))) { + if (isset($this->_packageInfo['providesextension'])) { + return $this->_packageInfo['providesextension']; + } } - $a = &new PEAR_PackageFile_Generator_v2($this); - return $a; + return false; } - function analyzeSourceCode($file, $string = false) + /** + * @param string Extension name + * @return bool + */ + function isExtension($extension) { - if (!isset($this->_v2Validator) || - !is_a($this->_v2Validator, 'PEAR_PackageFile_v2_Validator')) { - if (!class_exists('PEAR_PackageFile_v2_Validator')) { - require_once 'PEAR/PackageFile/v2/Validator.php'; - } - $this->_v2Validator = new PEAR_PackageFile_v2_Validator; + if (in_array($this->getPackageType(), + array('extsrc', 'extbin', 'zendextsrc', 'zendextbin'))) { + return $this->_packageInfo['providesextension'] == $extension; } - return $this->_v2Validator->analyzeSourceCode($file, $string); + return false; } - function validate($state = PEAR_VALIDATE_NORMAL) + /** + * Tests whether every part of the package.xml 1.0 is represented in + * this package.xml 2.0 + * @param PEAR_PackageFile_v1 + * @return bool + */ + function isEquivalent($pf1) { - if (!isset($this->_packageInfo) || !is_array($this->_packageInfo)) { + if (!$pf1) { + return true; + } + if ($this->getPackageType() == 'bundle') { return false; } - if (!isset($this->_v2Validator) || - !is_a($this->_v2Validator, 'PEAR_PackageFile_v2_Validator')) { - if (!class_exists('PEAR_PackageFile_v2_Validator')) { - require_once 'PEAR/PackageFile/v2/Validator.php'; + $this->_stack->getErrors(true); + if (!$pf1->validate(PEAR_VALIDATE_NORMAL)) { + return false; + } + $pass = true; + if ($pf1->getPackage() != $this->getPackage()) { + $this->_differentPackage($pf1->getPackage()); + $pass = false; + } + if ($pf1->getVersion() != $this->getVersion()) { + $this->_differentVersion($pf1->getVersion()); + $pass = false; + } + if (trim($pf1->getSummary()) != $this->getSummary()) { + $this->_differentSummary($pf1->getSummary()); + $pass = false; + } + if (preg_replace('/\s+/', '', $pf1->getDescription()) != + preg_replace('/\s+/', '', $this->getDescription())) { + $this->_differentDescription($pf1->getDescription()); + $pass = false; + } + if ($pf1->getState() != $this->getState()) { + $this->_differentState($pf1->getState()); + $pass = false; + } + if (!strstr(preg_replace('/\s+/', '', $this->getNotes()), + preg_replace('/\s+/', '', $pf1->getNotes()))) { + $this->_differentNotes($pf1->getNotes()); + $pass = false; + } + $mymaintainers = $this->getMaintainers(); + $yourmaintainers = $pf1->getMaintainers(); + for ($i1 = 0; $i1 < count($yourmaintainers); $i1++) { + $reset = false; + for ($i2 = 0; $i2 < count($mymaintainers); $i2++) { + if ($mymaintainers[$i2]['handle'] == $yourmaintainers[$i1]['handle']) { + if ($mymaintainers[$i2]['role'] != $yourmaintainers[$i1]['role']) { + $this->_differentRole($mymaintainers[$i2]['handle'], + $yourmaintainers[$i1]['role'], $mymaintainers[$i2]['role']); + $pass = false; + } + if ($mymaintainers[$i2]['email'] != $yourmaintainers[$i1]['email']) { + $this->_differentEmail($mymaintainers[$i2]['handle'], + $yourmaintainers[$i1]['email'], $mymaintainers[$i2]['email']); + $pass = false; + } + if ($mymaintainers[$i2]['name'] != $yourmaintainers[$i1]['name']) { + $this->_differentName($mymaintainers[$i2]['handle'], + $yourmaintainers[$i1]['name'], $mymaintainers[$i2]['name']); + $pass = false; + } + unset($mymaintainers[$i2]); + $mymaintainers = array_values($mymaintainers); + unset($yourmaintainers[$i1]); + $yourmaintainers = array_values($yourmaintainers); + $reset = true; + break; + } + } + if ($reset) { + $i1 = -1; } - $this->_v2Validator = new PEAR_PackageFile_v2_Validator; } - if (isset($this->_packageInfo['xsdversion'])) { - unset($this->_packageInfo['xsdversion']); + $this->_unmatchedMaintainers($mymaintainers, $yourmaintainers); + $filelist = $this->getFilelist(); + foreach ($pf1->getFilelist() as $file => $atts) { + if (!isset($filelist[$file])) { + $this->_missingFile($file); + $pass = false; + } } - return $this->_v2Validator->validate($this, $state); + return $pass; } - function getTasksNs() + function _differentPackage($package) { - if (!isset($this->_tasksNs)) { - if (isset($this->_packageInfo['attribs'])) { - foreach ($this->_packageInfo['attribs'] as $name => $value) { - if ($value == 'http://pear.php.net/dtd/tasks-1.0') { - $this->_tasksNs = str_replace('xmlns:', '', $name); - break; - } - } - } + $this->_stack->push(__FUNCTION__, 'error', array('package' => $package, + 'self' => $this->getPackage()), + 'package.xml 1.0 package "%package%" does not match "%self%"'); + } + + function _differentVersion($version) + { + $this->_stack->push(__FUNCTION__, 'error', array('version' => $version, + 'self' => $this->getVersion()), + 'package.xml 1.0 version "%version%" does not match "%self%"'); + } + + function _differentState($state) + { + $this->_stack->push(__FUNCTION__, 'error', array('state' => $state, + 'self' => $this->getState()), + 'package.xml 1.0 state "%state%" does not match "%self%"'); + } + + function _differentRole($handle, $role, $selfrole) + { + $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle, + 'role' => $role, 'self' => $selfrole), + 'package.xml 1.0 maintainer "%handle%" role "%role%" does not match "%self%"'); + } + + function _differentEmail($handle, $email, $selfemail) + { + $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle, + 'email' => $email, 'self' => $selfemail), + 'package.xml 1.0 maintainer "%handle%" email "%email%" does not match "%self%"'); + } + + function _differentName($handle, $name, $selfname) + { + $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle, + 'name' => $name, 'self' => $selfname), + 'package.xml 1.0 maintainer "%handle%" name "%name%" does not match "%self%"'); + } + + function _unmatchedMaintainers($my, $yours) + { + if ($my) { + array_walk($my, create_function('&$i, $k', '$i = $i["handle"];')); + $this->_stack->push(__FUNCTION__, 'error', array('handles' => $my), + 'package.xml 2.0 has unmatched extra maintainers "%handles%"'); } - return $this->_tasksNs; + if ($yours) { + array_walk($yours, create_function('&$i, $k', '$i = $i["handle"];')); + $this->_stack->push(__FUNCTION__, 'error', array('handles' => $yours), + 'package.xml 1.0 has unmatched extra maintainers "%handles%"'); + } + } + + function _differentNotes($notes) + { + $truncnotes = strlen($notes) < 25 ? $notes : substr($notes, 0, 24) . '...'; + $truncmynotes = strlen($this->getNotes()) < 25 ? $this->getNotes() : + substr($this->getNotes(), 0, 24) . '...'; + $this->_stack->push(__FUNCTION__, 'error', array('notes' => $truncnotes, + 'self' => $truncmynotes), + 'package.xml 1.0 release notes "%notes%" do not match "%self%"'); + } + + function _differentSummary($summary) + { + $truncsummary = strlen($summary) < 25 ? $summary : substr($summary, 0, 24) . '...'; + $truncmysummary = strlen($this->getsummary()) < 25 ? $this->getSummary() : + substr($this->getsummary(), 0, 24) . '...'; + $this->_stack->push(__FUNCTION__, 'error', array('summary' => $truncsummary, + 'self' => $truncmysummary), + 'package.xml 1.0 summary "%summary%" does not match "%self%"'); + } + + function _differentDescription($description) + { + $truncdescription = trim(strlen($description) < 25 ? $description : substr($description, 0, 24) . '...'); + $truncmydescription = trim(strlen($this->getDescription()) < 25 ? $this->getDescription() : + substr($this->getdescription(), 0, 24) . '...'); + $this->_stack->push(__FUNCTION__, 'error', array('description' => $truncdescription, + 'self' => $truncmydescription), + 'package.xml 1.0 description "%description%" does not match "%self%"'); + } + + function _missingFile($file) + { + $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), + 'package.xml 1.0 file "%file%" is not present in '); } /** - * Determine whether a task name is a valid task. Custom tasks may be defined - * using subdirectories by putting a "-" in the name, as in - * - * Note that this method will auto-load the task class file and test for the existence - * of the name with "-" replaced by "_" as in PEAR/Task/mycustom/task.php makes class - * PEAR_Task_mycustom_task - * @param string - * @return boolean + * WARNING - do not use this function unless you know what you're doing */ - function getTask($task) + function setRawState($state) { - $this->getTasksNs(); - // transform all '-' to '/' and 'tasks:' to '' so tasks:replace becomes replace - $task = str_replace(array($this->_tasksNs . ':', '-'), array('', ' '), $task); - $taskfile = str_replace(' ', '/', ucwords($task)); - $task = str_replace(array(' ', '/'), '_', ucwords($task)); - if (class_exists("PEAR_Task_$task")) { - return "PEAR_Task_$task"; - } - $fp = @fopen("PEAR/Task/$taskfile.php", 'r', true); - if ($fp) { - fclose($fp); - require_once "PEAR/Task/$taskfile.php"; - return "PEAR_Task_$task"; + if (!isset($this->_packageInfo['stability'])) { + $this->_packageInfo['stability'] = array(); } - return false; + $this->_packageInfo['stability']['release'] = $state; } /** - * Key-friendly array_splice - * @param tagname to splice a value in before - * @param mixed the value to splice in - * @param string the new tag name + * WARNING - do not use this function unless you know what you're doing */ - function _ksplice($array, $key, $value, $newkey) + function setRawCompatible($compatible) { - $offset = array_search($key, array_keys($array)); - $after = array_slice($array, $offset); - $before = array_slice($array, 0, $offset); - $before[$newkey] = $value; - return array_merge($before, $after); + $this->_packageInfo['compatible'] = $compatible; } /** - * @param array a list of possible keys, in the order they may occur - * @param mixed contents of the new package.xml tag - * @param string tag name - * @access private + * WARNING - do not use this function unless you know what you're doing */ - function _insertBefore($array, $keys, $contents, $newkey) + function setRawPackage($package) { - foreach ($keys as $key) { - if (isset($array[$key])) { - return $array = $this->_ksplice($array, $key, $contents, $newkey); - } - } - $array[$newkey] = $contents; - return $array; + $this->_packageInfo['name'] = $package; } /** - * @param subsection of {@link $_packageInfo} - * @param array|string tag contents - * @param array format: - *
-     * array(
-     *   tagname => array(list of tag names that follow this one),
-     *   childtagname => array(list of child tag names that follow this one),
-     * )
-     * 
- * - * This allows construction of nested tags - * @access private + * WARNING - do not use this function unless you know what you're doing */ - function _mergeTag($manip, $contents, $order) + function setRawChannel($channel) { - if (count($order)) { - foreach ($order as $tag => $curorder) { - if (!isset($manip[$tag])) { - // ensure that the tag is set up - $manip = $this->_insertBefore($manip, $curorder, array(), $tag); - } - if (count($order) > 1) { - $manip[$tag] = $this->_mergeTag($manip[$tag], $contents, array_slice($order, 1)); - return $manip; - } - } - } else { - return $manip; - } - if (is_array($manip[$tag]) && !empty($manip[$tag]) && isset($manip[$tag][0])) { - $manip[$tag][] = $contents; - } else { - if (!count($manip[$tag])) { - $manip[$tag] = $contents; - } else { - $manip[$tag] = array($manip[$tag]); - $manip[$tag][] = $contents; - } - } - return $manip; + $this->_packageInfo['channel'] = $channel; } -} -?> -PEAR-1.8.0/PEAR/REST/10.php100664 764 764 100236 100664 7604 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: 10.php,v 1.60 2009/03/07 23:09:56 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a12 - */ -/** - * For downloading REST xml/txt files - */ -require_once 'PEAR/REST.php'; + function setRequestedGroup($group) + { + $this->_requestedGroup = $group; + } -/** - * Implement REST 1.0 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a12 - */ -class PEAR_REST_10 -{ - /** - * @var PEAR_REST - */ - var $_rest; - function PEAR_REST_10($config, $options = array()) + function getRequestedGroup() { - $this->_rest = &new PEAR_REST($config, $options); + if (isset($this->_requestedGroup)) { + return $this->_requestedGroup; + } + return false; } /** - * Retrieve information about a remote package to be downloaded from a REST server + * For saving in the registry. * - * @param string $base The uri to prepend to all REST calls - * @param array $packageinfo an array of format: - *
-     *  array(
-     *   'package' => 'packagename',
-     *   'channel' => 'channelname',
-     *  ['state' => 'alpha' (or valid state),]
-     *  -or-
-     *  ['version' => '1.whatever']
-     * 
- * @param string $prefstate Current preferred_state config variable value - * @param bool $installed the installed version of this package to compare against - * @return array|false|PEAR_Error see {@link _returnDownloadURL()} + * Set the last version that was installed + * @param string */ - function getDownloadURL($base, $packageinfo, $prefstate, $installed, $channel = false) + function setLastInstalledVersion($version) { - $channel = $packageinfo['channel']; - $package = $packageinfo['package']; - $states = $this->betterStates($prefstate, true); - if (!$states) { - return PEAR::raiseError('"' . $prefstate . '" is not a valid state'); - } + $this->_packageInfo['_lastversion'] = $version; + } - $state = isset($packageinfo['state']) ? $packageinfo['state'] : null; - $version = isset($packageinfo['version']) ? $packageinfo['version'] : null; - $info = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . '/allreleases.xml', false, false, $channel); - if (PEAR::isError($info)) { - return PEAR::raiseError('No releases available for package "' . - $channel . '/' . $package . '"'); + /** + * @return string|false + */ + function getLastInstalledVersion() + { + if (isset($this->_packageInfo['_lastversion'])) { + return $this->_packageInfo['_lastversion']; } + return false; + } - if (!isset($info['r'])) { - return false; + /** + * Determines whether this package.xml has post-install scripts or not + * @return array|false + */ + function listPostinstallScripts() + { + $filelist = $this->getFilelist(); + $contents = $this->getContents(); + $contents = $contents['dir']['file']; + if (!is_array($contents) || !isset($contents[0])) { + $contents = array($contents); } - - $release = $found = false; - if (!is_array($info['r']) || !isset($info['r'][0])) { - $info['r'] = array($info['r']); + $taskfiles = array(); + foreach ($contents as $file) { + $atts = $file['attribs']; + unset($file['attribs']); + if (count($file)) { + $taskfiles[$atts['name']] = $file; + } } - - foreach ($info['r'] as $release) { - if (!isset($this->_rest->_options['force']) && ($installed && - version_compare($release['v'], $installed, '<'))) { + $common = new PEAR_Common; + $common->debug = $this->_config->get('verbose'); + $this->_scripts = array(); + $ret = array(); + foreach ($taskfiles as $name => $tasks) { + if (!isset($filelist[$name])) { + // ignored files will not be in the filelist continue; } - - if (isset($state)) { - // try our preferred state first - if ($release['s'] == $state) { - $found = true; - break; - } - // see if there is something newer and more stable - // bug #7221 - if (in_array($release['s'], $this->betterStates($state), true)) { - $found = true; - break; - } - } elseif (isset($version)) { - if ($release['v'] == $version) { - $found = true; - break; - } - } else { - if (in_array($release['s'], $states)) { - $found = true; - break; + $atts = $filelist[$name]; + foreach ($tasks as $tag => $raw) { + $task = $this->getTask($tag); + $task = &new $task($this->_config, $common, PEAR_TASK_INSTALL); + if ($task->isScript()) { + $ret[] = $filelist[$name]['installed_as']; } } } - - return $this->_returnDownloadURL($base, $package, $release, $info, $found, false, $channel); + if (count($ret)) { + return $ret; + } + return false; } - function getDepDownloadURL($base, $xsdversion, $dependency, $deppackage, - $prefstate = 'stable', $installed = false, $channel = false) + /** + * Initialize post-install scripts for running + * + * This method can be used to detect post-install scripts, as the return value + * indicates whether any exist + * @return bool + */ + function initPostinstallScripts() { - $channel = $dependency['channel']; - $package = $dependency['name']; - $states = $this->betterStates($prefstate, true); - if (!$states) { - return PEAR::raiseError('"' . $prefstate . '" is not a valid state'); - } - $state = isset($dependency['state']) ? $dependency['state'] : null; - $version = isset($dependency['version']) ? $dependency['version'] : null; - $info = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . '/allreleases.xml', false, false, $channel); - if (PEAR::isError($info)) { - return PEAR::raiseError('Package "' . $deppackage['channel'] . '/' . $deppackage['package'] - . '" dependency "' . $channel . '/' . $package . '" has no releases'); + $filelist = $this->getFilelist(); + $contents = $this->getContents(); + $contents = $contents['dir']['file']; + if (!is_array($contents) || !isset($contents[0])) { + $contents = array($contents); } - if (!is_array($info) || !isset($info['r'])) { - return false; + $taskfiles = array(); + foreach ($contents as $file) { + $atts = $file['attribs']; + unset($file['attribs']); + if (count($file)) { + $taskfiles[$atts['name']] = $file; + } } - $exclude = array(); - $min = $max = $recommended = false; - if ($xsdversion == '1.0') { - switch ($dependency['rel']) { - case 'ge' : - $min = $dependency['version']; - break; - case 'gt' : - $min = $dependency['version']; - $exclude = array($dependency['version']); - break; - case 'eq' : - $recommended = $dependency['version']; - break; - case 'lt' : - $max = $dependency['version']; - $exclude = array($dependency['version']); - break; - case 'le' : - $max = $dependency['version']; - break; - case 'ne' : - $exclude = array($dependency['version']); - break; + $common = new PEAR_Common; + $common->debug = $this->_config->get('verbose'); + $this->_scripts = array(); + foreach ($taskfiles as $name => $tasks) { + if (!isset($filelist[$name])) { + // file was not installed due to installconditions + continue; } - } else { - $min = isset($dependency['min']) ? $dependency['min'] : false; - $max = isset($dependency['max']) ? $dependency['max'] : false; - $recommended = isset($dependency['recommended']) ? - $dependency['recommended'] : false; - if (isset($dependency['exclude'])) { - if (!isset($dependency['exclude'][0])) { - $exclude = array($dependency['exclude']); + $atts = $filelist[$name]; + foreach ($tasks as $tag => $raw) { + $taskname = $this->getTask($tag); + $task = &new $taskname($this->_config, $common, PEAR_TASK_INSTALL); + if (!$task->isScript()) { + continue; // scripts are only handled after installation + } + $lastversion = isset($this->_packageInfo['_lastversion']) ? + $this->_packageInfo['_lastversion'] : null; + $task->init($raw, $atts, $lastversion); + $res = $task->startSession($this, $atts['installed_as']); + if (!$res) { + continue; // skip this file } + if (PEAR::isError($res)) { + return $res; + } + $assign = &$task; + $this->_scripts[] = &$assign; } } - $release = $found = false; - if (!is_array($info['r']) || !isset($info['r'][0])) { - $info['r'] = array($info['r']); + if (count($this->_scripts)) { + return true; } - foreach ($info['r'] as $release) { - if (!isset($this->_rest->_options['force']) && ($installed && - version_compare($release['v'], $installed, '<'))) { - continue; + return false; + } + + function runPostinstallScripts() + { + if ($this->initPostinstallScripts()) { + $ui = &PEAR_Frontend::singleton(); + if ($ui) { + $ui->runPostinstallScripts($this->_scripts, $this); } - if (in_array($release['v'], $exclude)) { // skip excluded versions - continue; + } + } + + + /** + * Convert a recursive set of and tags into a single tag with + * tags. + */ + function flattenFilelist() + { + if (isset($this->_packageInfo['bundle'])) { + return; + } + $filelist = array(); + if (isset($this->_packageInfo['contents']['dir']['dir'])) { + $this->_getFlattenedFilelist($filelist, $this->_packageInfo['contents']['dir']); + if (!isset($filelist[1])) { + $filelist = $filelist[0]; } - // allow newer releases to say "I'm OK with the dependent package" - if ($xsdversion == '2.0' && isset($release['co'])) { - if (!is_array($release['co']) || !isset($release['co'][0])) { - $release['co'] = array($release['co']); - } - foreach ($release['co'] as $entry) { - if (isset($entry['x']) && !is_array($entry['x'])) { - $entry['x'] = array($entry['x']); - } elseif (!isset($entry['x'])) { - $entry['x'] = array(); - } - if ($entry['c'] == $deppackage['channel'] && - strtolower($entry['p']) == strtolower($deppackage['package']) && - version_compare($deppackage['version'], $entry['min'], '>=') && - version_compare($deppackage['version'], $entry['max'], '<=') && - !in_array($release['v'], $entry['x'])) { - $recommended = $release['v']; - break; + $this->_packageInfo['contents']['dir']['file'] = $filelist; + unset($this->_packageInfo['contents']['dir']['dir']); + } else { + // else already flattened but check for baseinstalldir propagation + if (isset($this->_packageInfo['contents']['dir']['attribs']['baseinstalldir'])) { + if (isset($this->_packageInfo['contents']['dir']['file'][0])) { + foreach ($this->_packageInfo['contents']['dir']['file'] as $i => $file) { + if (isset($file['attribs']['baseinstalldir'])) { + continue; + } + $this->_packageInfo['contents']['dir']['file'][$i]['attribs']['baseinstalldir'] + = $this->_packageInfo['contents']['dir']['attribs']['baseinstalldir']; } - } - } - if ($recommended) { - if ($release['v'] != $recommended) { // if we want a specific - // version, then skip all others - continue; } else { - if (!in_array($release['s'], $states)) { - // the stability is too low, but we must return the - // recommended version if possible - return $this->_returnDownloadURL($base, $package, $release, $info, true, false, $channel); + if (!isset($this->_packageInfo['contents']['dir']['file']['attribs']['baseinstalldir'])) { + $this->_packageInfo['contents']['dir']['file']['attribs']['baseinstalldir'] + = $this->_packageInfo['contents']['dir']['attribs']['baseinstalldir']; } } } - if ($min && version_compare($release['v'], $min, 'lt')) { // skip too old versions - continue; - } - if ($max && version_compare($release['v'], $max, 'gt')) { // skip too new versions - continue; - } - if ($installed && version_compare($release['v'], $installed, '<')) { - continue; - } - if (in_array($release['s'], $states)) { // if in the preferred state... - $found = true; // ... then use it - break; - } } - return $this->_returnDownloadURL($base, $package, $release, $info, $found, false, $channel); } /** - * Take raw data and return the array needed for processing a download URL - * - * @param string $base REST base uri - * @param string $package Package name - * @param array $release an array of format array('v' => version, 's' => state) - * describing the release to download - * @param array $info list of all releases as defined by allreleases.xml - * @param bool|null $found determines whether the release was found or this is the next - * best alternative. If null, then versions were skipped because - * of PHP dependency - * @return array|PEAR_Error - * @access private + * @param array the final flattened file list + * @param array the current directory being processed + * @param string|false any recursively inherited baeinstalldir attribute + * @param string private recursion variable + * @return array + * @access protected */ - function _returnDownloadURL($base, $package, $release, $info, $found, $phpversion = false, $channel = false) + function _getFlattenedFilelist(&$files, $dir, $baseinstall = false, $path = '') { - if (!$found) { - $release = $info['r'][0]; - } - $pinfo = $this->_rest->retrieveCacheFirst($base . 'p/' . strtolower($package) . '/' . - 'info.xml', false, false, $channel); - if (PEAR::isError($pinfo)) { - return PEAR::raiseError('Package "' . $package . - '" does not have REST info xml available'); - } - $releaseinfo = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/' . - $release['v'] . '.xml', false, false, $channel); - if (PEAR::isError($releaseinfo)) { - return PEAR::raiseError('Package "' . $package . '" Version "' . $release['v'] . - '" does not have REST xml available'); - } - $packagexml = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/' . - 'deps.' . $release['v'] . '.txt', false, true, $channel); - if (PEAR::isError($packagexml)) { - return PEAR::raiseError('Package "' . $package . '" Version "' . $release['v'] . - '" does not have REST dependency information available'); - } - - $packagexml = unserialize($packagexml); - if (!$packagexml) { - $packagexml = array(); - } - $allinfo = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . - '/allreleases.xml', false, false, $channel); - if (!is_array($allinfo['r']) || !isset($allinfo['r'][0])) { - $allinfo['r'] = array($allinfo['r']); + if (isset($dir['attribs']) && isset($dir['attribs']['baseinstalldir'])) { + $baseinstall = $dir['attribs']['baseinstalldir']; } - $compatible = false; - foreach ($allinfo['r'] as $release) { - if ($release['v'] != $releaseinfo['v']) { - continue; - } - if (!isset($release['co'])) { - break; - } - $compatible = array(); - if (!is_array($release['co']) || !isset($release['co'][0])) { - $release['co'] = array($release['co']); + if (isset($dir['dir'])) { + if (!isset($dir['dir'][0])) { + $dir['dir'] = array($dir['dir']); } - foreach ($release['co'] as $entry) { - $comp = array(); - $comp['name'] = $entry['p']; - $comp['channel'] = $entry['c']; - $comp['min'] = $entry['min']; - $comp['max'] = $entry['max']; - if (isset($entry['x']) && !is_array($entry['x'])) { - $comp['exclude'] = $entry['x']; + foreach ($dir['dir'] as $subdir) { + if (!isset($subdir['attribs']) || !isset($subdir['attribs']['name'])) { + $name = '*unknown*'; + } else { + $name = $subdir['attribs']['name']; } - $compatible[] = $comp; - } - if (count($compatible) == 1) { - $compatible = $compatible[0]; + $newpath = empty($path) ? $name : + $path . '/' . $name; + $this->_getFlattenedFilelist($files, $subdir, + $baseinstall, $newpath); } - break; } - if (isset($pinfo['dc']) && isset($pinfo['dp'])) { - if (is_array($pinfo['dp'])) { - $deprecated = array('channel' => (string) $pinfo['dc'], - 'package' => trim($pinfo['dp']['_content'])); - } else { - $deprecated = array('channel' => (string) $pinfo['dc'], - 'package' => trim($pinfo['dp'])); + if (isset($dir['file'])) { + if (!isset($dir['file'][0])) { + $dir['file'] = array($dir['file']); + } + foreach ($dir['file'] as $file) { + $attrs = $file['attribs']; + $name = $attrs['name']; + if ($baseinstall && !isset($attrs['baseinstalldir'])) { + $attrs['baseinstalldir'] = $baseinstall; + } + $attrs['name'] = empty($path) ? $name : $path . '/' . $name; + $attrs['name'] = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), + $attrs['name']); + $file['attribs'] = $attrs; + $files[] = $file; } - } else { - $deprecated = false; - } - if ($found) { - return - array('version' => $releaseinfo['v'], - 'info' => $packagexml, - 'package' => $releaseinfo['p']['_content'], - 'stability' => $releaseinfo['st'], - 'url' => $releaseinfo['g'], - 'compatible' => $compatible, - 'deprecated' => $deprecated, - ); - } else { - return - array('version' => $releaseinfo['v'], - 'package' => $releaseinfo['p']['_content'], - 'stability' => $releaseinfo['st'], - 'info' => $packagexml, - 'compatible' => $compatible, - 'deprecated' => $deprecated, - 'php' => $phpversion - ); } } - function listPackages($base, $channel = false) + function setConfig(&$config) { - $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel); - if (PEAR::isError($packagelist)) { - return $packagelist; - } - if (!is_array($packagelist) || !isset($packagelist['p'])) { - return array(); - } - if (!is_array($packagelist['p'])) { - $packagelist['p'] = array($packagelist['p']); + $this->_config = &$config; + $this->_registry = &$config->getRegistry(); + } + + function setLogger(&$logger) + { + if (!is_object($logger) || !method_exists($logger, 'log')) { + return PEAR::raiseError('Logger must be compatible with PEAR_Common::log'); } - return $packagelist['p']; + $this->_logger = &$logger; } /** - * List all categories of a REST server - * - * @param string $base base URL of the server - * @return array of categorynames + * WARNING - do not use this function directly unless you know what you're doing */ - function listCategories($base, $channel = false) + function setDeps($deps) { - $categories = array(); + $this->_packageInfo['dependencies'] = $deps; + } - // c/categories.xml does not exist; - // check for every package its category manually - // This is SLOOOWWWW : /// - $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel); - if (PEAR::isError($packagelist)) { - return $packagelist; - } - if (!is_array($packagelist) || !isset($packagelist['p'])) { - $ret = array(); - return $ret; - } - if (!is_array($packagelist['p'])) { - $packagelist['p'] = array($packagelist['p']); - } + /** + * WARNING - do not use this function directly unless you know what you're doing + */ + function setCompatible($compat) + { + $this->_packageInfo['compatible'] = $compat; + } - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - foreach ($packagelist['p'] as $package) { - $inf = $this->_rest->retrieveData($base . 'p/' . strtolower($package) . '/info.xml', false, false, $channel); - if (PEAR::isError($inf)) { - PEAR::popErrorHandling(); - return $inf; - } - $cat = $inf['ca']['_content']; - if (!isset($categories[$cat])) { - $categories[$cat] = $inf['ca']; - } - } - return array_values($categories); + function setPackagefile($file, $archive = false) + { + $this->_packageFile = $file; + $this->_archiveFile = $archive ? $archive : $file; } /** - * List a category of a REST server - * - * @param string $base base URL of the server - * @param string $category name of the category - * @param boolean $info also download full package info - * @return array of packagenames + * Wrapper to {@link PEAR_ErrorStack::getErrors()} + * @param boolean determines whether to purge the error stack after retrieving + * @return array */ - function listCategory($base, $category, $info = false, $channel = false) + function getValidationWarnings($purge = true) { - // gives '404 Not Found' error when category doesn't exist - $packagelist = $this->_rest->retrieveData($base.'c/'.urlencode($category).'/packages.xml', false, false, $channel); - if (PEAR::isError($packagelist)) { - return $packagelist; - } - if (!is_array($packagelist) || !isset($packagelist['p'])) { - return array(); - } - if (!is_array($packagelist['p']) || - !isset($packagelist['p'][0])) { // only 1 pkg - $packagelist = array($packagelist['p']); - } else { - $packagelist = $packagelist['p']; - } + return $this->_stack->getErrors($purge); + } - if ($info == true) { - // get individual package info - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - foreach ($packagelist as $i => $packageitem) { - $url = sprintf('%s'.'r/%s/latest.txt', - $base, - strtolower($packageitem['_content'])); - $version = $this->_rest->retrieveData($url, false, false, $channel); - if (PEAR::isError($version)) { - break; // skipit - } - $url = sprintf('%s'.'r/%s/%s.xml', - $base, - strtolower($packageitem['_content']), - $version); - $info = $this->_rest->retrieveData($url, false, false, $channel); - if (PEAR::isError($info)) { - break; // skipit - } - $packagelist[$i]['info'] = $info; - } - PEAR::popErrorHandling(); - } + function getPackageFile() + { + return $this->_packageFile; + } - return $packagelist; + function getArchiveFile() + { + return $this->_archiveFile; } - function listAll($base, $dostable, $basic = true, $searchpackage = false, $searchsummary = false, $channel = false) + /** + * Directly set the array that defines this packagefile + * + * WARNING: no validation. This should only be performed by internal methods + * inside PEAR or by inputting an array saved from an existing PEAR_PackageFile_v2 + * @param array + */ + function fromArray($pinfo) { - $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel); - if (PEAR::isError($packagelist)) { - return $packagelist; - } - if ($this->_rest->config->get('verbose') > 0) { - $ui = &PEAR_Frontend::singleton(); - $ui->log('Retrieving data...0%', false); - } - $ret = array(); - if (!is_array($packagelist) || !isset($packagelist['p'])) { - return $ret; - } - if (!is_array($packagelist['p'])) { - $packagelist['p'] = array($packagelist['p']); - } + unset($pinfo['old']); + unset($pinfo['xsdversion']); + $this->_incomplete = false; + $this->_packageInfo = $pinfo; + } - // only search-packagename = quicksearch ! - if ($searchpackage && (!$searchsummary || empty($searchpackage))) { - $newpackagelist = array(); - foreach ($packagelist['p'] as $package) { - if (!empty($searchpackage) && stristr($package, $searchpackage) !== false) { - $newpackagelist[] = $package; - } - } - $packagelist['p'] = $newpackagelist; + function isIncomplete() + { + return $this->_incomplete; + } + + /** + * @return array + */ + function toArray($forreg = false) + { + if (!$this->validate(PEAR_VALIDATE_NORMAL)) { + return false; } - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $next = .1; - foreach ($packagelist['p'] as $progress => $package) { - if ($this->_rest->config->get('verbose') > 0) { - if ($progress / count($packagelist['p']) >= $next) { - if ($next == .5) { - $ui->log('50%', false); - } else { - $ui->log('.', false); - } - $next += .1; - } - } + return $this->getArray($forreg); + } - if ($basic) { // remote-list command - if ($dostable) { - $latest = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . - '/stable.txt', false, false, $channel); - } else { - $latest = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . - '/latest.txt', false, false, $channel); - } - if (PEAR::isError($latest)) { - $latest = false; - } - $info = array('stable' => $latest); - } else { // list-all command - $inf = $this->_rest->retrieveData($base . 'p/' . strtolower($package) . '/info.xml', false, false, $channel); - if (PEAR::isError($inf)) { - PEAR::popErrorHandling(); - return $inf; - } - if ($searchpackage) { - $found = (!empty($searchpackage) && stristr($package, $searchpackage) !== false); - if (!$found && !(isset($searchsummary) && !empty($searchsummary) - && (stristr($inf['s'], $searchsummary) !== false - || stristr($inf['d'], $searchsummary) !== false))) - { - continue; - }; - } - $releases = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . - '/allreleases.xml', false, false, $channel); - if (PEAR::isError($releases)) { - continue; - } - if (!isset($releases['r'][0])) { - $releases['r'] = array($releases['r']); - } - unset($latest); - unset($unstable); - unset($stable); - unset($state); - foreach ($releases['r'] as $release) { - if (!isset($latest)) { - if ($dostable && $release['s'] == 'stable') { - $latest = $release['v']; - $state = 'stable'; - } - if (!$dostable) { - $latest = $release['v']; - $state = $release['s']; - } - } - if (!isset($stable) && $release['s'] == 'stable') { - $stable = $release['v']; - if (!isset($unstable)) { - $unstable = $stable; - } - } - if (!isset($unstable) && $release['s'] != 'stable') { - $latest = $unstable = $release['v']; - $state = $release['s']; - } - if (isset($latest) && !isset($state)) { - $state = $release['s']; - } - if (isset($latest) && isset($stable) && isset($unstable)) { - break; - } - } - $deps = array(); - if (!isset($unstable)) { - $unstable = false; - $state = 'stable'; - if (isset($stable)) { - $latest = $unstable = $stable; - } - } else { - $latest = $unstable; - } - if (!isset($latest)) { - $latest = false; - } - if ($latest) { - $d = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/deps.' . - $latest . '.txt', false, false, $channel); - if (!PEAR::isError($d)) { - $d = unserialize($d); - if ($d) { - if (isset($d['required'])) { - if (!class_exists('PEAR_PackageFile_v2')) { - require_once 'PEAR/PackageFile/v2.php'; - } - if (!isset($pf)) { - $pf = new PEAR_PackageFile_v2; - } - $pf->setDeps($d); - $tdeps = $pf->getDeps(); - } else { - $tdeps = $d; - } - foreach ($tdeps as $dep) { - if ($dep['type'] !== 'pkg') { - continue; - } - $deps[] = $dep; - } - } - } - } - if (!isset($stable)) { - $stable = '-n/a-'; - } - if (!$searchpackage) { - $info = array('stable' => $latest, 'summary' => $inf['s'], 'description' => - $inf['d'], 'deps' => $deps, 'category' => $inf['ca']['_content'], - 'unstable' => $unstable, 'state' => $state); - } else { - $info = array('stable' => $stable, 'summary' => $inf['s'], 'description' => - $inf['d'], 'deps' => $deps, 'category' => $inf['ca']['_content'], - 'unstable' => $unstable, 'state' => $state); - } + function getArray($forReg = false) + { + if ($forReg) { + $arr = $this->_packageInfo; + $arr['old'] = array(); + $arr['old']['version'] = $this->getVersion(); + $arr['old']['release_date'] = $this->getDate(); + $arr['old']['release_state'] = $this->getState(); + $arr['old']['release_license'] = $this->getLicense(); + $arr['old']['release_notes'] = $this->getNotes(); + $arr['old']['release_deps'] = $this->getDeps(); + $arr['old']['maintainers'] = $this->getMaintainers(); + $arr['xsdversion'] = '2.0'; + return $arr; + } else { + $info = $this->_packageInfo; + unset($info['dirtree']); + if (isset($info['_lastversion'])) { + unset($info['_lastversion']); } - $ret[$package] = $info; + if (isset($info['#binarypackage'])) { + unset($info['#binarypackage']); + } + return $info; } - PEAR::popErrorHandling(); - return $ret; } - function listLatestUpgrades($base, $pref_state, $installed, $channel, &$reg) + function packageInfo($field) { - $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel); - if (PEAR::isError($packagelist)) { - return $packagelist; + $arr = $this->getArray(true); + if ($field == 'state') { + return $arr['stability']['release']; } - - $ret = array(); - if (!is_array($packagelist) || !isset($packagelist['p'])) { - return $ret; + if ($field == 'api-version') { + return $arr['version']['api']; } - - if (!is_array($packagelist['p'])) { - $packagelist['p'] = array($packagelist['p']); + if ($field == 'api-state') { + return $arr['stability']['api']; } - - foreach ($packagelist['p'] as $package) { - if (!isset($installed[strtolower($package)])) { - continue; - } - - $inst_version = $reg->packageInfo($package, 'version', $channel); - $inst_state = $reg->packageInfo($package, 'release_state', $channel); - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $info = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . - '/allreleases.xml', false, false, $channel); - PEAR::popErrorHandling(); - if (PEAR::isError($info)) { - continue; // no remote releases - } - - if (!isset($info['r'])) { - continue; + if (isset($arr['old'][$field])) { + if (!is_string($arr['old'][$field])) { + return null; } - - $release = $found = false; - if (!is_array($info['r']) || !isset($info['r'][0])) { - $info['r'] = array($info['r']); + return $arr['old'][$field]; + } + if (isset($arr[$field])) { + if (!is_string($arr[$field])) { + return null; } + return $arr[$field]; + } + return null; + } - // $info['r'] is sorted by version number - usort($info['r'], array($this, '_sortReleasesByVersionNumber')); - foreach ($info['r'] as $release) { - if ($inst_version && version_compare($release['v'], $inst_version, '<=')) { - // not newer than the one installed - break; - } - - // new version > installed version - if (!$pref_state) { - // every state is a good state - $found = true; - break; - } else { - $new_state = $release['s']; - // if new state >= installed state: go - if (in_array($new_state, $this->betterStates($inst_state, true))) { - $found = true; - break; - } else { - // only allow to lower the state of package, - // if new state >= preferred state: go - if (in_array($new_state, $this->betterStates($pref_state, true))) { - $found = true; - break; - } - } - } - } + function getName() + { + return $this->getPackage(); + } - if (!$found) { - continue; - } + function getPackage() + { + if (isset($this->_packageInfo['name'])) { + return $this->_packageInfo['name']; + } + return false; + } - $relinfo = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/' . - $release['v'] . '.xml', false, false, $channel); - if (PEAR::isError($relinfo)) { - return $relinfo; - } + function getChannel() + { + if (isset($this->_packageInfo['uri'])) { + return '__uri'; + } + if (isset($this->_packageInfo['channel'])) { + return strtolower($this->_packageInfo['channel']); + } + return false; + } - $ret[$package] = array( - 'version' => $release['v'], - 'state' => $release['s'], - 'filesize' => $relinfo['f'], - ); + function getUri() + { + if (isset($this->_packageInfo['uri'])) { + return $this->_packageInfo['uri']; } + return false; + } - return $ret; + function getExtends() + { + if (isset($this->_packageInfo['extends'])) { + return $this->_packageInfo['extends']; + } + return false; } - function packageInfo($base, $package, $channel = false) + function getSummary() { - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $pinfo = $this->_rest->retrieveData($base . 'p/' . strtolower($package) . '/info.xml', false, false, $channel); - if (PEAR::isError($pinfo)) { - PEAR::popErrorHandling(); - return PEAR::raiseError('Unknown package: "' . $package . '" in channel "' . $channel . '"' . "\n". 'Debug: ' . - $pinfo->getMessage()); + if (isset($this->_packageInfo['summary'])) { + return $this->_packageInfo['summary']; } + return false; + } - $releases = array(); - $allreleases = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . - '/allreleases.xml', false, false, $channel); - if (!PEAR::isError($allreleases)) { - if (!class_exists('PEAR_PackageFile_v2')) { - require_once 'PEAR/PackageFile/v2.php'; - } + function getDescription() + { + if (isset($this->_packageInfo['description'])) { + return $this->_packageInfo['description']; + } + return false; + } - if (!is_array($allreleases['r']) || !isset($allreleases['r'][0])) { - $allreleases['r'] = array($allreleases['r']); + function getMaintainers($raw = false) + { + if (!isset($this->_packageInfo['lead'])) { + return false; + } + if ($raw) { + $ret = array('lead' => $this->_packageInfo['lead']); + (isset($this->_packageInfo['developer'])) ? + $ret['developer'] = $this->_packageInfo['developer'] :null; + (isset($this->_packageInfo['contributor'])) ? + $ret['contributor'] = $this->_packageInfo['contributor'] :null; + (isset($this->_packageInfo['helper'])) ? + $ret['helper'] = $this->_packageInfo['helper'] :null; + return $ret; + } else { + $ret = array(); + $leads = isset($this->_packageInfo['lead'][0]) ? $this->_packageInfo['lead'] : + array($this->_packageInfo['lead']); + foreach ($leads as $lead) { + $s = $lead; + $s['handle'] = $s['user']; + unset($s['user']); + $s['role'] = 'lead'; + $ret[] = $s; } - - $pf = new PEAR_PackageFile_v2; - foreach ($allreleases['r'] as $release) { - $ds = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/deps.' . - $release['v'] . '.txt', false, false, $channel); - if (PEAR::isError($ds)) { - continue; - } - - if (!isset($latest)) { - $latest = $release['v']; + if (isset($this->_packageInfo['developer'])) { + $leads = isset($this->_packageInfo['developer'][0]) ? + $this->_packageInfo['developer'] : + array($this->_packageInfo['developer']); + foreach ($leads as $maintainer) { + $s = $maintainer; + $s['handle'] = $s['user']; + unset($s['user']); + $s['role'] = 'developer'; + $ret[] = $s; } - - $pf->setDeps(unserialize($ds)); - $ds = $pf->getDeps(); - $info = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) - . '/' . $release['v'] . '.xml', false, false, $channel); - - if (PEAR::isError($info)) { - continue; + } + if (isset($this->_packageInfo['contributor'])) { + $leads = isset($this->_packageInfo['contributor'][0]) ? + $this->_packageInfo['contributor'] : + array($this->_packageInfo['contributor']); + foreach ($leads as $maintainer) { + $s = $maintainer; + $s['handle'] = $s['user']; + unset($s['user']); + $s['role'] = 'contributor'; + $ret[] = $s; } - - $releases[$release['v']] = array( - 'doneby' => $info['m'], - 'license' => $info['l'], - 'summary' => $info['s'], - 'description' => $info['d'], - 'releasedate' => $info['da'], - 'releasenotes' => $info['n'], - 'state' => $release['s'], - 'deps' => $ds ? $ds : array(), - ); } - } else { - $latest = ''; - } - - PEAR::popErrorHandling(); - if (isset($pinfo['dc']) && isset($pinfo['dp'])) { - if (is_array($pinfo['dp'])) { - $deprecated = array('channel' => (string) $pinfo['dc'], - 'package' => trim($pinfo['dp']['_content'])); - } else { - $deprecated = array('channel' => (string) $pinfo['dc'], - 'package' => trim($pinfo['dp'])); + if (isset($this->_packageInfo['helper'])) { + $leads = isset($this->_packageInfo['helper'][0]) ? + $this->_packageInfo['helper'] : + array($this->_packageInfo['helper']); + foreach ($leads as $maintainer) { + $s = $maintainer; + $s['handle'] = $s['user']; + unset($s['user']); + $s['role'] = 'helper'; + $ret[] = $s; + } } - } else { - $deprecated = false; - } - - if (!isset($latest)) { - $latest = ''; + return $ret; } - - return array( - 'name' => $pinfo['n'], - 'channel' => $pinfo['c'], - 'category' => $pinfo['ca']['_content'], - 'stable' => $latest, - 'license' => $pinfo['l'], - 'summary' => $pinfo['s'], - 'description' => $pinfo['d'], - 'releases' => $releases, - 'deprecated' => $deprecated, - ); + return false; } - /** - * Return an array containing all of the states that are more stable than - * or equal to the passed in state - * - * @param string Release state - * @param boolean Determines whether to include $state in the list - * @return false|array False if $state is not a valid release state - */ - function betterStates($state, $include = false) + function getLeads() { - static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable'); - $i = array_search($state, $states); - if ($i === false) { - return false; + if (isset($this->_packageInfo['lead'])) { + return $this->_packageInfo['lead']; } + return false; + } - if ($include) { - $i--; + function getDevelopers() + { + if (isset($this->_packageInfo['developer'])) { + return $this->_packageInfo['developer']; } - - return array_slice($states, $i + 1); + return false; } - /** - * Sort releases by version number - * - * @access private - */ - function _sortReleasesByVersionNumber($a, $b) + function getContributors() { - if (version_compare($a['v'], $b['v'], '=')) { - return 0; + if (isset($this->_packageInfo['contributor'])) { + return $this->_packageInfo['contributor']; } + return false; + } - if (version_compare($a['v'], $b['v'], '>')) { - return -1; + function getHelpers() + { + if (isset($this->_packageInfo['helper'])) { + return $this->_packageInfo['helper']; } + return false; + } - if (version_compare($a['v'], $b['v'], '<')) { - return 1; + function setDate($date) + { + if (!isset($this->_packageInfo['date'])) { + // ensure that the extends tag is set up in the right location + $this->_packageInfo = $this->_insertBefore($this->_packageInfo, + array('time', 'version', + 'stability', 'license', 'notes', 'contents', 'compatible', + 'dependencies', 'providesextension', 'srcpackage', 'srcuri', + 'phprelease', 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease', + 'zendextbinrelease', 'bundle', 'changelog'), array(), 'date'); } + $this->_packageInfo['date'] = $date; + $this->_isValid = 0; } -}PEAR-1.8.0/PEAR/REST/11.php100664 764 764 26471 100664 7575 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: 11.php,v 1.16 2009/02/24 23:39:22 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.3 - */ - -/** - * For downloading REST xml/txt files - */ -require_once 'PEAR/REST.php'; - -/** - * Implement REST 1.1 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.3 - */ -class PEAR_REST_11 -{ - /** - * @var PEAR_REST - */ - var $_rest; - - function PEAR_REST_11($config, $options = array()) - { - $this->_rest = &new PEAR_REST($config, $options); - } - - function listAll($base, $dostable, $basic = true, $searchpackage = false, $searchsummary = false, $channel = false) - { - $categorylist = $this->_rest->retrieveData($base . 'c/categories.xml', false, false, $channel); - if (PEAR::isError($categorylist)) { - return $categorylist; - } - - $ret = array(); - if (!is_array($categorylist['c']) || !isset($categorylist['c'][0])) { - $categorylist['c'] = array($categorylist['c']); - } - - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - - foreach ($categorylist['c'] as $progress => $category) { - $category = $category['_content']; - $packagesinfo = $this->_rest->retrieveData($base . - 'c/' . urlencode($category) . '/packagesinfo.xml', false, false, $channel); - - if (PEAR::isError($packagesinfo)) { - continue; - } - - if (!is_array($packagesinfo) || !isset($packagesinfo['pi'])) { - continue; - } - - if (!is_array($packagesinfo['pi']) || !isset($packagesinfo['pi'][0])) { - $packagesinfo['pi'] = array($packagesinfo['pi']); - } - - foreach ($packagesinfo['pi'] as $packageinfo) { - if (empty($packageinfo)) { - continue; - } - - $info = $packageinfo['p']; - $package = $info['n']; - $releases = isset($packageinfo['a']) ? $packageinfo['a'] : false; - unset($latest); - unset($unstable); - unset($stable); - unset($state); - - if ($releases) { - if (!isset($releases['r'][0])) { - $releases['r'] = array($releases['r']); - } - foreach ($releases['r'] as $release) { - if (!isset($latest)) { - if ($dostable && $release['s'] == 'stable') { - $latest = $release['v']; - $state = 'stable'; - } - if (!$dostable) { - $latest = $release['v']; - $state = $release['s']; - } - } - if (!isset($stable) && $release['s'] == 'stable') { - $stable = $release['v']; - if (!isset($unstable)) { - $unstable = $stable; - } - } - if (!isset($unstable) && $release['s'] != 'stable') { - $unstable = $release['v']; - $state = $release['s']; - } - if (isset($latest) && !isset($state)) { - $state = $release['s']; - } - if (isset($latest) && isset($stable) && isset($unstable)) { - break; - } - } - } - - if ($basic) { // remote-list command - if (!isset($latest)) { - $latest = false; - } - if ($dostable) { - // $state is not set if there are no releases - if (isset($state) && $state == 'stable') { - $ret[$package] = array('stable' => $latest); - } else { - $ret[$package] = array('stable' => '-n/a-'); - } - } else { - $ret[$package] = array('stable' => $latest); - } - continue; - } - - // list-all command - $deps = array(); - if (!isset($unstable)) { - $unstable = false; - $state = 'stable'; - if (isset($stable)) { - $latest = $unstable = $stable; - } - } else { - $latest = $unstable; - } - - if (!isset($latest)) { - $latest = false; - } - - if ($latest && isset($packageinfo['deps'])) { - if (!is_array($packageinfo['deps']) || - !isset($packageinfo['deps'][0])) { - $packageinfo['deps'] = array($packageinfo['deps']); - } - $d = false; - foreach ($packageinfo['deps'] as $dep) { - if ($dep['v'] == $latest) { - $d = unserialize($dep['d']); - } - } - if ($d) { - if (isset($d['required'])) { - if (!class_exists('PEAR_PackageFile_v2')) { - require_once 'PEAR/PackageFile/v2.php'; - } - if (!isset($pf)) { - $pf = new PEAR_PackageFile_v2; - } - $pf->setDeps($d); - $tdeps = $pf->getDeps(); - } else { - $tdeps = $d; - } - foreach ($tdeps as $dep) { - if ($dep['type'] !== 'pkg') { - continue; - } - $deps[] = $dep; - } - } - } - - $info = array('stable' => $latest, 'summary' => $info['s'], - 'description' => - $info['d'], 'deps' => $deps, 'category' => $info['ca']['_content'], - 'unstable' => $unstable, 'state' => $state); - $ret[$package] = $info; - } - } - PEAR::popErrorHandling(); - return $ret; - } - - /** - * List all categories of a REST server - * - * @param string $base base URL of the server - * @return array of categorynames - */ - function listCategories($base, $channel = false) - { - $categorylist = $this->_rest->retrieveData($base . 'c/categories.xml', false, false, $channel); - if (PEAR::isError($categorylist)) { - return $categorylist; - } - if (!is_array($categorylist) || !isset($categorylist['c'])) { - return array(); - } - if (isset($categorylist['c']['_content'])) { - // only 1 category - $categorylist['c'] = array($categorylist['c']); - } - return $categorylist['c']; - } - - /** - * List packages in a category of a REST server - * - * @param string $base base URL of the server - * @param string $category name of the category - * @param boolean $info also download full package info - * @return array of packagenames - */ - function listCategory($base, $category, $info = false, $channel = false) - { - if ($info == false) { - $url = '%s'.'c/%s/packages.xml'; - } else { - $url = '%s'.'c/%s/packagesinfo.xml'; - } - $url = sprintf($url, - $base, - urlencode($category)); - - // gives '404 Not Found' error when category doesn't exist - $packagelist = $this->_rest->retrieveData($url, false, false, $channel); - if (PEAR::isError($packagelist)) { - return $packagelist; - } - if (!is_array($packagelist)) { - return array(); - } - - if ($info == false) { - if (!isset($packagelist['p'])) { - return array(); - } - if (!is_array($packagelist['p']) || - !isset($packagelist['p'][0])) { // only 1 pkg - $packagelist = array($packagelist['p']); - } else { - $packagelist = $packagelist['p']; - } - return $packagelist; - } else { - // info == true - if (!isset($packagelist['pi'])) { - return array(); - } - if (!is_array($packagelist['pi']) || - !isset($packagelist['pi'][0])) { // only 1 pkg - $packagelist_pre = array($packagelist['pi']); - } else { - $packagelist_pre = $packagelist['pi']; - } - - $packagelist = array(); - foreach ($packagelist_pre as $i => $item) { - // compatibility with r/.xml - if (isset($item['a']['r'][0])) { - // multiple releases - $item['p']['v'] = $item['a']['r'][0]['v']; - $item['p']['st'] = $item['a']['r'][0]['s']; - } elseif (isset($item['a'])) { - // first and only release - $item['p']['v'] = $item['a']['r']['v']; - $item['p']['st'] = $item['a']['r']['s']; - } - - $packagelist[$i] = array('attribs' => $item['p']['r'], - '_content' => $item['p']['n'], - 'info' => $item['p']); - } - } - - return $packagelist; - } - - /** - * Return an array containing all of the states that are more stable than - * or equal to the passed in state - * - * @param string Release state - * @param boolean Determines whether to include $state in the list - * @return false|array False if $state is not a valid release state - */ - function betterStates($state, $include = false) - { - static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable'); - $i = array_search($state, $states); - if ($i === false) { - return false; - } - if ($include) { - $i--; - } - return array_slice($states, $i + 1); - } -} -?>PEAR-1.8.0/PEAR/REST/13.php100664 764 764 27117 100664 7575 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: 13.php,v 1.8 2009/02/24 23:39:22 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a12 - */ - -/** - * For downloading REST xml/txt files - */ -require_once 'PEAR/REST.php'; -require_once 'PEAR/REST/10.php'; - -/** - * Implement REST 1.3 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a12 - */ -class PEAR_REST_13 extends PEAR_REST_10 -{ - /** - * Retrieve information about a remote package to be downloaded from a REST server - * - * This is smart enough to resolve the minimum PHP version dependency prior to download - * @param string $base The uri to prepend to all REST calls - * @param array $packageinfo an array of format: - *
-     *  array(
-     *   'package' => 'packagename',
-     *   'channel' => 'channelname',
-     *  ['state' => 'alpha' (or valid state),]
-     *  -or-
-     *  ['version' => '1.whatever']
-     * 
- * @param string $prefstate Current preferred_state config variable value - * @param bool $installed the installed version of this package to compare against - * @return array|false|PEAR_Error see {@link _returnDownloadURL()} - */ - function getDownloadURL($base, $packageinfo, $prefstate, $installed, $channel = false) - { - $channel = $packageinfo['channel']; - $package = $packageinfo['package']; - $states = $this->betterStates($prefstate, true); - if (!$states) { - return PEAR::raiseError('"' . $prefstate . '" is not a valid state'); - } - - $state = isset($packageinfo['state']) ? $packageinfo['state'] : null; - $version = isset($packageinfo['version']) ? $packageinfo['version'] : null; - $info = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . - '/allreleases2.xml'); - if (PEAR::isError($info)) { - return PEAR::raiseError('No releases available for package "' . - $channel . '/' . $package . '"'); - } - - if (!isset($info['r'])) { - return false; - } - - $release = $found = false; - if (!is_array($info['r']) || !isset($info['r'][0])) { - $info['r'] = array($info['r']); - } - - $skippedphp = false; - foreach ($info['r'] as $release) { - if (!isset($this->_rest->_options['force']) && ($installed && - version_compare($release['v'], $installed, '<'))) { - continue; - } - - if (isset($state)) { - // try our preferred state first - if ($release['s'] == $state) { - if (!isset($version) && version_compare($release['m'], phpversion(), '>')) { - // skip releases that require a PHP version newer than our PHP version - $skippedphp = $release; - continue; - } - $found = true; - break; - } - - // see if there is something newer and more stable - // bug #7221 - if (in_array($release['s'], $this->betterStates($state), true)) { - if (!isset($version) && version_compare($release['m'], phpversion(), '>')) { - // skip releases that require a PHP version newer than our PHP version - $skippedphp = $release; - continue; - } - $found = true; - break; - } - } elseif (isset($version)) { - if ($release['v'] == $version) { - if (!isset($this->_rest->_options['force']) && - !isset($version) && - version_compare($release['m'], phpversion(), '>')) { - // skip releases that require a PHP version newer than our PHP version - $skippedphp = $release; - continue; - } - $found = true; - break; - } - } else { - if (in_array($release['s'], $states)) { - if (version_compare($release['m'], phpversion(), '>')) { - // skip releases that require a PHP version newer than our PHP version - $skippedphp = $release; - continue; - } - $found = true; - break; - } - } - } - - if (!$found && $skippedphp) { - $found = null; - } - - return $this->_returnDownloadURL($base, $package, $release, $info, $found, $skippedphp, $channel); - } - - function getDepDownloadURL($base, $xsdversion, $dependency, $deppackage, - $prefstate = 'stable', $installed = false, $channel = false) - { - $channel = $dependency['channel']; - $package = $dependency['name']; - $states = $this->betterStates($prefstate, true); - if (!$states) { - return PEAR::raiseError('"' . $prefstate . '" is not a valid state'); - } - - $state = isset($dependency['state']) ? $dependency['state'] : null; - $version = isset($dependency['version']) ? $dependency['version'] : null; - $info = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . - '/allreleases2.xml'); - if (PEAR::isError($info)) { - return PEAR::raiseError('Package "' . $deppackage['channel'] . '/' . $deppackage['package'] - . '" dependency "' . $channel . '/' . $package . '" has no releases'); - } - - if (!is_array($info) || !isset($info['r'])) { - return false; - } - - $exclude = array(); - $min = $max = $recommended = false; - if ($xsdversion == '1.0') { - $pinfo['package'] = $dependency['name']; - $pinfo['channel'] = 'pear.php.net'; // this is always true - don't change this - switch ($dependency['rel']) { - case 'ge' : - $min = $dependency['version']; - break; - case 'gt' : - $min = $dependency['version']; - $exclude = array($dependency['version']); - break; - case 'eq' : - $recommended = $dependency['version']; - break; - case 'lt' : - $max = $dependency['version']; - $exclude = array($dependency['version']); - break; - case 'le' : - $max = $dependency['version']; - break; - case 'ne' : - $exclude = array($dependency['version']); - break; - } - } else { - $pinfo['package'] = $dependency['name']; - $min = isset($dependency['min']) ? $dependency['min'] : false; - $max = isset($dependency['max']) ? $dependency['max'] : false; - $recommended = isset($dependency['recommended']) ? - $dependency['recommended'] : false; - if (isset($dependency['exclude'])) { - if (!isset($dependency['exclude'][0])) { - $exclude = array($dependency['exclude']); - } - } - } - - $found = false; - $release = false; - $skippedphp = false; - if (!is_array($info['r']) || !isset($info['r'][0])) { - $info['r'] = array($info['r']); - } - - foreach ($info['r'] as $release) { - if (!isset($this->_rest->_options['force']) && ($installed && - version_compare($release['v'], $installed, '<'))) { - continue; - } - - if (in_array($release['v'], $exclude)) { // skip excluded versions - continue; - } - - // allow newer releases to say "I'm OK with the dependent package" - if ($xsdversion == '2.0' && isset($release['co'])) { - if (!is_array($release['co']) || !isset($release['co'][0])) { - $release['co'] = array($release['co']); - } - - foreach ($release['co'] as $entry) { - if (isset($entry['x']) && !is_array($entry['x'])) { - $entry['x'] = array($entry['x']); - } elseif (!isset($entry['x'])) { - $entry['x'] = array(); - } - - if ($entry['c'] == $deppackage['channel'] && - strtolower($entry['p']) == strtolower($deppackage['package']) && - version_compare($deppackage['version'], $entry['min'], '>=') && - version_compare($deppackage['version'], $entry['max'], '<=') && - !in_array($release['v'], $entry['x'])) { - if (version_compare($release['m'], phpversion(), '>')) { - // skip dependency releases that require a PHP version - // newer than our PHP version - $skippedphp = $release; - continue; - } - - $recommended = $release['v']; - break; - } - } - } - - if ($recommended) { - if ($release['v'] != $recommended) { // if we want a specific - // version, then skip all others - continue; - } - - if (!in_array($release['s'], $states)) { - // the stability is too low, but we must return the - // recommended version if possible - return $this->_returnDownloadURL($base, $package, $release, $info, true, false, $channel); - } - } - - if ($min && version_compare($release['v'], $min, 'lt')) { // skip too old versions - continue; - } - - if ($max && version_compare($release['v'], $max, 'gt')) { // skip too new versions - continue; - } - - if ($installed && version_compare($release['v'], $installed, '<')) { - continue; - } - - if (in_array($release['s'], $states)) { // if in the preferred state... - if (version_compare($release['m'], phpversion(), '>')) { - // skip dependency releases that require a PHP version - // newer than our PHP version - $skippedphp = $release; - continue; - } - - $found = true; // ... then use it - break; - } - } - - if (!$found && $skippedphp) { - $found = null; - } - - return $this->_returnDownloadURL($base, $package, $release, $info, $found, $skippedphp, $channel); - } -}PEAR-1.8.0/PEAR/Task/Postinstallscript/rw.php100664 764 764 13314 100664 13662 - read/write version - * - * PHP versions 4 and 5 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: rw.php,v 1.14 2009/02/24 23:45:32 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a10 - */ -/** - * Base class - */ -require_once 'PEAR/Task/Postinstallscript.php'; -/** - * Abstracts the postinstallscript file task xml. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a10 - */ -class PEAR_Task_Postinstallscript_rw extends PEAR_Task_Postinstallscript -{ - /** - * parent package file object - * - * @var PEAR_PackageFile_v2_rw - */ - var $_pkg; - /** - * Enter description here... - * - * @param PEAR_PackageFile_v2_rw $pkg - * @param PEAR_Config $config - * @param PEAR_Frontend $logger - * @param array $fileXml - * @return PEAR_Task_Postinstallscript_rw - */ - function PEAR_Task_Postinstallscript_rw(&$pkg, &$config, &$logger, $fileXml) + + function setTime($time) { - parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE); - $this->_contents = $fileXml; - $this->_pkg = &$pkg; - $this->_params = array(); + $this->_isValid = 0; + if (!isset($this->_packageInfo['time'])) { + // ensure that the time tag is set up in the right location + $this->_packageInfo = $this->_insertBefore($this->_packageInfo, + array('version', + 'stability', 'license', 'notes', 'contents', 'compatible', + 'dependencies', 'providesextension', 'srcpackage', 'srcuri', + 'phprelease', 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease', + 'zendextbinrelease', 'bundle', 'changelog'), $time, 'time'); + } + $this->_packageInfo['time'] = $time; } - function validate() + function getDate() { - return $this->validateXml($this->_pkg, $this->_params, $this->config, $this->_contents); + if (isset($this->_packageInfo['date'])) { + return $this->_packageInfo['date']; + } + return false; } - function getName() + function getTime() { - return 'postinstallscript'; + if (isset($this->_packageInfo['time'])) { + return $this->_packageInfo['time']; + } + return false; } /** - * add a simple to the post-install script - * - * Order is significant, so call this method in the same - * sequence the users should see the paramgroups. The $params - * parameter should either be the result of a call to {@link getParam()} - * or an array of calls to getParam(). - * - * Use {@link addConditionTypeGroup()} to add a containing - * a tag - * @param string $id id as seen by the script - * @param array|false $params array of getParam() calls, or false for no params - * @param string|false $instructions + * @param package|api version category to return */ - function addParamGroup($id, $params = false, $instructions = false) + function getVersion($key = 'release') { - if ($params && isset($params[0]) && !isset($params[1])) { - $params = $params[0]; - } - $stuff = - array( - $this->_pkg->getTasksNs() . ':id' => $id, - ); - if ($instructions) { - $stuff[$this->_pkg->getTasksNs() . ':instructions'] = $instructions; - } - if ($params) { - $stuff[$this->_pkg->getTasksNs() . ':param'] = $params; + if (isset($this->_packageInfo['version'][$key])) { + return $this->_packageInfo['version'][$key]; } - $this->_params[$this->_pkg->getTasksNs() . ':paramgroup'][] = $stuff; + return false; } - /** - * add a complex to the post-install script with conditions - * - * This inserts a with - * - * Order is significant, so call this method in the same - * sequence the users should see the paramgroups. The $params - * parameter should either be the result of a call to {@link getParam()} - * or an array of calls to getParam(). - * - * Use {@link addParamGroup()} to add a simple - * - * @param string $id id as seen by the script - * @param string $oldgroup id of the section referenced by - * - * @param string $param name of the from the older section referenced - * by - * @param string $value value to match of the parameter - * @param string $conditiontype one of '=', '!=', 'preg_match' - * @param array|false $params array of getParam() calls, or false for no params - * @param string|false $instructions - */ - function addConditionTypeGroup($id, $oldgroup, $param, $value, $conditiontype = '=', - $params = false, $instructions = false) + function getStability() { - if ($params && isset($params[0]) && !isset($params[1])) { - $params = $params[0]; - } - $stuff = array( - $this->_pkg->getTasksNs() . ':id' => $id, - ); - if ($instructions) { - $stuff[$this->_pkg->getTasksNs() . ':instructions'] = $instructions; - } - $stuff[$this->_pkg->getTasksNs() . ':name'] = $oldgroup . '::' . $param; - $stuff[$this->_pkg->getTasksNs() . ':conditiontype'] = $conditiontype; - $stuff[$this->_pkg->getTasksNs() . ':value'] = $value; - if ($params) { - $stuff[$this->_pkg->getTasksNs() . ':param'] = $params; + if (isset($this->_packageInfo['stability'])) { + return $this->_packageInfo['stability']; } - $this->_params[$this->_pkg->getTasksNs() . ':paramgroup'][] = $stuff; + return false; } - function getXml() + function getState($key = 'release') { - return $this->_params; + if (isset($this->_packageInfo['stability'][$key])) { + return $this->_packageInfo['stability'][$key]; + } + return false; } - /** - * Use to set up a param tag for use in creating a paramgroup - * @static - */ - function getParam($name, $prompt, $type = 'string', $default = null) + function getLicense($raw = false) { - if ($default !== null) { - return - array( - $this->_pkg->getTasksNs() . ':name' => $name, - $this->_pkg->getTasksNs() . ':prompt' => $prompt, - $this->_pkg->getTasksNs() . ':type' => $type, - $this->_pkg->getTasksNs() . ':default' => $default - ); + if (isset($this->_packageInfo['license'])) { + if ($raw) { + return $this->_packageInfo['license']; + } + if (is_array($this->_packageInfo['license'])) { + return $this->_packageInfo['license']['_content']; + } else { + return $this->_packageInfo['license']; + } } - return - array( - $this->_pkg->getTasksNs() . ':name' => $name, - $this->_pkg->getTasksNs() . ':prompt' => $prompt, - $this->_pkg->getTasksNs() . ':type' => $type, - ); + return false; } -} -?>PEAR-1.8.0/PEAR/Task/Replace/rw.php100664 764 764 3213 100664 11451 - read/write version - * - * PHP versions 4 and 5 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: rw.php,v 1.5 2009/02/24 23:45:44 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a10 - */ -/** - * Base class - */ -require_once 'PEAR/Task/Replace.php'; -/** - * Abstracts the replace task xml. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a10 - */ -class PEAR_Task_Replace_rw extends PEAR_Task_Replace -{ - function PEAR_Task_Replace_rw(&$pkg, &$config, &$logger, $fileXml) - { - parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE); - $this->_contents = $fileXml; - $this->_pkg = &$pkg; - $this->_params = array(); - } - - function validate() - { - return $this->validateXml($this->_pkg, $this->_params, $this->config, $this->_contents); - } - - function setInfo($from, $to, $type) - { - $this->_params = array('attribs' => array('from' => $from, 'to' => $to, 'type' => $type)); - } - - function getName() - { - return 'replace'; - } - - function getXml() - { - return $this->_params; - } -} -?>PEAR-1.8.0/PEAR/Task/Unixeol/rw.php100664 764 764 2626 100664 11530 - read/write version - * - * PHP versions 4 and 5 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: rw.php,v 1.6 2009/02/24 23:45:30 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a10 - */ -/** - * Base class - */ -require_once 'PEAR/Task/Unixeol.php'; -/** - * Abstracts the unixeol task xml. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a10 - */ -class PEAR_Task_Unixeol_rw extends PEAR_Task_Unixeol -{ - function PEAR_Task_Unixeol_rw(&$pkg, &$config, &$logger, $fileXml) - { - parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE); - $this->_contents = $fileXml; - $this->_pkg = &$pkg; - $this->_params = array(); - } - - function validate() - { - return true; - } - - function getName() - { - return 'unixeol'; - } - - function getXml() - { - return ''; - } -} -?>PEAR-1.8.0/PEAR/Task/Windowseol/rw.php100664 764 764 2653 100664 12237 - read/write version - * - * PHP versions 4 and 5 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: rw.php,v 1.6 2009/02/24 23:45:20 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a10 - */ -/** - * Base class - */ -require_once 'PEAR/Task/Windowseol.php'; -/** - * Abstracts the windowseol task xml. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a10 - */ -class PEAR_Task_Windowseol_rw extends PEAR_Task_Windowseol -{ - function PEAR_Task_Windowseol_rw(&$pkg, &$config, &$logger, $fileXml) - { - parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE); - $this->_contents = $fileXml; - $this->_pkg = &$pkg; - $this->_params = array(); - } - - function validate() - { - return true; - } - - function getName() - { - return 'windowseol'; - } - - function getXml() - { - return ''; - } -} -?>PEAR-1.8.0/PEAR/Task/Common.php100664 764 764 13741 100664 10725 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Common.php,v 1.20 2009/02/25 00:15:49 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/**#@+ - * Error codes for task validation routines - */ -define('PEAR_TASK_ERROR_NOATTRIBS', 1); -define('PEAR_TASK_ERROR_MISSING_ATTRIB', 2); -define('PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE', 3); -define('PEAR_TASK_ERROR_INVALID', 4); -/**#@-*/ -define('PEAR_TASK_PACKAGE', 1); -define('PEAR_TASK_INSTALL', 2); -define('PEAR_TASK_PACKAGEANDINSTALL', 3); -/** - * A task is an operation that manipulates the contents of a file. - * - * Simple tasks operate on 1 file. Multiple tasks are executed after all files have been - * processed and installed, and are designed to operate on all files containing the task. - * The Post-install script task simply takes advantage of the fact that it will be run - * after installation, replace is a simple task. - * - * Combining tasks is possible, but ordering is significant. - * - * - * - * - * - * - * This will first replace any instance of @data-dir@ in the test.php file - * with the path to the current data directory. Then, it will include the - * test.php file and run the script it contains to configure the package post-installation. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - * @abstract - */ -class PEAR_Task_Common -{ - /** - * Valid types for this version are 'simple' and 'multiple' - * - * - simple tasks operate on the contents of a file and write out changes to disk - * - multiple tasks operate on the contents of many files and write out the - * changes directly to disk - * - * Child task classes must override this property. - * @access protected - */ - var $type = 'simple'; - /** - * Determines which install phase this task is executed under - */ - var $phase = PEAR_TASK_INSTALL; - /** - * @access protected - */ - var $config; - /** - * @access protected - */ - var $registry; - /** - * @access protected - */ - var $logger; - /** - * @access protected - */ - var $installphase; - /** - * @param PEAR_Config - * @param PEAR_Common - */ - function PEAR_Task_Common(&$config, &$logger, $phase) + + function getLicenseLocation() { - $this->config = &$config; - $this->registry = &$config->getRegistry(); - $this->logger = &$logger; - $this->installphase = $phase; - if ($this->type == 'multiple') { - $GLOBALS['_PEAR_TASK_POSTINSTANCES'][get_class($this)][] = &$this; + if (!isset($this->_packageInfo['license']) || !is_array($this->_packageInfo['license'])) { + return false; } + return $this->_packageInfo['license']['attribs']; } - /** - * Validate the basic contents of a task tag. - * @param PEAR_PackageFile_v2 - * @param array - * @param PEAR_Config - * @param array the entire parsed tag - * @return true|array On error, return an array in format: - * array(PEAR_TASK_ERROR_???[, param1][, param2][, ...]) - * - * For PEAR_TASK_ERROR_MISSING_ATTRIB, pass the attribute name in - * For PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, pass the attribute name and an array - * of legal values in - * @static - * @abstract - */ - function validateXml($pkg, $xml, $config, $fileXml) + function getNotes() { + if (isset($this->_packageInfo['notes'])) { + return $this->_packageInfo['notes']; + } + return false; } /** - * Initialize a task instance with the parameters - * @param array raw, parsed xml - * @param array attributes from the tag containing this task - * @param string|null last installed version of this package - * @abstract + * Return the tag contents, if any + * @return array|false */ - function init($xml, $fileAttributes, $lastVersion) + function getUsesrole() { + if (isset($this->_packageInfo['usesrole'])) { + return $this->_packageInfo['usesrole']; + } + return false; } /** - * Begin a task processing session. All multiple tasks will be processed after each file - * has been successfully installed, all simple tasks should perform their task here and - * return any errors using the custom throwError() method to allow forward compatibility - * - * This method MUST NOT write out any changes to disk - * @param PEAR_PackageFile_v2 - * @param string file contents - * @param string the eventual final file location (informational only) - * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail - * (use $this->throwError), otherwise return the new contents - * @abstract + * Return the tag contents, if any + * @return array|false */ - function startSession($pkg, $contents, $dest) + function getUsestask() { + if (isset($this->_packageInfo['usestask'])) { + return $this->_packageInfo['usestask']; + } + return false; } /** - * This method is used to process each of the tasks for a particular multiple class - * type. Simple tasks need not implement this method. - * @param array an array of tasks - * @access protected - * @static - * @abstract + * This should only be used to retrieve filenames and install attributes */ - function run($tasks) + function getFilelist($preserve = false) { + if (isset($this->_packageInfo['filelist']) && !$preserve) { + return $this->_packageInfo['filelist']; + } + $this->flattenFilelist(); + if ($contents = $this->getContents()) { + $ret = array(); + if (!isset($contents['dir'])) { + return false; + } + if (!isset($contents['dir']['file'][0])) { + $contents['dir']['file'] = array($contents['dir']['file']); + } + foreach ($contents['dir']['file'] as $file) { + $name = $file['attribs']['name']; + if (!$preserve) { + $file = $file['attribs']; + } + $ret[$name] = $file; + } + if (!$preserve) { + $this->_packageInfo['filelist'] = $ret; + } + return $ret; + } + return false; } /** - * @static - * @final + * Return configure options array, if any + * + * @return array|false */ - function hasPostinstallTasks() + function getConfigureOptions() { - return isset($GLOBALS['_PEAR_TASK_POSTINSTANCES']); - } + if ($this->getPackageType() != 'extsrc' && $this->getPackageType() != 'zendextsrc') { + return false; + } - /** - * @static - * @final - */ - function runPostinstallTasks() - { - foreach ($GLOBALS['_PEAR_TASK_POSTINSTANCES'] as $class => $tasks) { - $err = call_user_func(array($class, 'run'), - $GLOBALS['_PEAR_TASK_POSTINSTANCES'][$class]); - if ($err) { - return PEAR_Task_Common::throwError($err); - } - } - unset($GLOBALS['_PEAR_TASK_POSTINSTANCES']); + $releases = $this->getReleases(); + if (isset($releases[0])) { + $releases = $releases[0]; + } + + if (isset($releases['configureoption'])) { + if (!isset($releases['configureoption'][0])) { + $releases['configureoption'] = array($releases['configureoption']); + } + + for ($i = 0; $i < count($releases['configureoption']); $i++) { + $releases['configureoption'][$i] = $releases['configureoption'][$i]['attribs']; + } + + return $releases['configureoption']; + } + + return false; } /** - * Determines whether a role is a script - * @return bool + * This is only used at install-time, after all serialization + * is over. */ - function isScript() + function resetFilelist() { - return $this->type == 'script'; + $this->_packageInfo['filelist'] = array(); } - function throwError($msg, $code = -1) + /** + * Retrieve a list of files that should be installed on this computer + * @return array + */ + function getInstallationFilelist($forfilecheck = false) { - include_once 'PEAR.php'; - return PEAR::raiseError($msg, $code); - } -} -?>PEAR-1.8.0/PEAR/Task/Postinstallscript.php100664 764 764 34125 100664 13235 - * - * PHP versions 4 and 5 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Postinstallscript.php,v 1.22 2009/02/24 23:45:56 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * Base class - */ -require_once 'PEAR/Task/Common.php'; -/** - * Implements the postinstallscript file task. - * - * Note that post-install scripts are handled separately from installation, by the - * "pear run-scripts" command - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Task_Postinstallscript extends PEAR_Task_Common -{ - var $type = 'script'; - var $_class; - var $_params; - var $_obj; - /** - * - * @var PEAR_PackageFile_v2 - */ - var $_pkg; - var $_contents; - var $phase = PEAR_TASK_INSTALL; - - /** - * Validate the raw xml at parsing-time. - * - * This also attempts to validate the script to make sure it meets the criteria - * for a post-install script - * @param PEAR_PackageFile_v2 - * @param array The XML contents of the tag - * @param PEAR_Config - * @param array the entire parsed tag - * @static - */ - function validateXml($pkg, $xml, $config, $fileXml) - { - if ($fileXml['role'] != 'php') { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" must be role="php"'); - } - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $file = $pkg->getFileContents($fileXml['name']); - if (PEAR::isError($file)) { - PEAR::popErrorHandling(); - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" is not valid: ' . - $file->getMessage()); - } elseif ($file === null) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" could not be retrieved for processing!'); - } else { - $analysis = $pkg->analyzeSourceCode($file, true); - if (!$analysis) { - PEAR::popErrorHandling(); - $warnings = ''; - foreach ($pkg->getValidationWarnings() as $warn) { - $warnings .= $warn['message'] . "\n"; - } - return array(PEAR_TASK_ERROR_INVALID, 'Analysis of post-install script "' . - $fileXml['name'] . '" failed: ' . $warnings); - } - if (count($analysis['declared_classes']) != 1) { - PEAR::popErrorHandling(); - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" must declare exactly 1 class'); - } - $class = $analysis['declared_classes'][0]; - if ($class != str_replace(array('/', '.php'), array('_', ''), - $fileXml['name']) . '_postinstall') { - PEAR::popErrorHandling(); - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" class "' . $class . '" must be named "' . - str_replace(array('/', '.php'), array('_', ''), - $fileXml['name']) . '_postinstall"'); - } - if (!isset($analysis['declared_methods'][$class])) { - PEAR::popErrorHandling(); - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" must declare methods init() and run()'); - } - $methods = array('init' => 0, 'run' => 1); - foreach ($analysis['declared_methods'][$class] as $method) { - if (isset($methods[$method])) { - unset($methods[$method]); - } - } - if (count($methods)) { - PEAR::popErrorHandling(); - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" must declare methods init() and run()'); - } + $contents = $this->getFilelist(true); + if (isset($contents['dir']['attribs']['baseinstalldir'])) { + $base = $contents['dir']['attribs']['baseinstalldir']; } - PEAR::popErrorHandling(); - $definedparams = array(); - $tasksNamespace = $pkg->getTasksNs() . ':'; - if (!isset($xml[$tasksNamespace . 'paramgroup']) && isset($xml['paramgroup'])) { - // in order to support the older betas, which did not expect internal tags - // to also use the namespace - $tasksNamespace = ''; + if (isset($this->_packageInfo['bundle'])) { + return PEAR::raiseError( + 'Exception: bundles should be handled in download code only'); } - if (isset($xml[$tasksNamespace . 'paramgroup'])) { - $params = $xml[$tasksNamespace . 'paramgroup']; - if (!is_array($params) || !isset($params[0])) { - $params = array($params); - } - foreach ($params as $param) { - if (!isset($param[$tasksNamespace . 'id'])) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" must have ' . - 'an ' . $tasksNamespace . 'id> tag'); - } - if (isset($param[$tasksNamespace . 'name'])) { - if (!in_array($param[$tasksNamespace . 'name'], $definedparams)) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" ' . $tasksNamespace . - 'paramgroup> id "' . $param[$tasksNamespace . 'id'] . - '" parameter "' . $param[$tasksNamespace . 'name'] . - '" has not been previously defined'); - } - if (!isset($param[$tasksNamespace . 'conditiontype'])) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" ' . $tasksNamespace . - 'paramgroup> id "' . $param[$tasksNamespace . 'id'] . - '" must have a ' . $tasksNamespace . - 'conditiontype> tag containing either "=", ' . - '"!=", or "preg_match"'); - } - if (!in_array($param[$tasksNamespace . 'conditiontype'], - array('=', '!=', 'preg_match'))) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" ' . $tasksNamespace . - 'paramgroup> id "' . $param[$tasksNamespace . 'id'] . - '" must have a ' . $tasksNamespace . - 'conditiontype> tag containing either "=", ' . - '"!=", or "preg_match"'); - } - if (!isset($param[$tasksNamespace . 'value'])) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" ' . $tasksNamespace . - 'paramgroup> id "' . $param[$tasksNamespace . 'id'] . - '" must have a ' . $tasksNamespace . - 'value> tag containing expected parameter value'); + $release = $this->getReleases(); + if ($release) { + if (!isset($release[0])) { + if (!isset($release['installconditions']) && !isset($release['filelist'])) { + if ($forfilecheck) { + return $this->getFilelist(); } + return $contents; } - if (isset($param[$tasksNamespace . 'instructions'])) { - if (!is_string($param[$tasksNamespace . 'instructions'])) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" ' . $tasksNamespace . - 'paramgroup> id "' . $param[$tasksNamespace . 'id'] . - '" ' . $tasksNamespace . 'instructions> must be simple text'); + $release = array($release); + } + $depchecker = &$this->getPEARDependency2($this->_config, array(), + array('channel' => $this->getChannel(), 'package' => $this->getPackage()), + PEAR_VALIDATE_INSTALLING); + foreach ($release as $instance) { + if (isset($instance['installconditions'])) { + $installconditions = $instance['installconditions']; + if (is_array($installconditions)) { + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + foreach ($installconditions as $type => $conditions) { + if (!isset($conditions[0])) { + $conditions = array($conditions); + } + foreach ($conditions as $condition) { + $ret = $depchecker->{"validate{$type}Dependency"}($condition); + if (PEAR::isError($ret)) { + PEAR::popErrorHandling(); + continue 3; // skip this release + } + } + } + PEAR::popErrorHandling(); } } - if (!isset($param[$tasksNamespace . 'param'])) { - continue; // is no longer required - } - $subparams = $param[$tasksNamespace . 'param']; - if (!is_array($subparams) || !isset($subparams[0])) { - $subparams = array($subparams); - } - foreach ($subparams as $subparam) { - if (!isset($subparam[$tasksNamespace . 'name'])) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" parameter for ' . - $tasksNamespace . 'paramgroup> id "' . - $param[$tasksNamespace . 'id'] . '" must have ' . - 'a ' . $tasksNamespace . 'name> tag'); - } - if (!preg_match('/[a-zA-Z0-9]+/', - $subparam[$tasksNamespace . 'name'])) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" parameter "' . - $subparam[$tasksNamespace . 'name'] . - '" for ' . $tasksNamespace . 'paramgroup> id "' . - $param[$tasksNamespace . 'id'] . - '" is not a valid name. Must contain only alphanumeric characters'); + // this is the release to use + if (isset($instance['filelist'])) { + // ignore files + if (isset($instance['filelist']['ignore'])) { + $ignore = isset($instance['filelist']['ignore'][0]) ? + $instance['filelist']['ignore'] : + array($instance['filelist']['ignore']); + foreach ($ignore as $ig) { + unset ($contents[$ig['attribs']['name']]); + } } - if (!isset($subparam[$tasksNamespace . 'prompt'])) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" parameter "' . - $subparam[$tasksNamespace . 'name'] . - '" for ' . $tasksNamespace . 'paramgroup> id "' . - $param[$tasksNamespace . 'id'] . - '" must have a ' . $tasksNamespace . 'prompt> tag'); + // install files as this name + if (isset($instance['filelist']['install'])) { + $installas = isset($instance['filelist']['install'][0]) ? + $instance['filelist']['install'] : + array($instance['filelist']['install']); + foreach ($installas as $as) { + $contents[$as['attribs']['name']]['attribs']['install-as'] = + $as['attribs']['as']; + } } - if (!isset($subparam[$tasksNamespace . 'type'])) { - return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . - $fileXml['name'] . '" parameter "' . - $subparam[$tasksNamespace . 'name'] . - '" for ' . $tasksNamespace . 'paramgroup> id "' . - $param[$tasksNamespace . 'id'] . - '" must have a ' . $tasksNamespace . 'type> tag'); + } + if ($forfilecheck) { + foreach ($contents as $file => $attrs) { + $contents[$file] = $attrs['attribs']; } - $definedparams[] = $param[$tasksNamespace . 'id'] . '::' . - $subparam[$tasksNamespace . 'name']; } + return $contents; + } + } else { // simple release - no installconditions or install-as + if ($forfilecheck) { + return $this->getFilelist(); } + return $contents; } - return true; + // no releases matched + return PEAR::raiseError('No releases in package.xml matched the existing operating ' . + 'system, extensions installed, or architecture, cannot install'); } /** - * Initialize a task instance with the parameters - * @param array raw, parsed xml - * @param array attributes from the tag containing this task - * @param string|null last installed version of this package, if any (useful for upgrades) + * This is only used at install-time, after all serialization + * is over. + * @param string file name + * @param string installed path */ - function init($xml, $fileattribs, $lastversion) + function setInstalledAs($file, $path) { - $this->_class = str_replace('/', '_', $fileattribs['name']); - $this->_filename = $fileattribs['name']; - $this->_class = str_replace ('.php', '', $this->_class) . '_postinstall'; - $this->_params = $xml; - $this->_lastversion = $lastversion; + if ($path) { + return $this->_packageInfo['filelist'][$file]['installed_as'] = $path; + } + unset($this->_packageInfo['filelist'][$file]['installed_as']); } - /** - * Strip the tasks: namespace from internal params - * - * @access private - */ - function _stripNamespace($params = null) + function getInstalledLocation($file) { - if ($params === null) { - $params = array(); - if (!is_array($this->_params)) { - return; - } - foreach ($this->_params as $i => $param) { - if (is_array($param)) { - $param = $this->_stripNamespace($param); - } - $params[str_replace($this->_pkg->getTasksNs() . ':', '', $i)] = $param; - } - $this->_params = $params; - } else { - $newparams = array(); - foreach ($params as $i => $param) { - if (is_array($param)) { - $param = $this->_stripNamespace($param); - } - $newparams[str_replace($this->_pkg->getTasksNs() . ':', '', $i)] = $param; - } - return $newparams; + if (isset($this->_packageInfo['filelist'][$file]['installed_as'])) { + return $this->_packageInfo['filelist'][$file]['installed_as']; } + return false; } /** - * Unlike other tasks, the installed file name is passed in instead of the file contents, - * because this task is handled post-installation - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @param string file name - * @return bool|PEAR_Error false to skip this file, PEAR_Error to fail - * (use $this->throwError) + * This is only used at install-time, after all serialization + * is over. */ - function startSession($pkg, $contents) + function installedFile($file, $atts) { - if ($this->installphase != PEAR_TASK_INSTALL) { - return false; - } - // remove the tasks: namespace if present - $this->_pkg = $pkg; - $this->_stripNamespace(); - $this->logger->log(0, 'Including external post-installation script "' . - $contents . '" - any errors are in this script'); - include_once $contents; - if (class_exists($this->_class)) { - $this->logger->log(0, 'Inclusion succeeded'); - } else { - return $this->throwError('init of post-install script class "' . $this->_class - . '" failed'); - } - $this->_obj = new $this->_class; - $this->logger->log(1, 'running post-install script "' . $this->_class . '->init()"'); - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $res = $this->_obj->init($this->config, $pkg, $this->_lastversion); - PEAR::popErrorHandling(); - if ($res) { - $this->logger->log(0, 'init succeeded'); + if (isset($this->_packageInfo['filelist'][$file])) { + $this->_packageInfo['filelist'][$file] = + array_merge($this->_packageInfo['filelist'][$file], $atts['attribs']); } else { - return $this->throwError('init of post-install script "' . $this->_class . - '->init()" failed'); + $this->_packageInfo['filelist'][$file] = $atts['attribs']; } - $this->_contents = $contents; - return true; } /** - * No longer used - * @see PEAR_PackageFile_v2::runPostinstallScripts() - * @param array an array of tasks - * @param string install or upgrade - * @access protected - * @static + * Retrieve the contents tag */ - function run() + function getContents() { + if (isset($this->_packageInfo['contents'])) { + return $this->_packageInfo['contents']; + } + return false; } -} -?>PEAR-1.8.0/PEAR/Task/Replace.php100664 764 764 15235 100664 11050 - * - * PHP versions 4 and 5 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Replace.php,v 1.19 2009/02/25 00:15:49 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * Base class - */ -require_once 'PEAR/Task/Common.php'; -/** - * Implements the replace file task. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Task_Replace extends PEAR_Task_Common -{ - var $type = 'simple'; - var $phase = PEAR_TASK_PACKAGEANDINSTALL; - var $_replacements; /** - * Validate the raw xml at parsing-time. - * @param PEAR_PackageFile_v2 - * @param array raw, parsed xml - * @param PEAR_Config - * @static + * @param string full path to file + * @param string attribute name + * @param string attribute value + * @param int risky but fast - use this to choose a file based on its position in the list + * of files. Index is zero-based like PHP arrays. + * @return bool success of operation */ - function validateXml($pkg, $xml, $config, $fileXml) + function setFileAttribute($filename, $attr, $value, $index = false) { - if (!isset($xml['attribs'])) { - return array(PEAR_TASK_ERROR_NOATTRIBS); + $this->_isValid = 0; + if (in_array($attr, array('role', 'name', 'baseinstalldir'))) { + $this->_filesValid = false; } - if (!isset($xml['attribs']['type'])) { - return array(PEAR_TASK_ERROR_MISSING_ATTRIB, 'type'); + if ($index !== false && + isset($this->_packageInfo['contents']['dir']['file'][$index]['attribs'])) { + $this->_packageInfo['contents']['dir']['file'][$index]['attribs'][$attr] = $value; + return true; } - if (!isset($xml['attribs']['to'])) { - return array(PEAR_TASK_ERROR_MISSING_ATTRIB, 'to'); + if (!isset($this->_packageInfo['contents']['dir']['file'])) { + return false; } - if (!isset($xml['attribs']['from'])) { - return array(PEAR_TASK_ERROR_MISSING_ATTRIB, 'from'); + $files = $this->_packageInfo['contents']['dir']['file']; + if (!isset($files[0])) { + $files = array($files); + $ind = false; + } else { + $ind = true; } - if ($xml['attribs']['type'] == 'pear-config') { - if (!in_array($xml['attribs']['to'], $config->getKeys())) { - return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'to', $xml['attribs']['to'], - $config->getKeys()); - } - } elseif ($xml['attribs']['type'] == 'php-const') { - if (defined($xml['attribs']['to'])) { - return true; - } else { - return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'to', $xml['attribs']['to'], - array('valid PHP constant')); - } - } elseif ($xml['attribs']['type'] == 'package-info') { - if (in_array($xml['attribs']['to'], - array('name', 'summary', 'channel', 'notes', 'extends', 'description', - 'release_notes', 'license', 'release-license', 'license-uri', - 'version', 'api-version', 'state', 'api-state', 'release_date', - 'date', 'time'))) { - return true; - } else { - return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'to', $xml['attribs']['to'], - array('name', 'summary', 'channel', 'notes', 'extends', 'description', - 'release_notes', 'license', 'release-license', 'license-uri', - 'version', 'api-version', 'state', 'api-state', 'release_date', - 'date', 'time')); + foreach ($files as $i => $file) { + if (isset($file['attribs'])) { + if ($file['attribs']['name'] == $filename) { + if ($ind) { + $this->_packageInfo['contents']['dir']['file'][$i]['attribs'][$attr] = $value; + } else { + $this->_packageInfo['contents']['dir']['file']['attribs'][$attr] = $value; + } + return true; + } } - } else { - return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'type', $xml['attribs']['type'], - array('pear-config', 'package-info', 'php-const')); } - return true; + return false; } - /** - * Initialize a task instance with the parameters - * @param array raw, parsed xml - * @param unused - */ - function init($xml, $attribs) + function setDirtree($path) { - $this->_replacements = isset($xml['attribs']) ? array($xml) : $xml; + if (!isset($this->_packageInfo['dirtree'])) { + $this->_packageInfo['dirtree'] = array(); + } + $this->_packageInfo['dirtree'][$path] = true; } - /** - * Do a package.xml 1.0 replacement, with additional package-info fields available - * - * See validateXml() source for the complete list of allowed fields - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @param string file contents - * @param string the eventual final file location (informational only) - * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail - * (use $this->throwError), otherwise return the new contents - */ - function startSession($pkg, $contents, $dest) + function getDirtree() { - $subst_from = $subst_to = array(); - foreach ($this->_replacements as $a) { - $a = $a['attribs']; - $to = ''; - if ($a['type'] == 'pear-config') { - if ($this->installphase == PEAR_TASK_PACKAGE) { - return false; - } - if ($a['to'] == 'master_server') { - $chan = $this->registry->getChannel($pkg->getChannel()); - if (!PEAR::isError($chan)) { - $to = $chan->getServer(); - } else { - $this->logger->log(0, "$dest: invalid pear-config replacement: $a[to]"); - return false; - } - } else { - if ($this->config->isDefinedLayer('ftp')) { - // try the remote config file first - $to = $this->config->get($a['to'], 'ftp', $pkg->getChannel()); - if (is_null($to)) { - // then default to local - $to = $this->config->get($a['to'], null, $pkg->getChannel()); - } - } else { - $to = $this->config->get($a['to'], null, $pkg->getChannel()); - } - } - if (is_null($to)) { - $this->logger->log(0, "$dest: invalid pear-config replacement: $a[to]"); - return false; - } - } elseif ($a['type'] == 'php-const') { - if ($this->installphase == PEAR_TASK_PACKAGE) { - return false; - } - if (defined($a['to'])) { - $to = constant($a['to']); - } else { - $this->logger->log(0, "$dest: invalid php-const replacement: $a[to]"); - return false; - } - } else { - if ($t = $pkg->packageInfo($a['to'])) { - $to = $t; - } else { - $this->logger->log(0, "$dest: invalid package-info replacement: $a[to]"); - return false; - } - } - if (!is_null($to)) { - $subst_from[] = $a['from']; - $subst_to[] = $to; - } - } - $this->logger->log(3, "doing " . sizeof($subst_from) . - " substitution(s) for $dest"); - if (sizeof($subst_from)) { - $contents = str_replace($subst_from, $subst_to, $contents); + if (isset($this->_packageInfo['dirtree']) && count($this->_packageInfo['dirtree'])) { + return $this->_packageInfo['dirtree']; } - return $contents; + return false; } -} -?>PEAR-1.8.0/PEAR/Task/Unixeol.php100664 764 764 4344 100664 11077 - * - * PHP versions 4 and 5 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Unixeol.php,v 1.12 2009/02/25 00:15:49 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * Base class - */ -require_once 'PEAR/Task/Common.php'; -/** - * Implements the unix line endings file task. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Task_Unixeol extends PEAR_Task_Common -{ - var $type = 'simple'; - var $phase = PEAR_TASK_PACKAGE; - var $_replacements; - /** - * Validate the raw xml at parsing-time. - * @param PEAR_PackageFile_v2 - * @param array raw, parsed xml - * @param PEAR_Config - * @static - */ - function validateXml($pkg, $xml, $config, $fileXml) + function resetDirtree() { - if ($xml != '') { - return array(PEAR_TASK_ERROR_INVALID, 'no attributes allowed'); - } - return true; + unset($this->_packageInfo['dirtree']); } /** - * Initialize a task instance with the parameters - * @param array raw, parsed xml - * @param unused + * Determines whether this package claims it is compatible with the version of + * the package that has a recommended version dependency + * @param PEAR_PackageFile_v2|PEAR_PackageFile_v1|PEAR_Downloader_Package + * @return boolean */ - function init($xml, $attribs) + function isCompatible($pf) { + if (!isset($this->_packageInfo['compatible'])) { + return false; + } + if (!isset($this->_packageInfo['channel'])) { + return false; + } + $me = $pf->getVersion(); + $compatible = $this->_packageInfo['compatible']; + if (!isset($compatible[0])) { + $compatible = array($compatible); + } + $found = false; + foreach ($compatible as $info) { + if (strtolower($info['name']) == strtolower($pf->getPackage())) { + if (strtolower($info['channel']) == strtolower($pf->getChannel())) { + $found = true; + break; + } + } + } + if (!$found) { + return false; + } + if (isset($info['exclude'])) { + if (!isset($info['exclude'][0])) { + $info['exclude'] = array($info['exclude']); + } + foreach ($info['exclude'] as $exclude) { + if (version_compare($me, $exclude, '==')) { + return false; + } + } + } + if (version_compare($me, $info['min'], '>=') && version_compare($me, $info['max'], '<=')) { + return true; + } + return false; } /** - * Replace all line endings with line endings customized for the current OS - * - * See validateXml() source for the complete list of allowed fields - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @param string file contents - * @param string the eventual final file location (informational only) - * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail - * (use $this->throwError), otherwise return the new contents + * @return array|false */ - function startSession($pkg, $contents, $dest) + function getCompatible() { - $this->logger->log(3, "replacing all line endings with \\n in $dest"); - return preg_replace("/\r\n|\n\r|\r|\n/", "\n", $contents); + if (isset($this->_packageInfo['compatible'])) { + return $this->_packageInfo['compatible']; + } + return false; } -} -?>PEAR-1.8.0/PEAR/Task/Windowseol.php100664 764 764 4340 100664 11602 - * - * PHP versions 4 and 5 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Windowseol.php,v 1.11 2009/02/25 00:15:49 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * Base class - */ -require_once 'PEAR/Task/Common.php'; -/** - * Implements the windows line endsings file task. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Task_Windowseol extends PEAR_Task_Common -{ - var $type = 'simple'; - var $phase = PEAR_TASK_PACKAGE; - var $_replacements; - /** - * Validate the raw xml at parsing-time. - * @param PEAR_PackageFile_v2 - * @param array raw, parsed xml - * @param PEAR_Config - * @static - */ - function validateXml($pkg, $xml, $config, $fileXml) + function getDependencies() { - if ($xml != '') { - return array(PEAR_TASK_ERROR_INVALID, 'no attributes allowed'); + if (isset($this->_packageInfo['dependencies'])) { + return $this->_packageInfo['dependencies']; } - return true; + return false; } - /** - * Initialize a task instance with the parameters - * @param array raw, parsed xml - * @param unused - */ - function init($xml, $attribs) + function isSubpackageOf($p) { + return $p->isSubpackage($this); } /** - * Replace all line endings with windows line endings + * Determines whether the passed in package is a subpackage of this package. * - * See validateXml() source for the complete list of allowed fields + * No version checking is done, only name verification. * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @param string file contents - * @param string the eventual final file location (informational only) - * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail - * (use $this->throwError), otherwise return the new contents + * @return bool */ - function startSession($pkg, $contents, $dest) - { - $this->logger->log(3, "replacing all line endings with \\r\\n in $dest"); - return preg_replace("/\r\n|\n\r|\r|\n/", "\r\n", $contents); - } -} -?>PEAR-1.8.0/PEAR/Validator/PECL.php100664 764 764 4200 100664 11211 - * @copyright 1997-2006 The PHP Group - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: PECL.php,v 1.10 2009/02/24 23:39:19 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a5 - */ -/** - * This is the parent class for all validators - */ -require_once 'PEAR/Validate.php'; -/** - * Channel Validator for the pecl.php.net channel - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a5 - */ -class PEAR_Validator_PECL extends PEAR_Validate -{ - function validateVersion() + function isSubpackage($p) { - if ($this->_state == PEAR_VALIDATE_PACKAGING) { - $version = $this->_packagexml->getVersion(); - $versioncomponents = explode('.', $version); - $last = array_pop($versioncomponents); - if (substr($last, 1, 2) == 'rc') { - $this->_addFailure('version', 'Release Candidate versions must have ' . - 'upper-case RC, not lower-case rc'); - return false; + $sub = array(); + if (isset($this->_packageInfo['dependencies']['required']['subpackage'])) { + $sub = $this->_packageInfo['dependencies']['required']['subpackage']; + if (!isset($sub[0])) { + $sub = array($sub); } } - return true; + if (isset($this->_packageInfo['dependencies']['optional']['subpackage'])) { + $sub1 = $this->_packageInfo['dependencies']['optional']['subpackage']; + if (!isset($sub1[0])) { + $sub1 = array($sub1); + } + $sub = array_merge($sub, $sub1); + } + if (isset($this->_packageInfo['dependencies']['group'])) { + $group = $this->_packageInfo['dependencies']['group']; + if (!isset($group[0])) { + $group = array($group); + } + foreach ($group as $deps) { + if (isset($deps['subpackage'])) { + $sub2 = $deps['subpackage']; + if (!isset($sub2[0])) { + $sub2 = array($sub2); + } + $sub = array_merge($sub, $sub2); + } + } + } + foreach ($sub as $dep) { + if (strtolower($dep['name']) == strtolower($p->getPackage())) { + if (isset($dep['channel'])) { + if (strtolower($dep['channel']) == strtolower($p->getChannel())) { + return true; + } + } else { + if ($dep['uri'] == $p->getURI()) { + return true; + } + } + } + } + return false; } - function validatePackageName() + function dependsOn($package, $channel) { - $ret = parent::validatePackageName(); - if ($this->_packagexml->getPackageType() == 'extsrc' || - $this->_packagexml->getPackageType() == 'zendextsrc') { - if (strtolower($this->_packagexml->getPackage()) != - strtolower($this->_packagexml->getProvidesExtension())) { - $this->_addWarning('providesextension', 'package name "' . - $this->_packagexml->getPackage() . '" is different from extension name "' . - $this->_packagexml->getProvidesExtension() . '"'); + if (!($deps = $this->getDependencies())) { + return false; + } + foreach (array('package', 'subpackage') as $type) { + foreach (array('required', 'optional') as $needed) { + if (isset($deps[$needed][$type])) { + if (!isset($deps[$needed][$type][0])) { + $deps[$needed][$type] = array($deps[$needed][$type]); + } + foreach ($deps[$needed][$type] as $dep) { + $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri'; + if (strtolower($dep['name']) == strtolower($package) && + $depchannel == $channel) { + return true; + } + } + } + } + if (isset($deps['group'])) { + if (!isset($deps['group'][0])) { + $dep['group'] = array($deps['group']); + } + foreach ($deps['group'] as $group) { + if (isset($group[$type])) { + if (!is_array($group[$type])) { + $group[$type] = array($group[$type]); + } + foreach ($group[$type] as $dep) { + $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri'; + if (strtolower($dep['name']) == strtolower($package) && + $depchannel == $channel) { + return true; + } + } + } + } } } - return $ret; + return false; } -} -?>PEAR-1.8.0/PEAR/Autoloader.php100664 764 764 15202 100664 10664 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Autoloader.php,v 1.15 2009/02/24 23:38:22 dufuz Exp $ - * @link http://pear.php.net/manual/en/core.ppm.php#core.ppm.pear-autoloader - * @since File available since Release 0.1 - * @deprecated File deprecated in Release 1.4.0a1 - */ - -// /* vim: set expandtab tabstop=4 shiftwidth=4: */ - -if (!extension_loaded("overload")) { - // die hard without ext/overload - die("Rebuild PHP with the `overload' extension to use PEAR_Autoloader"); -} - -/** - * Include for PEAR_Error and PEAR classes - */ -require_once "PEAR.php"; - -/** - * This class is for objects where you want to separate the code for - * some methods into separate classes. This is useful if you have a - * class with not-frequently-used methods that contain lots of code - * that you would like to avoid always parsing. - * - * The PEAR_Autoloader class provides autoloading and aggregation. - * The autoloading lets you set up in which classes the separated - * methods are found. Aggregation is the technique used to import new - * methods, an instance of each class providing separated methods is - * stored and called every time the aggregated method is called. - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/manual/en/core.ppm.php#core.ppm.pear-autoloader - * @since File available since Release 0.1 - * @deprecated File deprecated in Release 1.4.0a1 - */ -class PEAR_Autoloader extends PEAR -{ - // {{{ properties - - /** - * Map of methods and classes where they are defined - * - * @var array - * - * @access private - */ - var $_autoload_map = array(); - - /** - * Map of methods and aggregate objects - * - * @var array - * - * @access private - */ - var $_method_map = array(); - - // }}} - // {{{ addAutoload() - - /** - * Add one or more autoload entries. - * - * @param string $method which method to autoload - * - * @param string $classname (optional) which class to find the method in. - * If the $method parameter is an array, this - * parameter may be omitted (and will be ignored - * if not), and the $method parameter will be - * treated as an associative array with method - * names as keys and class names as values. - * - * @return void - * - * @access public - */ - function addAutoload($method, $classname = null) - { - if (is_array($method)) { - array_walk($method, create_function('$a,&$b', '$b = strtolower($b);')); - $this->_autoload_map = array_merge($this->_autoload_map, $method); - } else { - $this->_autoload_map[strtolower($method)] = $classname; - } - } - - // }}} - // {{{ removeAutoload() - - /** - * Remove an autoload entry. - * - * @param string $method which method to remove the autoload entry for - * - * @return bool TRUE if an entry was removed, FALSE if not - * - * @access public - */ - function removeAutoload($method) - { - $method = strtolower($method); - $ok = isset($this->_autoload_map[$method]); - unset($this->_autoload_map[$method]); - return $ok; - } - - // }}} - // {{{ addAggregateObject() - - /** - * Add an aggregate object to this object. If the specified class - * is not defined, loading it will be attempted following PEAR's - * file naming scheme. All the methods in the class will be - * aggregated, except private ones (name starting with an - * underscore) and constructors. - * - * @param string $classname what class to instantiate for the object. - * - * @return void - * - * @access public - */ - function addAggregateObject($classname) - { - $classname = strtolower($classname); - if (!class_exists($classname)) { - $include_file = preg_replace('/[^a-z0-9]/i', '_', $classname); - include_once $include_file; - } - $obj =& new $classname; - $methods = get_class_methods($classname); - foreach ($methods as $method) { - // don't import priviate methods and constructors - if ($method{0} != '_' && $method != $classname) { - $this->_method_map[$method] = $obj; - } - } - } - - // }}} - // {{{ removeAggregateObject() - - /** - * Remove an aggregate object. - * - * @param string $classname the class of the object to remove - * - * @return bool TRUE if an object was removed, FALSE if not - * - * @access public - */ - function removeAggregateObject($classname) - { - $ok = false; - $classname = strtolower($classname); - reset($this->_method_map); - while (list($method, $obj) = each($this->_method_map)) { - if (is_a($obj, $classname)) { - unset($this->_method_map[$method]); - $ok = true; - } - } - return $ok; - } - - // }}} - // {{{ __call() - - /** - * Overloaded object call handler, called each time an - * undefined/aggregated method is invoked. This method repeats - * the call in the right aggregate object and passes on the return - * value. - * - * @param string $method which method that was called - * - * @param string $args An array of the parameters passed in the - * original call - * - * @return mixed The return value from the aggregated method, or a PEAR - * error if the called method was unknown. - */ - function __call($method, $args, &$retval) - { - $method = strtolower($method); - if (empty($this->_method_map[$method]) && isset($this->_autoload_map[$method])) { - $this->addAggregateObject($this->_autoload_map[$method]); - } - if (isset($this->_method_map[$method])) { - $retval = call_user_func_array(array($this->_method_map[$method], $method), $args); - return true; - } - return false; - } - - // }}} -} - -overload("PEAR_Autoloader"); - -?> -PEAR-1.8.0/PEAR/Builder.php100664 764 764 40123 100664 10153 - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Builder.php,v 1.38 2009/02/24 23:38:22 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - * - * TODO: log output parameters in PECL command line - * TODO: msdev path in configuration - */ - -/** - * Needed for extending PEAR_Builder - */ -require_once 'PEAR/Common.php'; -require_once 'PEAR/PackageFile.php'; - -/** - * Class to handle building (compiling) extensions. - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since PHP 4.0.2 - * @see http://pear.php.net/manual/en/core.ppm.pear-builder.php - */ -class PEAR_Builder extends PEAR_Common -{ - var $php_api_version = 0; - var $zend_module_api_no = 0; - var $zend_extension_api_no = 0; - - var $extensions_built = array(); - - /** - * @var string Used for reporting when it is not possible to pass function - * via extra parameter, e.g. log, msdevCallback - */ - var $current_callback = null; - - // used for msdev builds - var $_lastline = null; - var $_firstline = null; /** - * PEAR_Builder constructor. - * - * @param object $ui user interface object (instance of PEAR_Frontend_*) - * - * @access public + * Get the contents of a dependency group + * @param string + * @return array|false */ - function PEAR_Builder(&$ui) + function getDependencyGroup($name) { - parent::PEAR_Common(); - $this->setFrontendObject($ui); + $name = strtolower($name); + if (!isset($this->_packageInfo['dependencies']['group'])) { + return false; + } + $groups = $this->_packageInfo['dependencies']['group']; + if (!isset($groups[0])) { + $groups = array($groups); + } + foreach ($groups as $group) { + if (strtolower($group['attribs']['name']) == $name) { + return $group; + } + } + return false; } /** - * Build an extension from source on windows. - * requires msdev + * Retrieve a partial package.xml 1.0 representation of dependencies + * + * a very limited representation of dependencies is returned by this method. + * The tag for excluding certain versions of a dependency is + * completely ignored. In addition, dependency groups are ignored, with the + * assumption that all dependencies in dependency groups are also listed in + * the optional group that work with all dependency groups + * @param boolean return package.xml 2.0 tag + * @return array|false */ - function _build_win32($descfile, $callback = null) + function getDeps($raw = false, $nopearinstaller = false) { - if (is_object($descfile)) { - $pkg = $descfile; - $descfile = $pkg->getPackageFile(); - } else { - $pf = &new PEAR_PackageFile($this->config, $this->debug); - $pkg = &$pf->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL); - if (PEAR::isError($pkg)) { - return $pkg; - } - } - $dir = dirname($descfile); - $old_cwd = getcwd(); - - if (!file_exists($dir) || !is_dir($dir) || !chdir($dir)) { - return $this->raiseError("could not chdir to $dir"); - } - - // packages that were in a .tar have the packagefile in this directory - $vdir = $pkg->getPackage() . '-' . $pkg->getVersion(); - if (file_exists($dir) && is_dir($vdir)) { - if (!chdir($vdir)) { - return $this->raiseError("could not chdir to " . realpath($vdir)); + if (isset($this->_packageInfo['dependencies'])) { + if ($raw) { + return $this->_packageInfo['dependencies']; + } + $ret = array(); + $map = array( + 'php' => 'php', + 'package' => 'pkg', + 'subpackage' => 'pkg', + 'extension' => 'ext', + 'os' => 'os', + 'pearinstaller' => 'pkg', + ); + foreach (array('required', 'optional') as $type) { + $optional = ($type == 'optional') ? 'yes' : 'no'; + if (!isset($this->_packageInfo['dependencies'][$type]) + || empty($this->_packageInfo['dependencies'][$type])) { + continue; + } + foreach ($this->_packageInfo['dependencies'][$type] as $dtype => $deps) { + if ($dtype == 'pearinstaller' && $nopearinstaller) { + continue; + } + if (!isset($deps[0])) { + $deps = array($deps); + } + foreach ($deps as $dep) { + if (!isset($map[$dtype])) { + // no support for arch type + continue; + } + if ($dtype == 'pearinstaller') { + $dep['name'] = 'PEAR'; + $dep['channel'] = 'pear.php.net'; + } + $s = array('type' => $map[$dtype]); + if (isset($dep['channel'])) { + $s['channel'] = $dep['channel']; + } + if (isset($dep['uri'])) { + $s['uri'] = $dep['uri']; + } + if (isset($dep['name'])) { + $s['name'] = $dep['name']; + } + if (isset($dep['conflicts'])) { + $s['rel'] = 'not'; + } else { + if (!isset($dep['min']) && + !isset($dep['max'])) { + $s['rel'] = 'has'; + $s['optional'] = $optional; + } elseif (isset($dep['min']) && + isset($dep['max'])) { + $s['rel'] = 'ge'; + $s1 = $s; + $s1['rel'] = 'le'; + $s['version'] = $dep['min']; + $s1['version'] = $dep['max']; + if (isset($dep['channel'])) { + $s1['channel'] = $dep['channel']; + } + if ($dtype != 'php') { + $s['name'] = $dep['name']; + $s1['name'] = $dep['name']; + } + $s['optional'] = $optional; + $s1['optional'] = $optional; + $ret[] = $s1; + } elseif (isset($dep['min'])) { + if (isset($dep['exclude']) && + $dep['exclude'] == $dep['min']) { + $s['rel'] = 'gt'; + } else { + $s['rel'] = 'ge'; + } + $s['version'] = $dep['min']; + $s['optional'] = $optional; + if ($dtype != 'php') { + $s['name'] = $dep['name']; + } + } elseif (isset($dep['max'])) { + if (isset($dep['exclude']) && + $dep['exclude'] == $dep['max']) { + $s['rel'] = 'lt'; + } else { + $s['rel'] = 'le'; + } + $s['version'] = $dep['max']; + $s['optional'] = $optional; + if ($dtype != 'php') { + $s['name'] = $dep['name']; + } + } + } + $ret[] = $s; + } + } + } + if (count($ret)) { + return $ret; } - - $dir = getcwd(); - } - - $this->log(2, "building in $dir"); - - $dsp = $pkg->getPackage().'.dsp'; - if (!file_exists("$dir/$dsp")) { - return $this->raiseError("The DSP $dsp does not exist."); } - // XXX TODO: make release build type configurable - $command = 'msdev '.$dsp.' /MAKE "'.$pkg->getPackage(). ' - Release"'; + return false; + } - $err = $this->_runCommand($command, array(&$this, 'msdevCallback')); - if (PEAR::isError($err)) { - return $err; + /** + * @return php|extsrc|extbin|zendextsrc|zendextbin|bundle|false + */ + function getPackageType() + { + if (isset($this->_packageInfo['phprelease'])) { + return 'php'; } - - // figure out the build platform and type - $platform = 'Win32'; - $buildtype = 'Release'; - if (preg_match('/.*?'.$pkg->getPackage().'\s-\s(\w+)\s(.*?)-+/i',$this->_firstline,$matches)) { - $platform = $matches[1]; - $buildtype = $matches[2]; + if (isset($this->_packageInfo['extsrcrelease'])) { + return 'extsrc'; } - - if (preg_match('/(.*)?\s-\s(\d+).*?(\d+)/', $this->_lastline, $matches)) { - if ($matches[2]) { - // there were errors in the build - return $this->raiseError("There were errors during compilation."); - } - $out = $matches[1]; - } else { - return $this->raiseError("Did not understand the completion status returned from msdev.exe."); + if (isset($this->_packageInfo['extbinrelease'])) { + return 'extbin'; } + if (isset($this->_packageInfo['zendextsrcrelease'])) { + return 'zendextsrc'; + } + if (isset($this->_packageInfo['zendextbinrelease'])) { + return 'zendextbin'; + } + if (isset($this->_packageInfo['bundle'])) { + return 'bundle'; + } + return false; + } - // msdev doesn't tell us the output directory :/ - // open the dsp, find /out and use that directory - $dsptext = join(file($dsp),''); - - // this regex depends on the build platform and type having been - // correctly identified above. - $regex ='/.*?!IF\s+"\$\(CFG\)"\s+==\s+("'. - $pkg->getPackage().'\s-\s'. - $platform.'\s'. - $buildtype.'").*?'. - '\/out:"(.*?)"/is'; - - if ($dsptext && preg_match($regex, $dsptext, $matches)) { - // what we get back is a relative path to the output file itself. - $outfile = realpath($matches[2]); - } else { - return $this->raiseError("Could not retrieve output information from $dsp."); + /** + * @return array|false + */ + function getReleases() + { + $type = $this->getPackageType(); + if ($type != 'bundle') { + $type .= 'release'; } - // realpath returns false if the file doesn't exist - if ($outfile && copy($outfile, "$dir/$out")) { - $outfile = "$dir/$out"; + if ($this->getPackageType() && isset($this->_packageInfo[$type])) { + return $this->_packageInfo[$type]; } + return false; + } - $built_files[] = array( - 'file' => "$outfile", - 'php_api' => $this->php_api_version, - 'zend_mod_api' => $this->zend_module_api_no, - 'zend_ext_api' => $this->zend_extension_api_no, - ); + /** + * @return array + */ + function getChangelog() + { + if (isset($this->_packageInfo['changelog'])) { + return $this->_packageInfo['changelog']; + } + return false; + } - return $built_files; + function hasDeps() + { + return isset($this->_packageInfo['dependencies']); } - // }}} - // {{{ msdevCallback() - function msdevCallback($what, $data) + function getPackagexmlVersion() { - if (!$this->_firstline) - $this->_firstline = $data; - $this->_lastline = $data; - call_user_func($this->current_callback, $what, $data); + if (isset($this->_packageInfo['zendextsrcrelease'])) { + return '2.1'; + } + if (isset($this->_packageInfo['zendextbinrelease'])) { + return '2.1'; + } + return '2.0'; } /** - * @param string - * @param string - * @param array - * @access private + * @return array|false */ - function _harvestInstDir($dest_prefix, $dirname, &$built_files) + function getSourcePackage() { - $d = opendir($dirname); - if (!$d) - return false; + if (isset($this->_packageInfo['extbinrelease']) || + isset($this->_packageInfo['zendextbinrelease'])) { + return array('channel' => $this->_packageInfo['srcchannel'], + 'package' => $this->_packageInfo['srcpackage']); + } + return false; + } - $ret = true; - while (($ent = readdir($d)) !== false) { - if ($ent{0} == '.') - continue; + function getBundledPackages() + { + if (isset($this->_packageInfo['bundle'])) { + return $this->_packageInfo['contents']['bundledpackage']; + } + return false; + } - $full = $dirname . DIRECTORY_SEPARATOR . $ent; - if (is_dir($full)) { - if (!$this->_harvestInstDir( - $dest_prefix . DIRECTORY_SEPARATOR . $ent, - $full, $built_files)) { - $ret = false; - break; - } - } else { - $dest = $dest_prefix . DIRECTORY_SEPARATOR . $ent; - $built_files[] = array( - 'file' => $full, - 'dest' => $dest, - 'php_api' => $this->php_api_version, - 'zend_mod_api' => $this->zend_module_api_no, - 'zend_ext_api' => $this->zend_extension_api_no, - ); - } + function getLastModified() + { + if (isset($this->_packageInfo['_lastmodified'])) { + return $this->_packageInfo['_lastmodified']; } - closedir($d); - return $ret; + return false; } /** - * Build an extension from source. Runs "phpize" in the source - * directory, but compiles in a temporary directory - * (/var/tmp/pear-build-USER/PACKAGE-VERSION). - * - * @param string|PEAR_PackageFile_v* $descfile path to XML package description file, or - * a PEAR_PackageFile object - * - * @param mixed $callback callback function used to report output, - * see PEAR_Builder::_runCommand for details - * - * @return array an array of associative arrays with built files, - * format: - * array( array( 'file' => '/path/to/ext.so', - * 'php_api' => YYYYMMDD, - * 'zend_mod_api' => YYYYMMDD, - * 'zend_ext_api' => YYYYMMDD ), - * ... ) - * - * @access public - * - * @see PEAR_Builder::_runCommand + * Get the contents of a file listed within the package.xml + * @param string + * @return string */ - function build($descfile, $callback = null) + function getFileContents($file) { - if (preg_match('/(\\/|\\\\|^)([^\\/\\\\]+)?php(.+)?$/', - $this->config->get('php_bin'), $matches)) { - if (isset($matches[2]) && strlen($matches[2]) && - trim($matches[2]) != trim($this->config->get('php_prefix'))) { - $this->log(0, 'WARNING: php_bin ' . $this->config->get('php_bin') . - ' appears to have a prefix ' . $matches[2] . ', but' . - ' config variable php_prefix does not match'); + if ($this->_archiveFile == $this->_packageFile) { // unpacked + $dir = dirname($this->_packageFile); + $file = $dir . DIRECTORY_SEPARATOR . $file; + $file = str_replace(array('/', '\\'), + array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), $file); + if (file_exists($file) && is_readable($file)) { + return implode('', file($file)); } - if (isset($matches[3]) && strlen($matches[3]) && - trim($matches[3]) != trim($this->config->get('php_suffix'))) { - $this->log(0, 'WARNING: php_bin ' . $this->config->get('php_bin') . - ' appears to have a suffix ' . $matches[3] . ', but' . - ' config variable php_suffix does not match'); + } else { // tgz + $tar = &new Archive_Tar($this->_archiveFile); + $tar->pushErrorHandling(PEAR_ERROR_RETURN); + if ($file != 'package.xml' && $file != 'package2.xml') { + $file = $this->getPackage() . '-' . $this->getVersion() . '/' . $file; + } + $file = $tar->extractInString($file); + $tar->popErrorHandling(); + if (PEAR::isError($file)) { + return PEAR::raiseError("Cannot locate file '$file' in archive"); } + return $file; } + } - - $this->current_callback = $callback; - if (PEAR_OS == "Windows") { - return $this->_build_win32($descfile, $callback); - } - if (PEAR_OS != 'Unix') { - return $this->raiseError("building extensions not supported on this platform"); + function &getRW() + { + if (!class_exists('PEAR_PackageFile_v2_rw')) { + require_once 'PEAR/PackageFile/v2/rw.php'; } - if (is_object($descfile)) { - $pkg = $descfile; - $descfile = $pkg->getPackageFile(); - if (is_a($pkg, 'PEAR_PackageFile_v1')) { - $dir = dirname($descfile); - } else { - $dir = $pkg->_config->get('temp_dir') . '/' . $pkg->getName(); - // automatically delete at session end - $this->addTempFile($dir); + $a = new PEAR_PackageFile_v2_rw; + foreach (get_object_vars($this) as $name => $unused) { + if (!isset($this->$name)) { + continue; } - } else { - $pf = &new PEAR_PackageFile($this->config); - $pkg = &$pf->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL); - if (PEAR::isError($pkg)) { - return $pkg; + if ($name == '_config' || $name == '_logger'|| $name == '_registry' || + $name == '_stack') { + $a->$name = &$this->$name; + } else { + $a->$name = $this->$name; } - $dir = dirname($descfile); - } - $old_cwd = getcwd(); - if (!file_exists($dir) || !is_dir($dir) || !chdir($dir)) { - return $this->raiseError("could not chdir to $dir"); - } - $vdir = $pkg->getPackage() . '-' . $pkg->getVersion(); - if (is_dir($vdir)) { - chdir($vdir); - } - $dir = getcwd(); - $this->log(2, "building in $dir"); - putenv('PATH=' . $this->config->get('bin_dir') . ':' . getenv('PATH')); - $err = $this->_runCommand($this->config->get('php_prefix') - . "phpize" . - $this->config->get('php_suffix'), - array(&$this, 'phpizeCallback')); - if (PEAR::isError($err)) { - return $err; } - if (!$err) { - return $this->raiseError("`phpize' failed"); + return $a; + } + + function &getDefaultGenerator() + { + if (!class_exists('PEAR_PackageFile_Generator_v2')) { + require_once 'PEAR/PackageFile/Generator/v2.php'; } + $a = &new PEAR_PackageFile_Generator_v2($this); + return $a; + } - // {{{ start of interactive part - $configure_command = "$dir/configure"; - $configure_options = $pkg->getConfigureOptions(); - if ($configure_options) { - foreach ($configure_options as $o) { - $default = array_key_exists('default', $o) ? $o['default'] : null; - list($r) = $this->ui->userDialog('build', - array($o['prompt']), - array('text'), - array($default)); - if (substr($o['name'], 0, 5) == 'with-' && - ($r == 'yes' || $r == 'autodetect')) { - $configure_command .= " --$o[name]"; - } else { - $configure_command .= " --$o[name]=".trim($r); - } + function analyzeSourceCode($file, $string = false) + { + if (!isset($this->_v2Validator) || + !is_a($this->_v2Validator, 'PEAR_PackageFile_v2_Validator')) { + if (!class_exists('PEAR_PackageFile_v2_Validator')) { + require_once 'PEAR/PackageFile/v2/Validator.php'; } + $this->_v2Validator = new PEAR_PackageFile_v2_Validator; } - // }}} end of interactive part + return $this->_v2Validator->analyzeSourceCode($file, $string); + } - // FIXME make configurable - if(!$user=getenv('USER')){ - $user='defaultuser'; - } - $build_basedir = "/var/tmp/pear-build-$user"; - $build_dir = "$build_basedir/$vdir"; - $inst_dir = "$build_basedir/install-$vdir"; - $this->log(1, "building in $build_dir"); - if (is_dir($build_dir)) { - System::rm(array('-rf', $build_dir)); + function validate($state = PEAR_VALIDATE_NORMAL) + { + if (!isset($this->_packageInfo) || !is_array($this->_packageInfo)) { + return false; } - if (!System::mkDir(array('-p', $build_dir))) { - return $this->raiseError("could not create build dir: $build_dir"); + if (!isset($this->_v2Validator) || + !is_a($this->_v2Validator, 'PEAR_PackageFile_v2_Validator')) { + if (!class_exists('PEAR_PackageFile_v2_Validator')) { + require_once 'PEAR/PackageFile/v2/Validator.php'; + } + $this->_v2Validator = new PEAR_PackageFile_v2_Validator; } - $this->addTempFile($build_dir); - if (!System::mkDir(array('-p', $inst_dir))) { - return $this->raiseError("could not create temporary install dir: $inst_dir"); + if (isset($this->_packageInfo['xsdversion'])) { + unset($this->_packageInfo['xsdversion']); } - $this->addTempFile($inst_dir); + return $this->_v2Validator->validate($this, $state); + } - if (getenv('MAKE')) { - $make_command = getenv('MAKE'); - } else { - $make_command = 'make'; - } - $to_run = array( - $configure_command, - $make_command, - "$make_command INSTALL_ROOT=\"$inst_dir\" install", - "find \"$inst_dir\" | xargs ls -dils" - ); - if (!file_exists($build_dir) || !is_dir($build_dir) || !chdir($build_dir)) { - return $this->raiseError("could not chdir to $build_dir"); - } - putenv('PHP_PEAR_VERSION=1.8.0'); - foreach ($to_run as $cmd) { - $err = $this->_runCommand($cmd, $callback); - if (PEAR::isError($err)) { - chdir($old_cwd); - return $err; - } - if (!$err) { - chdir($old_cwd); - return $this->raiseError("`$cmd' failed"); + function getTasksNs() + { + if (!isset($this->_tasksNs)) { + if (isset($this->_packageInfo['attribs'])) { + foreach ($this->_packageInfo['attribs'] as $name => $value) { + if ($value == 'http://pear.php.net/dtd/tasks-1.0') { + $this->_tasksNs = str_replace('xmlns:', '', $name); + break; + } + } } } - if (!($dp = opendir("modules"))) { - chdir($old_cwd); - return $this->raiseError("no `modules' directory found"); - } - $built_files = array(); - $prefix = exec($this->config->get('php_prefix') - . "php-config" . - $this->config->get('php_suffix') . " --prefix"); - $this->_harvestInstDir($prefix, $inst_dir . DIRECTORY_SEPARATOR . $prefix, $built_files); - chdir($old_cwd); - return $built_files; + return $this->_tasksNs; } /** - * Message callback function used when running the "phpize" - * program. Extracts the API numbers used. Ignores other message - * types than "cmdoutput". - * - * @param string $what the type of message - * @param mixed $data the message - * - * @return void + * Determine whether a task name is a valid task. Custom tasks may be defined + * using subdirectories by putting a "-" in the name, as in * - * @access public + * Note that this method will auto-load the task class file and test for the existence + * of the name with "-" replaced by "_" as in PEAR/Task/mycustom/task.php makes class + * PEAR_Task_mycustom_task + * @param string + * @return boolean */ - function phpizeCallback($what, $data) + function getTask($task) { - if ($what != 'cmdoutput') { - return; - } - $this->log(1, rtrim($data)); - if (preg_match('/You should update your .aclocal.m4/', $data)) { - return; + $this->getTasksNs(); + // transform all '-' to '/' and 'tasks:' to '' so tasks:replace becomes replace + $task = str_replace(array($this->_tasksNs . ':', '-'), array('', ' '), $task); + $taskfile = str_replace(' ', '/', ucwords($task)); + $task = str_replace(array(' ', '/'), '_', ucwords($task)); + if (class_exists("PEAR_Task_$task")) { + return "PEAR_Task_$task"; } - $matches = array(); - if (preg_match('/^\s+(\S[^:]+):\s+(\d{8})/', $data, $matches)) { - $member = preg_replace('/[^a-z]/', '_', strtolower($matches[1])); - $apino = (int)$matches[2]; - if (isset($this->$member)) { - $this->$member = $apino; - //$msg = sprintf("%-22s : %d", $matches[1], $apino); - //$this->log(1, $msg); - } + $fp = @fopen("PEAR/Task/$taskfile.php", 'r', true); + if ($fp) { + fclose($fp); + require_once "PEAR/Task/$taskfile.php"; + return "PEAR_Task_$task"; } + return false; } /** - * Run an external command, using a message callback to report - * output. The command will be run through popen and output is - * reported for every line with a "cmdoutput" message with the - * line string, including newlines, as payload. - * - * @param string $command the command to run - * - * @param mixed $callback (optional) function to use as message - * callback - * - * @return bool whether the command was successful (exit code 0 - * means success, any other means failure) - * - * @access private + * Key-friendly array_splice + * @param tagname to splice a value in before + * @param mixed the value to splice in + * @param string the new tag name */ - function _runCommand($command, $callback = null) + function _ksplice($array, $key, $value, $newkey) { - $this->log(1, "running: $command"); - $pp = popen("$command 2>&1", "r"); - if (!$pp) { - return $this->raiseError("failed to run `$command'"); - } - if ($callback && $callback[0]->debug == 1) { - $olddbg = $callback[0]->debug; - $callback[0]->debug = 2; - } + $offset = array_search($key, array_keys($array)); + $after = array_slice($array, $offset); + $before = array_slice($array, 0, $offset); + $before[$newkey] = $value; + return array_merge($before, $after); + } - while ($line = fgets($pp, 1024)) { - if ($callback) { - call_user_func($callback, 'cmdoutput', $line); - } else { - $this->log(2, rtrim($line)); + /** + * @param array a list of possible keys, in the order they may occur + * @param mixed contents of the new package.xml tag + * @param string tag name + * @access private + */ + function _insertBefore($array, $keys, $contents, $newkey) + { + foreach ($keys as $key) { + if (isset($array[$key])) { + return $array = $this->_ksplice($array, $key, $contents, $newkey); } } - if ($callback && isset($olddbg)) { - $callback[0]->debug = $olddbg; - } - - $exitcode = is_resource($pp) ? pclose($pp) : -1; - return ($exitcode == 0); + $array[$newkey] = $contents; + return $array; } - function log($level, $msg) + /** + * @param subsection of {@link $_packageInfo} + * @param array|string tag contents + * @param array format: + *
+     * array(
+     *   tagname => array(list of tag names that follow this one),
+     *   childtagname => array(list of child tag names that follow this one),
+     * )
+     * 
+ * + * This allows construction of nested tags + * @access private + */ + function _mergeTag($manip, $contents, $order) { - if ($this->current_callback) { - if ($this->debug >= $level) { - call_user_func($this->current_callback, 'output', $msg); + if (count($order)) { + foreach ($order as $tag => $curorder) { + if (!isset($manip[$tag])) { + // ensure that the tag is set up + $manip = $this->_insertBefore($manip, $curorder, array(), $tag); + } + if (count($order) > 1) { + $manip[$tag] = $this->_mergeTag($manip[$tag], $contents, array_slice($order, 1)); + return $manip; + } } - return; + } else { + return $manip; } - return PEAR_Common::log($level, $msg); + if (is_array($manip[$tag]) && !empty($manip[$tag]) && isset($manip[$tag][0])) { + $manip[$tag][] = $contents; + } else { + if (!count($manip[$tag])) { + $manip[$tag] = $contents; + } else { + $manip[$tag] = array($manip[$tag]); + $manip[$tag][] = $contents; + } + } + return $manip; } -}PEAR-1.8.0/PEAR/ChannelFile.php100664 764 764 142432 100664 10763 +PEAR-1.9.0/PEAR/REST/10.php100664 764 764 77605 100664 7602 * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: ChannelFile.php,v 1.84 2009/03/09 01:03:51 dufuz Exp $ + * @version CVS: $Id: 10.php 287558 2009-08-21 22:21:28Z dufuz $ * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * Needed for error handling - */ -require_once 'PEAR/ErrorStack.php'; -require_once 'PEAR/XMLParser.php'; -require_once 'PEAR/Common.php'; - -/** - * Error code if the channel.xml tag does not contain a valid version - */ -define('PEAR_CHANNELFILE_ERROR_NO_VERSION', 1); -/** - * Error code if the channel.xml tag version is not supported (version 1.0 is the only supported version, - * currently - */ -define('PEAR_CHANNELFILE_ERROR_INVALID_VERSION', 2); - -/** - * Error code if parsing is attempted with no xml extension - */ -define('PEAR_CHANNELFILE_ERROR_NO_XML_EXT', 3); - -/** - * Error code if creating the xml parser resource fails - */ -define('PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER', 4); - -/** - * Error code used for all sax xml parsing errors - */ -define('PEAR_CHANNELFILE_ERROR_PARSER_ERROR', 5); - -/**#@+ - * Validation errors - */ -/** - * Error code when channel name is missing - */ -define('PEAR_CHANNELFILE_ERROR_NO_NAME', 6); -/** - * Error code when channel name is invalid - */ -define('PEAR_CHANNELFILE_ERROR_INVALID_NAME', 7); -/** - * Error code when channel summary is missing - */ -define('PEAR_CHANNELFILE_ERROR_NO_SUMMARY', 8); -/** - * Error code when channel summary is multi-line - */ -define('PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY', 9); -/** - * Error code when channel server is missing for protocol - */ -define('PEAR_CHANNELFILE_ERROR_NO_HOST', 10); -/** - * Error code when channel server is invalid for protocol - */ -define('PEAR_CHANNELFILE_ERROR_INVALID_HOST', 11); -/** - * Error code when a mirror name is invalid - */ -define('PEAR_CHANNELFILE_ERROR_INVALID_MIRROR', 21); -/** - * Error code when a mirror type is invalid - */ -define('PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE', 22); -/** - * Error code when an attempt is made to generate xml, but the parsed content is invalid - */ -define('PEAR_CHANNELFILE_ERROR_INVALID', 23); -/** - * Error code when an empty package name validate regex is passed in - */ -define('PEAR_CHANNELFILE_ERROR_EMPTY_REGEX', 24); -/** - * Error code when a tag has no version - */ -define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION', 25); -/** - * Error code when a tag has no name - */ -define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME', 26); -/** - * Error code when a tag has no name - */ -define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME', 27); -/** - * Error code when a tag has no version attribute - */ -define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION', 28); -/** - * Error code when a mirror does not exist but is called for in one of the set* - * methods. - */ -define('PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND', 32); -/** - * Error code when a server port is not numeric - */ -define('PEAR_CHANNELFILE_ERROR_INVALID_PORT', 33); -/** - * Error code when contains no version attribute - */ -define('PEAR_CHANNELFILE_ERROR_NO_STATICVERSION', 34); -/** - * Error code when contains no type attribute in a protocol definition - */ -define('PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE', 35); -/** - * Error code when a mirror is defined and the channel.xml represents the __uri pseudo-channel - */ -define('PEAR_CHANNELFILE_URI_CANT_MIRROR', 36); -/** - * Error code when ssl attribute is present and is not "yes" + * @since File available since Release 1.4.0a12 */ -define('PEAR_CHANNELFILE_ERROR_INVALID_SSL', 37); -/**#@-*/ /** - * Mirror types allowed. Currently only internet servers are recognized. + * For downloading REST xml/txt files */ -$GLOBALS['_PEAR_CHANNELS_MIRROR_TYPES'] = array('server'); - +require_once 'PEAR/REST.php'; /** - * The Channel handling class + * Implement REST 1.0 * * @category pear * @package PEAR * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 + * @since Class available since Release 1.4.0a12 */ -class PEAR_ChannelFile +class PEAR_REST_10 { /** - * @access private - * @var PEAR_ErrorStack - * @access private - */ - var $_stack; - - /** - * Supported channel.xml versions, for parsing - * @var array - * @access private - */ - var $_supportedVersions = array('1.0'); - - /** - * Parsed channel information - * @var array - * @access private + * @var PEAR_REST */ - var $_channelInfo; + var $_rest; + function PEAR_REST_10($config, $options = array()) + { + $this->_rest = &new PEAR_REST($config, $options); + } /** - * index into the subchannels array, used for parsing xml - * @var int - * @access private + * Retrieve information about a remote package to be downloaded from a REST server + * + * @param string $base The uri to prepend to all REST calls + * @param array $packageinfo an array of format: + *
+     *  array(
+     *   'package' => 'packagename',
+     *   'channel' => 'channelname',
+     *  ['state' => 'alpha' (or valid state),]
+     *  -or-
+     *  ['version' => '1.whatever']
+     * 
+ * @param string $prefstate Current preferred_state config variable value + * @param bool $installed the installed version of this package to compare against + * @return array|false|PEAR_Error see {@link _returnDownloadURL()} */ - var $_subchannelIndex; + function getDownloadURL($base, $packageinfo, $prefstate, $installed, $channel = false) + { + $states = $this->betterStates($prefstate, true); + if (!$states) { + return PEAR::raiseError('"' . $prefstate . '" is not a valid state'); + } - /** - * index into the mirrors array, used for parsing xml - * @var int - * @access private - */ - var $_mirrorIndex; + $channel = $packageinfo['channel']; + $package = $packageinfo['package']; + $state = isset($packageinfo['state']) ? $packageinfo['state'] : null; + $version = isset($packageinfo['version']) ? $packageinfo['version'] : null; + $restFile = $base . 'r/' . strtolower($package) . '/allreleases.xml'; - /** - * Flag used to determine the validity of parsed content - * @var boolean - * @access private - */ - var $_isValid = false; + $info = $this->_rest->retrieveData($restFile, false, false, $channel); + if (PEAR::isError($info)) { + return PEAR::raiseError('No releases available for package "' . + $channel . '/' . $package . '"'); + } - function PEAR_ChannelFile() - { - $this->_stack = &new PEAR_ErrorStack('PEAR_ChannelFile'); - $this->_stack->setErrorMessageTemplate($this->_getErrorMessage()); - $this->_isValid = false; - } + if (!isset($info['r'])) { + return false; + } - /** - * @return array - * @access protected - */ - function _getErrorMessage() - { - return - array( - PEAR_CHANNELFILE_ERROR_INVALID_VERSION => - 'While parsing channel.xml, an invalid version number "%version% was passed in, expecting one of %versions%', - PEAR_CHANNELFILE_ERROR_NO_VERSION => - 'No version number found in tag', - PEAR_CHANNELFILE_ERROR_NO_XML_EXT => - '%error%', - PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER => - 'Unable to create XML parser', - PEAR_CHANNELFILE_ERROR_PARSER_ERROR => - '%error%', - PEAR_CHANNELFILE_ERROR_NO_NAME => - 'Missing channel name', - PEAR_CHANNELFILE_ERROR_INVALID_NAME => - 'Invalid channel %tag% "%name%"', - PEAR_CHANNELFILE_ERROR_NO_SUMMARY => - 'Missing channel summary', - PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY => - 'Channel summary should be on one line, but is multi-line', - PEAR_CHANNELFILE_ERROR_NO_HOST => - 'Missing channel server for %type% server', - PEAR_CHANNELFILE_ERROR_INVALID_HOST => - 'Server name "%server%" is invalid for %type% server', - PEAR_CHANNELFILE_ERROR_INVALID_MIRROR => - 'Invalid mirror name "%name%", mirror type %type%', - PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE => - 'Invalid mirror type "%type%"', - PEAR_CHANNELFILE_ERROR_INVALID => - 'Cannot generate xml, contents are invalid', - PEAR_CHANNELFILE_ERROR_EMPTY_REGEX => - 'packagenameregex cannot be empty', - PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION => - '%parent% %protocol% function has no version', - PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME => - '%parent% %protocol% function has no name', - PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE => - '%parent% rest baseurl has no type', - PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME => - 'Validation package has no name in tag', - PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION => - 'Validation package "%package%" has no version', - PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND => - 'Mirror "%mirror%" does not exist', - PEAR_CHANNELFILE_ERROR_INVALID_PORT => - 'Port "%port%" must be numeric', - PEAR_CHANNELFILE_ERROR_NO_STATICVERSION => - ' tag must contain version attribute', - PEAR_CHANNELFILE_URI_CANT_MIRROR => - 'The __uri pseudo-channel cannot have mirrors', - PEAR_CHANNELFILE_ERROR_INVALID_SSL => - '%server% has invalid ssl attribute "%ssl%" can only be yes or not present', - ); - } + $release = $found = false; + if (!is_array($info['r']) || !isset($info['r'][0])) { + $info['r'] = array($info['r']); + } - /** - * @param string contents of package.xml file - * @return bool success of parsing - */ - function fromXmlString($data) - { - if (preg_match('/_supportedVersions)) { - $this->_stack->push(PEAR_CHANNELFILE_ERROR_INVALID_VERSION, 'error', - array('version' => $channelversion[1])); - return false; + foreach ($info['r'] as $release) { + if (!isset($this->_rest->_options['force']) && ($installed && + version_compare($release['v'], $installed, '<'))) { + continue; } - $parser = new PEAR_XMLParser; - $result = $parser->parse($data); - if ($result !== true) { - if ($result->getCode() == 1) { - $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_XML_EXT, 'error', - array('error' => $result->getMessage())); - } else { - $this->_stack->push(PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER, 'error'); + + if (isset($state)) { + // try our preferred state first + if ($release['s'] == $state) { + $found = true; + break; + } + // see if there is something newer and more stable + // bug #7221 + if (in_array($release['s'], $this->betterStates($state), true)) { + $found = true; + break; + } + } elseif (isset($version)) { + if ($release['v'] == $version) { + $found = true; + break; + } + } else { + if (in_array($release['s'], $states)) { + $found = true; + break; } - return false; } - $this->_channelInfo = $parser->getData(); - return true; - } else { - $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_VERSION, 'error', array('xml' => $data)); - return false; } - } - /** - * @return array - */ - function toArray() - { - if (!$this->_isValid && !$this->validate()) { - return false; - } - return $this->_channelInfo; + return $this->_returnDownloadURL($base, $package, $release, $info, $found, false, $channel); } - /** - * @param array - * @static - * @return PEAR_ChannelFile|false false if invalid - */ - function &fromArray($data, $compatibility = false, $stackClass = 'PEAR_ErrorStack') + function getDepDownloadURL($base, $xsdversion, $dependency, $deppackage, + $prefstate = 'stable', $installed = false, $channel = false) { - $a = new PEAR_ChannelFile($compatibility, $stackClass); - $a->_fromArray($data); - if (!$a->validate()) { - $a = false; - return $a; + $states = $this->betterStates($prefstate, true); + if (!$states) { + return PEAR::raiseError('"' . $prefstate . '" is not a valid state'); } - return $a; - } - /** - * Unlike {@link fromArray()} this does not do any validation - * @param array - * @static - * @return PEAR_ChannelFile - */ - function &fromArrayWithErrors($data, $compatibility = false, - $stackClass = 'PEAR_ErrorStack') - { - $a = new PEAR_ChannelFile($compatibility, $stackClass); - $a->_fromArray($data); - return $a; - } + $channel = $dependency['channel']; + $package = $dependency['name']; + $state = isset($dependency['state']) ? $dependency['state'] : null; + $version = isset($dependency['version']) ? $dependency['version'] : null; + $restFile = $base . 'r/' . strtolower($package) . '/allreleases.xml'; - /** - * @param array - * @access private - */ - function _fromArray($data) - { - $this->_channelInfo = $data; - } + $info = $this->_rest->retrieveData($restFile, false, false, $channel); + if (PEAR::isError($info)) { + return PEAR::raiseError('Package "' . $deppackage['channel'] . '/' . $deppackage['package'] + . '" dependency "' . $channel . '/' . $package . '" has no releases'); + } - /** - * Wrapper to {@link PEAR_ErrorStack::getErrors()} - * @param boolean determines whether to purge the error stack after retrieving - * @return array - */ - function getErrors($purge = false) - { - return $this->_stack->getErrors($purge); - } + if (!is_array($info) || !isset($info['r'])) { + return false; + } - /** - * Unindent given string (?) - * - * @param string $str The string that has to be unindented. - * @return string - * @access private - */ - function _unIndent($str) - { - // remove leading newlines - $str = preg_replace('/^[\r\n]+/', '', $str); - // find whitespace at the beginning of the first line - $indent_len = strspn($str, " \t"); - $indent = substr($str, 0, $indent_len); - $data = ''; - // remove the same amount of whitespace from following lines - foreach (explode("\n", $str) as $line) { - if (substr($line, 0, $indent_len) == $indent) { - $data .= substr($line, $indent_len) . "\n"; + $exclude = array(); + $min = $max = $recommended = false; + if ($xsdversion == '1.0') { + switch ($dependency['rel']) { + case 'ge' : + $min = $dependency['version']; + break; + case 'gt' : + $min = $dependency['version']; + $exclude = array($dependency['version']); + break; + case 'eq' : + $recommended = $dependency['version']; + break; + case 'lt' : + $max = $dependency['version']; + $exclude = array($dependency['version']); + break; + case 'le' : + $max = $dependency['version']; + break; + case 'ne' : + $exclude = array($dependency['version']); + break; + } + } else { + $min = isset($dependency['min']) ? $dependency['min'] : false; + $max = isset($dependency['max']) ? $dependency['max'] : false; + $recommended = isset($dependency['recommended']) ? + $dependency['recommended'] : false; + if (isset($dependency['exclude'])) { + if (!isset($dependency['exclude'][0])) { + $exclude = array($dependency['exclude']); + } } } - return $data; - } - - /** - * Parse a channel.xml file. Expects the name of - * a channel xml file as input. - * - * @param string $descfile name of channel xml file - * @return bool success of parsing - */ - function fromXmlFile($descfile) - { - if (!file_exists($descfile) || !is_file($descfile) || !is_readable($descfile) || - (!$fp = fopen($descfile, 'r'))) { - require_once 'PEAR.php'; - return PEAR::raiseError("Unable to open $descfile"); + $release = $found = false; + if (!is_array($info['r']) || !isset($info['r'][0])) { + $info['r'] = array($info['r']); } - - // read the whole thing so we only get one cdata callback - // for each block of cdata - fclose($fp); - $data = file_get_contents($descfile); - return $this->fromXmlString($data); - } - - /** - * Parse channel information from different sources - * - * This method is able to extract information about a channel - * from an .xml file or a string - * - * @access public - * @param string Filename of the source or the source itself - * @return bool - */ - function fromAny($info) - { - if (is_string($info) && file_exists($info) && strlen($info) < 255) { - $tmp = substr($info, -4); - if ($tmp == '.xml') { - $info = $this->fromXmlFile($info); - } else { - $fp = fopen($info, "r"); - $test = fread($fp, 5); - fclose($fp); - if ($test == "fromXmlFile($info); + foreach ($info['r'] as $release) { + if (!isset($this->_rest->_options['force']) && ($installed && + version_compare($release['v'], $installed, '<'))) { + continue; + } + if (in_array($release['v'], $exclude)) { // skip excluded versions + continue; + } + // allow newer releases to say "I'm OK with the dependent package" + if ($xsdversion == '2.0' && isset($release['co'])) { + if (!is_array($release['co']) || !isset($release['co'][0])) { + $release['co'] = array($release['co']); + } + foreach ($release['co'] as $entry) { + if (isset($entry['x']) && !is_array($entry['x'])) { + $entry['x'] = array($entry['x']); + } elseif (!isset($entry['x'])) { + $entry['x'] = array(); + } + if ($entry['c'] == $deppackage['channel'] && + strtolower($entry['p']) == strtolower($deppackage['package']) && + version_compare($deppackage['version'], $entry['min'], '>=') && + version_compare($deppackage['version'], $entry['max'], '<=') && + !in_array($release['v'], $entry['x'])) { + $recommended = $release['v']; + break; + } } } - if (PEAR::isError($info)) { - require_once 'PEAR.php'; - return PEAR::raiseError($info); + if ($recommended) { + if ($release['v'] != $recommended) { // if we want a specific + // version, then skip all others + continue; + } else { + if (!in_array($release['s'], $states)) { + // the stability is too low, but we must return the + // recommended version if possible + return $this->_returnDownloadURL($base, $package, $release, $info, true, false, $channel); + } + } + } + if ($min && version_compare($release['v'], $min, 'lt')) { // skip too old versions + continue; + } + if ($max && version_compare($release['v'], $max, 'gt')) { // skip too new versions + continue; + } + if ($installed && version_compare($release['v'], $installed, '<')) { + continue; + } + if (in_array($release['s'], $states)) { // if in the preferred state... + $found = true; // ... then use it + break; } } - if (is_string($info)) { - $info = $this->fromXmlString($info); - } - return $info; + return $this->_returnDownloadURL($base, $package, $release, $info, $found, false, $channel); } /** - * Return an XML document based on previous parsing and modifications - * - * @return string XML data + * Take raw data and return the array needed for processing a download URL * - * @access public + * @param string $base REST base uri + * @param string $package Package name + * @param array $release an array of format array('v' => version, 's' => state) + * describing the release to download + * @param array $info list of all releases as defined by allreleases.xml + * @param bool|null $found determines whether the release was found or this is the next + * best alternative. If null, then versions were skipped because + * of PHP dependency + * @return array|PEAR_Error + * @access private */ - function toXml() + function _returnDownloadURL($base, $package, $release, $info, $found, $phpversion = false, $channel = false) { - if (!$this->_isValid && !$this->validate()) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID); - return false; - } - if (!isset($this->_channelInfo['attribs']['version'])) { - $this->_channelInfo['attribs']['version'] = '1.0'; - } - $channelInfo = $this->_channelInfo; - $ret = "\n"; - $ret .= " - $channelInfo[name] - " . htmlspecialchars($channelInfo['summary'])." -"; - if (isset($channelInfo['suggestedalias'])) { - $ret .= ' ' . $channelInfo['suggestedalias'] . "\n"; - } - if (isset($channelInfo['validatepackage'])) { - $ret .= ' ' . - htmlspecialchars($channelInfo['validatepackage']['_content']) . - "\n"; - } - $ret .= " \n"; - $ret .= ' _makeRestXml($channelInfo['servers']['primary']['rest'], ' '); + + $packageLower = strtolower($package); + $pinfo = $this->_rest->retrieveCacheFirst($base . 'p/' . $packageLower . '/' . + 'info.xml', false, false, $channel); + if (PEAR::isError($pinfo)) { + return PEAR::raiseError('Package "' . $package . + '" does not have REST info xml available'); } - $ret .= " \n"; - if (isset($channelInfo['servers']['mirror'])) { - $ret .= $this->_makeMirrorsXml($channelInfo); + + $releaseinfo = $this->_rest->retrieveCacheFirst($base . 'r/' . $packageLower . '/' . + $release['v'] . '.xml', false, false, $channel); + if (PEAR::isError($releaseinfo)) { + return PEAR::raiseError('Package "' . $package . '" Version "' . $release['v'] . + '" does not have REST xml available'); } - $ret .= " \n"; - $ret .= ""; - return str_replace("\r", "\n", str_replace("\r\n", "\n", $ret)); - } - /** - * Generate the tag - * @access private - */ - function _makeRestXml($info, $indent) - { - $ret = $indent . "\n"; - if (!isset($info['baseurl'][0])) { - $info['baseurl'] = array($info['baseurl']); + $packagexml = $this->_rest->retrieveCacheFirst($base . 'r/' . $packageLower . '/' . + 'deps.' . $release['v'] . '.txt', false, true, $channel); + if (PEAR::isError($packagexml)) { + return PEAR::raiseError('Package "' . $package . '" Version "' . $release['v'] . + '" does not have REST dependency information available'); } - foreach ($info['baseurl'] as $url) { - $ret .= "$indent \n"; + + $packagexml = unserialize($packagexml); + if (!$packagexml) { + $packagexml = array(); } - $ret .= $indent . "\n"; - return $ret; - } - /** - * Generate the tag - * @access private - */ - function _makeMirrorsXml($channelInfo) - { - $ret = ""; - if (!isset($channelInfo['servers']['mirror'][0])) { - $channelInfo['servers']['mirror'] = array($channelInfo['servers']['mirror']); + $allinfo = $this->_rest->retrieveData($base . 'r/' . $packageLower . + '/allreleases.xml', false, false, $channel); + if (!is_array($allinfo['r']) || !isset($allinfo['r'][0])) { + $allinfo['r'] = array($allinfo['r']); } - foreach ($channelInfo['servers']['mirror'] as $mirror) { - $ret .= ' _makeRestXml($mirror['rest'], ' '); + + $compatible = array(); + if (!is_array($release['co']) || !isset($release['co'][0])) { + $release['co'] = array($release['co']); + } + + foreach ($release['co'] as $entry) { + $comp = array(); + $comp['name'] = $entry['p']; + $comp['channel'] = $entry['c']; + $comp['min'] = $entry['min']; + $comp['max'] = $entry['max']; + if (isset($entry['x']) && !is_array($entry['x'])) { + $comp['exclude'] = $entry['x']; } - $ret .= " \n"; + + $compatible[] = $comp; + } + + if (count($compatible) == 1) { + $compatible = $compatible[0]; + } + + break; + } + + $deprecated = false; + if (isset($pinfo['dc']) && isset($pinfo['dp'])) { + if (is_array($pinfo['dp'])) { + $deprecated = array('channel' => (string) $pinfo['dc'], + 'package' => trim($pinfo['dp']['_content'])); } else { - $ret .= "/>\n"; + $deprecated = array('channel' => (string) $pinfo['dc'], + 'package' => trim($pinfo['dp'])); } } - return $ret; + + $return = array( + 'version' => $releaseinfo['v'], + 'info' => $packagexml, + 'package' => $releaseinfo['p']['_content'], + 'stability' => $releaseinfo['st'], + 'compatible' => $compatible, + 'deprecated' => $deprecated, + ); + + if ($found) { + $return['url'] = $releaseinfo['g']; + return $return; + } + + $return['php'] = $phpversion; + return $return; } - /** - * Generate the tag - * @access private - */ - function _makeFunctionsXml($functions, $indent, $rest = false) + function listPackages($base, $channel = false) { - $ret = ''; - if (!isset($functions[0])) { - $functions = array($functions); + $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel); + if (PEAR::isError($packagelist)) { + return $packagelist; } - foreach ($functions as $function) { - $ret .= "$indent\n"; + + if (!is_array($packagelist) || !isset($packagelist['p'])) { + return array(); } - return $ret; - } - /** - * Validation error. Also marks the object contents as invalid - * @param error code - * @param array error information - * @access private - */ - function _validateError($code, $params = array()) - { - $this->_stack->push($code, 'error', $params); - $this->_isValid = false; - } + if (!is_array($packagelist['p'])) { + $packagelist['p'] = array($packagelist['p']); + } - /** - * Validation warning. Does not mark the object contents invalid. - * @param error code - * @param array error information - * @access private - */ - function _validateWarning($code, $params = array()) - { - $this->_stack->push($code, 'warning', $params); + return $packagelist['p']; } /** - * Validate parsed file. + * List all categories of a REST server * - * @access public - * @return boolean + * @param string $base base URL of the server + * @return array of categorynames */ - function validate() + function listCategories($base, $channel = false) { - $this->_isValid = true; - $info = $this->_channelInfo; - if (empty($info['name'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_NAME); - } elseif (!$this->validChannelServer($info['name'])) { - if ($info['name'] != '__uri') { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, array('tag' => 'name', - 'name' => $info['name'])); - } - } - if (empty($info['summary'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY); - } elseif (strpos(trim($info['summary']), "\n") !== false) { - $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY, - array('summary' => $info['summary'])); - } - if (isset($info['suggestedalias'])) { - if (!$this->validChannelServer($info['suggestedalias'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, - array('tag' => 'suggestedalias', 'name' =>$info['suggestedalias'])); - } - } - if (isset($info['localalias'])) { - if (!$this->validChannelServer($info['localalias'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, - array('tag' => 'localalias', 'name' =>$info['localalias'])); - } - } - if (isset($info['validatepackage'])) { - if (!isset($info['validatepackage']['_content'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME); - } - if (!isset($info['validatepackage']['attribs']['version'])) { - $content = isset($info['validatepackage']['_content']) ? - $info['validatepackage']['_content'] : - null; - $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION, - array('package' => $content)); - } - } + $categories = array(); - if (isset($info['servers']['primary']['attribs'], $info['servers']['primary']['attribs']['port']) && - !is_numeric($info['servers']['primary']['attribs']['port'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_PORT, - array('port' => $info['servers']['primary']['attribs']['port'])); + // c/categories.xml does not exist; + // check for every package its category manually + // This is SLOOOWWWW : /// + $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel); + if (PEAR::isError($packagelist)) { + return $packagelist; } - if (isset($info['servers']['primary']['attribs'], $info['servers']['primary']['attribs']['ssl']) && - $info['servers']['primary']['attribs']['ssl'] != 'yes') { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL, - array('ssl' => $info['servers']['primary']['attribs']['ssl'], - 'server' => $info['name'])); + if (!is_array($packagelist) || !isset($packagelist['p'])) { + $ret = array(); + return $ret; } - if (isset($info['servers']['primary']['rest']) && - isset($info['servers']['primary']['rest']['baseurl'])) { - $this->_validateFunctions('rest', $info['servers']['primary']['rest']['baseurl']); + if (!is_array($packagelist['p'])) { + $packagelist['p'] = array($packagelist['p']); } - if (isset($info['servers']['mirror'])) { - if ($this->_channelInfo['name'] == '__uri') { - $this->_validateError(PEAR_CHANNELFILE_URI_CANT_MIRROR); - } - if (!isset($info['servers']['mirror'][0])) { - $info['servers']['mirror'] = array($info['servers']['mirror']); - } - foreach ($info['servers']['mirror'] as $mirror) { - if (!isset($mirror['attribs']['host'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_HOST, - array('type' => 'mirror')); - } elseif (!$this->validChannelServer($mirror['attribs']['host'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_HOST, - array('server' => $mirror['attribs']['host'], 'type' => 'mirror')); - } - if (isset($mirror['attribs']['ssl']) && $mirror['attribs']['ssl'] != 'yes') { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL, - array('ssl' => $info['ssl'], 'server' => $mirror['attribs']['host'])); + + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + foreach ($packagelist['p'] as $package) { + $inf = $this->_rest->retrieveData($base . 'p/' . strtolower($package) . '/info.xml', false, false, $channel); + if (PEAR::isError($inf)) { + PEAR::popErrorHandling(); + return $inf; } - if (isset($mirror['rest'])) { - $this->_validateFunctions('rest', $mirror['rest']['baseurl'], - $mirror['attribs']['host']); + $cat = $inf['ca']['_content']; + if (!isset($categories[$cat])) { + $categories[$cat] = $inf['ca']; } - } } - return $this->_isValid; + + return array_values($categories); } /** - * @param string rest - protocol name this function applies to - * @param array the functions - * @param string the name of the parent element (mirror name, for instance) + * List a category of a REST server + * + * @param string $base base URL of the server + * @param string $category name of the category + * @param boolean $info also download full package info + * @return array of packagenames */ - function _validateFunctions($protocol, $functions, $parent = '') + function listCategory($base, $category, $info = false, $channel = false) { - if (!isset($functions[0])) { - $functions = array($functions); + // gives '404 Not Found' error when category doesn't exist + $packagelist = $this->_rest->retrieveData($base.'c/'.urlencode($category).'/packages.xml', false, false, $channel); + if (PEAR::isError($packagelist)) { + return $packagelist; } - foreach ($functions as $function) { - if (!isset($function['_content']) || empty($function['_content'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME, - array('parent' => $parent, 'protocol' => $protocol)); - } - if ($protocol == 'rest') { - if (!isset($function['attribs']['type']) || - empty($function['attribs']['type'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_BASEURLTYPE, - array('parent' => $parent, 'protocol' => $protocol)); - } - } else { - if (!isset($function['attribs']['version']) || - empty($function['attribs']['version'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION, - array('parent' => $parent, 'protocol' => $protocol)); - } - } - } - } - /** - * Test whether a string contains a valid channel server. - * @param string $ver the package version to test - * @return bool - */ - function validChannelServer($server) - { - if ($server == '__uri') { - return true; + if (!is_array($packagelist) || !isset($packagelist['p'])) { + return array(); } - return (bool) preg_match(PEAR_CHANNELS_SERVER_PREG, $server); - } - /** - * @return string|false - */ - function getName() - { - if (isset($this->_channelInfo['name'])) { - return $this->_channelInfo['name']; + if (!is_array($packagelist['p']) || + !isset($packagelist['p'][0])) { // only 1 pkg + $packagelist = array($packagelist['p']); + } else { + $packagelist = $packagelist['p']; } - return false; - } - - /** - * @return string|false - */ - function getServer() - { - if (isset($this->_channelInfo['name'])) { - return $this->_channelInfo['name']; + if ($info == true) { + // get individual package info + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + foreach ($packagelist as $i => $packageitem) { + $url = sprintf('%s'.'r/%s/latest.txt', + $base, + strtolower($packageitem['_content'])); + $version = $this->_rest->retrieveData($url, false, false, $channel); + if (PEAR::isError($version)) { + break; // skipit + } + $url = sprintf('%s'.'r/%s/%s.xml', + $base, + strtolower($packageitem['_content']), + $version); + $info = $this->_rest->retrieveData($url, false, false, $channel); + if (PEAR::isError($info)) { + break; // skipit + } + $packagelist[$i]['info'] = $info; + } + PEAR::popErrorHandling(); } - return false; + return $packagelist; } - /** - * @return int|80 port number to connect to - */ - function getPort($mirror = false) - { - if ($mirror) { - if ($mir = $this->getMirror($mirror)) { - if (isset($mir['attribs']['port'])) { - return $mir['attribs']['port']; - } - - if ($this->getSSL($mirror)) { - return 443; - } - - return 80; - } - return false; + function listAll($base, $dostable, $basic = true, $searchpackage = false, $searchsummary = false, $channel = false) + { + $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel); + if (PEAR::isError($packagelist)) { + return $packagelist; } - - if (isset($this->_channelInfo['servers']['primary']['attribs']['port'])) { - return $this->_channelInfo['servers']['primary']['attribs']['port']; + if ($this->_rest->config->get('verbose') > 0) { + $ui = &PEAR_Frontend::singleton(); + $ui->log('Retrieving data...0%', true); } - - if ($this->getSSL()) { - return 443; + $ret = array(); + if (!is_array($packagelist) || !isset($packagelist['p'])) { + return $ret; + } + if (!is_array($packagelist['p'])) { + $packagelist['p'] = array($packagelist['p']); } - return 80; - } - - /** - * @return bool Determines whether secure sockets layer (SSL) is used to connect to this channel - */ - function getSSL($mirror = false) - { - if ($mirror) { - if ($mir = $this->getMirror($mirror)) { - if (isset($mir['attribs']['ssl'])) { - return true; + // only search-packagename = quicksearch ! + if ($searchpackage && (!$searchsummary || empty($searchpackage))) { + $newpackagelist = array(); + foreach ($packagelist['p'] as $package) { + if (!empty($searchpackage) && stristr($package, $searchpackage) !== false) { + $newpackagelist[] = $package; } - - return false; } - - return false; + $packagelist['p'] = $newpackagelist; } + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $next = .1; + foreach ($packagelist['p'] as $progress => $package) { + if ($this->_rest->config->get('verbose') > 0) { + if ($progress / count($packagelist['p']) >= $next) { + if ($next == .5) { + $ui->log('50%', false); + } else { + $ui->log('.', false); + } + $next += .1; + } + } - if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) { - return true; + if ($basic) { // remote-list command + if ($dostable) { + $latest = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . + '/stable.txt', false, false, $channel); + } else { + $latest = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . + '/latest.txt', false, false, $channel); + } + if (PEAR::isError($latest)) { + $latest = false; + } + $info = array('stable' => $latest); + } else { // list-all command + $inf = $this->_rest->retrieveData($base . 'p/' . strtolower($package) . '/info.xml', false, false, $channel); + if (PEAR::isError($inf)) { + PEAR::popErrorHandling(); + return $inf; + } + if ($searchpackage) { + $found = (!empty($searchpackage) && stristr($package, $searchpackage) !== false); + if (!$found && !(isset($searchsummary) && !empty($searchsummary) + && (stristr($inf['s'], $searchsummary) !== false + || stristr($inf['d'], $searchsummary) !== false))) + { + continue; + }; + } + $releases = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . + '/allreleases.xml', false, false, $channel); + if (PEAR::isError($releases)) { + continue; + } + if (!isset($releases['r'][0])) { + $releases['r'] = array($releases['r']); + } + unset($latest); + unset($unstable); + unset($stable); + unset($state); + foreach ($releases['r'] as $release) { + if (!isset($latest)) { + if ($dostable && $release['s'] == 'stable') { + $latest = $release['v']; + $state = 'stable'; + } + if (!$dostable) { + $latest = $release['v']; + $state = $release['s']; + } + } + if (!isset($stable) && $release['s'] == 'stable') { + $stable = $release['v']; + if (!isset($unstable)) { + $unstable = $stable; + } + } + if (!isset($unstable) && $release['s'] != 'stable') { + $latest = $unstable = $release['v']; + $state = $release['s']; + } + if (isset($latest) && !isset($state)) { + $state = $release['s']; + } + if (isset($latest) && isset($stable) && isset($unstable)) { + break; + } + } + $deps = array(); + if (!isset($unstable)) { + $unstable = false; + $state = 'stable'; + if (isset($stable)) { + $latest = $unstable = $stable; + } + } else { + $latest = $unstable; + } + if (!isset($latest)) { + $latest = false; + } + if ($latest) { + $d = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/deps.' . + $latest . '.txt', false, false, $channel); + if (!PEAR::isError($d)) { + $d = unserialize($d); + if ($d) { + if (isset($d['required'])) { + if (!class_exists('PEAR_PackageFile_v2')) { + require_once 'PEAR/PackageFile/v2.php'; + } + if (!isset($pf)) { + $pf = new PEAR_PackageFile_v2; + } + $pf->setDeps($d); + $tdeps = $pf->getDeps(); + } else { + $tdeps = $d; + } + foreach ($tdeps as $dep) { + if ($dep['type'] !== 'pkg') { + continue; + } + $deps[] = $dep; + } + } + } + } + if (!isset($stable)) { + $stable = '-n/a-'; + } + if (!$searchpackage) { + $info = array('stable' => $latest, 'summary' => $inf['s'], 'description' => + $inf['d'], 'deps' => $deps, 'category' => $inf['ca']['_content'], + 'unstable' => $unstable, 'state' => $state); + } else { + $info = array('stable' => $stable, 'summary' => $inf['s'], 'description' => + $inf['d'], 'deps' => $deps, 'category' => $inf['ca']['_content'], + 'unstable' => $unstable, 'state' => $state); + } + } + $ret[$package] = $info; } - - return false; + PEAR::popErrorHandling(); + return $ret; } - /** - * @return string|false - */ - function getSummary() + function listLatestUpgrades($base, $pref_state, $installed, $channel, &$reg) { - if (isset($this->_channelInfo['summary'])) { - return $this->_channelInfo['summary']; + $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel); + if (PEAR::isError($packagelist)) { + return $packagelist; } - return false; - } + $ret = array(); + if (!is_array($packagelist) || !isset($packagelist['p'])) { + return $ret; + } - /** - * @param string protocol type - * @param string Mirror name - * @return array|false - */ - function getFunctions($protocol, $mirror = false) - { - if ($this->getName() == '__uri') { - return false; + if (!is_array($packagelist['p'])) { + $packagelist['p'] = array($packagelist['p']); } - $function = $protocol == 'rest' ? 'baseurl' : 'function'; - if ($mirror) { - if ($mir = $this->getMirror($mirror)) { - if (isset($mir[$protocol][$function])) { - return $mir[$protocol][$function]; - } + foreach ($packagelist['p'] as $package) { + if (!isset($installed[strtolower($package)])) { + continue; } - return false; - } + $inst_version = $reg->packageInfo($package, 'version', $channel); + $inst_state = $reg->packageInfo($package, 'release_state', $channel); + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $info = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . + '/allreleases.xml', false, false, $channel); + PEAR::popErrorHandling(); + if (PEAR::isError($info)) { + continue; // no remote releases + } - if (isset($this->_channelInfo['servers']['primary'][$protocol][$function])) { - return $this->_channelInfo['servers']['primary'][$protocol][$function]; - } + if (!isset($info['r'])) { + continue; + } - return false; - } + $release = $found = false; + if (!is_array($info['r']) || !isset($info['r'][0])) { + $info['r'] = array($info['r']); + } - /** - * @param string Protocol type - * @param string Function name (null to return the - * first protocol of the type requested) - * @param string Mirror name, if any - * @return array - */ - function getFunction($type, $name = null, $mirror = false) - { - $protocols = $this->getFunctions($type, $mirror); - if (!$protocols) { - return false; - } + // $info['r'] is sorted by version number + usort($info['r'], array($this, '_sortReleasesByVersionNumber')); + foreach ($info['r'] as $release) { + if ($inst_version && version_compare($release['v'], $inst_version, '<=')) { + // not newer than the one installed + break; + } - foreach ($protocols as $protocol) { - if ($name === null) { - return $protocol; + // new version > installed version + if (!$pref_state) { + // every state is a good state + $found = true; + break; + } else { + $new_state = $release['s']; + // if new state >= installed state: go + if (in_array($new_state, $this->betterStates($inst_state, true))) { + $found = true; + break; + } else { + // only allow to lower the state of package, + // if new state >= preferred state: go + if (in_array($new_state, $this->betterStates($pref_state, true))) { + $found = true; + break; + } + } + } } - if ($protocol['_content'] != $name) { + if (!$found) { continue; } - return $protocol; + $relinfo = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/' . + $release['v'] . '.xml', false, false, $channel); + if (PEAR::isError($relinfo)) { + return $relinfo; + } + + $ret[$package] = array( + 'version' => $release['v'], + 'state' => $release['s'], + 'filesize' => $relinfo['f'], + ); } - return false; - } + return $ret; + } - /** - * @param string protocol type - * @param string protocol name - * @param string version - * @param string mirror name - * @return boolean - */ - function supports($type, $name = null, $mirror = false, $version = '1.0') + function packageInfo($base, $package, $channel = false) { - $protocols = $this->getFunctions($type, $mirror); - if (!$protocols) { - return false; + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $pinfo = $this->_rest->retrieveData($base . 'p/' . strtolower($package) . '/info.xml', false, false, $channel); + if (PEAR::isError($pinfo)) { + PEAR::popErrorHandling(); + return PEAR::raiseError('Unknown package: "' . $package . '" in channel "' . $channel . '"' . "\n". 'Debug: ' . + $pinfo->getMessage()); } - foreach ($protocols as $protocol) { - if ($protocol['attribs']['version'] != $version) { - continue; + $releases = array(); + $allreleases = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . + '/allreleases.xml', false, false, $channel); + if (!PEAR::isError($allreleases)) { + if (!class_exists('PEAR_PackageFile_v2')) { + require_once 'PEAR/PackageFile/v2.php'; } - if ($name === null) { - return true; + if (!is_array($allreleases['r']) || !isset($allreleases['r'][0])) { + $allreleases['r'] = array($allreleases['r']); } - if ($protocol['_content'] != $name) { - continue; + $pf = new PEAR_PackageFile_v2; + foreach ($allreleases['r'] as $release) { + $ds = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/deps.' . + $release['v'] . '.txt', false, false, $channel); + if (PEAR::isError($ds)) { + continue; + } + + if (!isset($latest)) { + $latest = $release['v']; + } + + $pf->setDeps(unserialize($ds)); + $ds = $pf->getDeps(); + $info = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) + . '/' . $release['v'] . '.xml', false, false, $channel); + + if (PEAR::isError($info)) { + continue; + } + + $releases[$release['v']] = array( + 'doneby' => $info['m'], + 'license' => $info['l'], + 'summary' => $info['s'], + 'description' => $info['d'], + 'releasedate' => $info['da'], + 'releasenotes' => $info['n'], + 'state' => $release['s'], + 'deps' => $ds ? $ds : array(), + ); + } + } else { + $latest = ''; + } + + PEAR::popErrorHandling(); + if (isset($pinfo['dc']) && isset($pinfo['dp'])) { + if (is_array($pinfo['dp'])) { + $deprecated = array('channel' => (string) $pinfo['dc'], + 'package' => trim($pinfo['dp']['_content'])); + } else { + $deprecated = array('channel' => (string) $pinfo['dc'], + 'package' => trim($pinfo['dp'])); } + } else { + $deprecated = false; + } - return true; + if (!isset($latest)) { + $latest = ''; } - return false; + return array( + 'name' => $pinfo['n'], + 'channel' => $pinfo['c'], + 'category' => $pinfo['ca']['_content'], + 'stable' => $latest, + 'license' => $pinfo['l'], + 'summary' => $pinfo['s'], + 'description' => $pinfo['d'], + 'releases' => $releases, + 'deprecated' => $deprecated, + ); } /** - * Determines whether a channel supports Representational State Transfer (REST) protocols - * for retrieving channel information - * @param string - * @return bool + * Return an array containing all of the states that are more stable than + * or equal to the passed in state + * + * @param string Release state + * @param boolean Determines whether to include $state in the list + * @return false|array False if $state is not a valid release state */ - function supportsREST($mirror = false) + function betterStates($state, $include = false) { - if ($mirror == $this->_channelInfo['name']) { - $mirror = false; + static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable'); + $i = array_search($state, $states); + if ($i === false) { + return false; } - if ($mirror) { - if ($mir = $this->getMirror($mirror)) { - return isset($mir['rest']); - } - - return false; + if ($include) { + $i--; } - return isset($this->_channelInfo['servers']['primary']['rest']); + return array_slice($states, $i + 1); } /** - * Get the URL to access a base resource. + * Sort releases by version number * - * Hyperlinks in the returned xml will be used to retrieve the proper information - * needed. This allows extreme extensibility and flexibility in implementation - * @param string Resource Type to retrieve + * @access private */ - function getBaseURL($resourceType, $mirror = false) + function _sortReleasesByVersionNumber($a, $b) { - if ($mirror == $this->_channelInfo['name']) { - $mirror = false; - } - - if ($mirror) { - $mir = $this->getMirror($mirror); - if (!$mir) { - return false; - } - - $rest = $mir['rest']; - } else { - $rest = $this->_channelInfo['servers']['primary']['rest']; + if (version_compare($a['v'], $b['v'], '=')) { + return 0; } - if (!isset($rest['baseurl'][0])) { - $rest['baseurl'] = array($rest['baseurl']); + if (version_compare($a['v'], $b['v'], '>')) { + return -1; } - foreach ($rest['baseurl'] as $baseurl) { - if (strtolower($baseurl['attribs']['type']) == strtolower($resourceType)) { - return $baseurl['_content']; - } + if (version_compare($a['v'], $b['v'], '<')) { + return 1; } - - return false; } +}PEAR-1.9.0/PEAR/REST/11.php100664 764 764 26054 100664 7573 + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: 11.php 286670 2009-08-02 14:16:06Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.3 + */ + +/** + * For downloading REST xml/txt files + */ +require_once 'PEAR/REST.php'; +/** + * Implement REST 1.1 + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.3 + */ +class PEAR_REST_11 +{ /** - * Since REST does not implement RPC, provide this as a logical wrapper around - * resetFunctions for REST - * @param string|false mirror name, if any + * @var PEAR_REST */ - function resetREST($mirror = false) + var $_rest; + + function PEAR_REST_11($config, $options = array()) { - return $this->resetFunctions('rest', $mirror); + $this->_rest = &new PEAR_REST($config, $options); } - /** - * Empty all protocol definitions - * @param string protocol type - * @param string|false mirror name, if any - */ - function resetFunctions($type, $mirror = false) + function listAll($base, $dostable, $basic = true, $searchpackage = false, $searchsummary = false, $channel = false) { - if ($mirror) { - if (isset($this->_channelInfo['servers']['mirror'])) { - $mirrors = $this->_channelInfo['servers']['mirror']; - if (!isset($mirrors[0])) { - $mirrors = array($mirrors); - } + $categorylist = $this->_rest->retrieveData($base . 'c/categories.xml', false, false, $channel); + if (PEAR::isError($categorylist)) { + return $categorylist; + } - foreach ($mirrors as $i => $mir) { - if ($mir['attribs']['host'] == $mirror) { - if (isset($this->_channelInfo['servers']['mirror'][$i][$type])) { - unset($this->_channelInfo['servers']['mirror'][$i][$type]); - } + $ret = array(); + if (!is_array($categorylist['c']) || !isset($categorylist['c'][0])) { + $categorylist['c'] = array($categorylist['c']); + } - return true; - } - } + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - return false; + foreach ($categorylist['c'] as $progress => $category) { + $category = $category['_content']; + $packagesinfo = $this->_rest->retrieveData($base . + 'c/' . urlencode($category) . '/packagesinfo.xml', false, false, $channel); + + if (PEAR::isError($packagesinfo)) { + continue; } - return false; - } + if (!is_array($packagesinfo) || !isset($packagesinfo['pi'])) { + continue; + } - if (isset($this->_channelInfo['servers']['primary'][$type])) { - unset($this->_channelInfo['servers']['primary'][$type]); - } + if (!is_array($packagesinfo['pi']) || !isset($packagesinfo['pi'][0])) { + $packagesinfo['pi'] = array($packagesinfo['pi']); + } - return true; - } + foreach ($packagesinfo['pi'] as $packageinfo) { + if (empty($packageinfo)) { + continue; + } - /** - * Set a channel's protocols to the protocols supported by pearweb - */ - function setDefaultPEARProtocols($version = '1.0', $mirror = false) - { - switch ($version) { - case '1.0' : - $this->resetREST($mirror); - return true; - break; - default : - return false; - break; - } - } + $info = $packageinfo['p']; + $package = $info['n']; + $releases = isset($packageinfo['a']) ? $packageinfo['a'] : false; + unset($latest); + unset($unstable); + unset($stable); + unset($state); - /** - * @return array - */ - function getMirrors() - { - if (isset($this->_channelInfo['servers']['mirror'])) { - $mirrors = $this->_channelInfo['servers']['mirror']; - if (!isset($mirrors[0])) { - $mirrors = array($mirrors); - } + if ($releases) { + if (!isset($releases['r'][0])) { + $releases['r'] = array($releases['r']); + } - return $mirrors; - } + foreach ($releases['r'] as $release) { + if (!isset($latest)) { + if ($dostable && $release['s'] == 'stable') { + $latest = $release['v']; + $state = 'stable'; + } + if (!$dostable) { + $latest = $release['v']; + $state = $release['s']; + } + } - return array(); - } + if (!isset($stable) && $release['s'] == 'stable') { + $stable = $release['v']; + if (!isset($unstable)) { + $unstable = $stable; + } + } - /** - * Get the unserialized XML representing a mirror - * @return array|false - */ - function getMirror($server) - { - foreach ($this->getMirrors() as $mirror) { - if ($mirror['attribs']['host'] == $server) { - return $mirror; - } - } + if (!isset($unstable) && $release['s'] != 'stable') { + $unstable = $release['v']; + $state = $release['s']; + } - return false; - } + if (isset($latest) && !isset($state)) { + $state = $release['s']; + } - /** - * @param string - * @return string|false - * @error PEAR_CHANNELFILE_ERROR_NO_NAME - * @error PEAR_CHANNELFILE_ERROR_INVALID_NAME - */ - function setName($name) - { - return $this->setServer($name); - } + if (isset($latest) && isset($stable) && isset($unstable)) { + break; + } + } + } - /** - * Set the socket number (port) that is used to connect to this channel - * @param integer - * @param string|false name of the mirror server, or false for the primary - */ - function setPort($port, $mirror = false) - { - if ($mirror) { - if (!isset($this->_channelInfo['servers']['mirror'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, - array('mirror' => $mirror)); - return false; - } + if ($basic) { // remote-list command + if (!isset($latest)) { + $latest = false; + } - if (isset($this->_channelInfo['servers']['mirror'][0])) { - foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { - if ($mirror == $mir['attribs']['host']) { - $this->_channelInfo['servers']['mirror'][$i]['attribs']['port'] = $port; - return true; + if ($dostable) { + // $state is not set if there are no releases + if (isset($state) && $state == 'stable') { + $ret[$package] = array('stable' => $latest); + } else { + $ret[$package] = array('stable' => '-n/a-'); + } + } else { + $ret[$package] = array('stable' => $latest); } + + continue; } - return false; - } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { - $this->_channelInfo['servers']['mirror']['attribs']['port'] = $port; - $this->_isValid = false; - return true; - } - } + // list-all command + if (!isset($unstable)) { + $unstable = false; + $state = 'stable'; + if (isset($stable)) { + $latest = $unstable = $stable; + } + } else { + $latest = $unstable; + } - $this->_channelInfo['servers']['primary']['attribs']['port'] = $port; - $this->_isValid = false; - return true; - } + if (!isset($latest)) { + $latest = false; + } - /** - * Set the socket number (port) that is used to connect to this channel - * @param bool Determines whether to turn on SSL support or turn it off - * @param string|false name of the mirror server, or false for the primary - */ - function setSSL($ssl = true, $mirror = false) - { - if ($mirror) { - if (!isset($this->_channelInfo['servers']['mirror'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, - array('mirror' => $mirror)); - return false; - } + $deps = array(); + if ($latest && isset($packageinfo['deps'])) { + if (!is_array($packageinfo['deps']) || + !isset($packageinfo['deps'][0]) + ) { + $packageinfo['deps'] = array($packageinfo['deps']); + } - if (isset($this->_channelInfo['servers']['mirror'][0])) { - foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { - if ($mirror == $mir['attribs']['host']) { - if (!$ssl) { - if (isset($this->_channelInfo['servers']['mirror'][$i] - ['attribs']['ssl'])) { - unset($this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl']); + $d = false; + foreach ($packageinfo['deps'] as $dep) { + if ($dep['v'] == $latest) { + $d = unserialize($dep['d']); + } + } + + if ($d) { + if (isset($d['required'])) { + if (!class_exists('PEAR_PackageFile_v2')) { + require_once 'PEAR/PackageFile/v2.php'; + } + + if (!isset($pf)) { + $pf = new PEAR_PackageFile_v2; } + + $pf->setDeps($d); + $tdeps = $pf->getDeps(); } else { - $this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl'] = 'yes'; + $tdeps = $d; } - return true; - } - } + foreach ($tdeps as $dep) { + if ($dep['type'] !== 'pkg') { + continue; + } - return false; - } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { - if (!$ssl) { - if (isset($this->_channelInfo['servers']['mirror']['attribs']['ssl'])) { - unset($this->_channelInfo['servers']['mirror']['attribs']['ssl']); + $deps[] = $dep; + } } - } else { - $this->_channelInfo['servers']['mirror']['attribs']['ssl'] = 'yes'; } - $this->_isValid = false; - return true; - } - } - - if ($ssl) { - $this->_channelInfo['servers']['primary']['attribs']['ssl'] = 'yes'; - } else { - if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) { - unset($this->_channelInfo['servers']['primary']['attribs']['ssl']); + $info = array( + 'stable' => $latest, + 'summary' => $info['s'], + 'description' => $info['d'], + 'deps' => $deps, + 'category' => $info['ca']['_content'], + 'unstable' => $unstable, + 'state' => $state + ); + $ret[$package] = $info; } } - $this->_isValid = false; - return true; + PEAR::popErrorHandling(); + return $ret; } /** - * @param string - * @return string|false - * @error PEAR_CHANNELFILE_ERROR_NO_SERVER - * @error PEAR_CHANNELFILE_ERROR_INVALID_SERVER + * List all categories of a REST server + * + * @param string $base base URL of the server + * @return array of categorynames */ - function setServer($server, $mirror = false) + function listCategories($base, $channel = false) { - if (empty($server)) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SERVER); - return false; - } elseif (!$this->validChannelServer($server)) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, - array('tag' => 'name', 'name' => $server)); - return false; + $categorylist = $this->_rest->retrieveData($base . 'c/categories.xml', false, false, $channel); + if (PEAR::isError($categorylist)) { + return $categorylist; } - if ($mirror) { - $found = false; - foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { - if ($mirror == $mir['attribs']['host']) { - $found = true; - break; - } - } - - if (!$found) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, - array('mirror' => $mirror)); - return false; - } + if (!is_array($categorylist) || !isset($categorylist['c'])) { + return array(); + } - $this->_channelInfo['mirror'][$i]['attribs']['host'] = $server; - return true; + if (isset($categorylist['c']['_content'])) { + // only 1 category + $categorylist['c'] = array($categorylist['c']); } - $this->_channelInfo['name'] = $server; - return true; + return $categorylist['c']; } /** - * @param string - * @return boolean success - * @error PEAR_CHANNELFILE_ERROR_NO_SUMMARY - * @warning PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY + * List packages in a category of a REST server + * + * @param string $base base URL of the server + * @param string $category name of the category + * @param boolean $info also download full package info + * @return array of packagenames */ - function setSummary($summary) + function listCategory($base, $category, $info = false, $channel = false) { - if (empty($summary)) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY); - return false; - } elseif (strpos(trim($summary), "\n") !== false) { - $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY, - array('summary' => $summary)); + if ($info == false) { + $url = '%s'.'c/%s/packages.xml'; + } else { + $url = '%s'.'c/%s/packagesinfo.xml'; } + $url = sprintf($url, + $base, + urlencode($category)); - $this->_channelInfo['summary'] = $summary; - return true; - } + // gives '404 Not Found' error when category doesn't exist + $packagelist = $this->_rest->retrieveData($url, false, false, $channel); + if (PEAR::isError($packagelist)) { + return $packagelist; + } + if (!is_array($packagelist)) { + return array(); + } - /** - * @param string - * @param boolean determines whether the alias is in channel.xml or local - * @return boolean success - */ - function setAlias($alias, $local = false) - { - if (!$this->validChannelServer($alias)) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, - array('tag' => 'suggestedalias', 'name' => $alias)); - return false; + if ($info == false) { + if (!isset($packagelist['p'])) { + return array(); + } + if (!is_array($packagelist['p']) || + !isset($packagelist['p'][0])) { // only 1 pkg + $packagelist = array($packagelist['p']); + } else { + $packagelist = $packagelist['p']; + } + return $packagelist; } - if ($local) { - $this->_channelInfo['localalias'] = $alias; - } else { - $this->_channelInfo['suggestedalias'] = $alias; + // info == true + if (!isset($packagelist['pi'])) { + return array(); } - return true; + if (!is_array($packagelist['pi']) || + !isset($packagelist['pi'][0])) { // only 1 pkg + $packagelist_pre = array($packagelist['pi']); + } else { + $packagelist_pre = $packagelist['pi']; + } + + $packagelist = array(); + foreach ($packagelist_pre as $i => $item) { + // compatibility with r/.xml + if (isset($item['a']['r'][0])) { + // multiple releases + $item['p']['v'] = $item['a']['r'][0]['v']; + $item['p']['st'] = $item['a']['r'][0]['s']; + } elseif (isset($item['a'])) { + // first and only release + $item['p']['v'] = $item['a']['r']['v']; + $item['p']['st'] = $item['a']['r']['s']; + } + + $packagelist[$i] = array('attribs' => $item['p']['r'], + '_content' => $item['p']['n'], + 'info' => $item['p']); + } + + return $packagelist; } /** - * @return string + * Return an array containing all of the states that are more stable than + * or equal to the passed in state + * + * @param string Release state + * @param boolean Determines whether to include $state in the list + * @return false|array False if $state is not a valid release state */ - function getAlias() + function betterStates($state, $include = false) { - if (isset($this->_channelInfo['localalias'])) { - return $this->_channelInfo['localalias']; - } - if (isset($this->_channelInfo['suggestedalias'])) { - return $this->_channelInfo['suggestedalias']; + static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable'); + $i = array_search($state, $states); + if ($i === false) { + return false; } - if (isset($this->_channelInfo['name'])) { - return $this->_channelInfo['name']; + if ($include) { + $i--; } - return ''; + return array_slice($states, $i + 1); } +} +?>PEAR-1.9.0/PEAR/REST/13.php100664 764 764 26544 100664 7601 + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: 13.php 287110 2009-08-11 18:51:15Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a12 + */ - /** - * Set the package validation object if it differs from PEAR's default - * The class must be includeable via changing _ in the classname to path separator, - * but no checking of this is made. - * @param string|false pass in false to reset to the default packagename regex - * @return boolean success - */ - function setValidationPackage($validateclass, $version) - { - if (empty($validateclass)) { - unset($this->_channelInfo['validatepackage']); - } - $this->_channelInfo['validatepackage'] = array('_content' => $validateclass); - $this->_channelInfo['validatepackage']['attribs'] = array('version' => $version); - } +/** + * For downloading REST xml/txt files + */ +require_once 'PEAR/REST.php'; +require_once 'PEAR/REST/10.php'; +/** + * Implement REST 1.3 + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a12 + */ +class PEAR_REST_13 extends PEAR_REST_10 +{ /** - * Add a protocol to the provides section - * @param string protocol type - * @param string protocol version - * @param string protocol name, if any - * @param string mirror name, if this is a mirror's protocol - * @return bool + * Retrieve information about a remote package to be downloaded from a REST server + * + * This is smart enough to resolve the minimum PHP version dependency prior to download + * @param string $base The uri to prepend to all REST calls + * @param array $packageinfo an array of format: + *
+     *  array(
+     *   'package' => 'packagename',
+     *   'channel' => 'channelname',
+     *  ['state' => 'alpha' (or valid state),]
+     *  -or-
+     *  ['version' => '1.whatever']
+     * 
+ * @param string $prefstate Current preferred_state config variable value + * @param bool $installed the installed version of this package to compare against + * @return array|false|PEAR_Error see {@link _returnDownloadURL()} */ - function addFunction($type, $version, $name = '', $mirror = false) + function getDownloadURL($base, $packageinfo, $prefstate, $installed, $channel = false) { - if ($mirror) { - return $this->addMirrorFunction($mirror, $type, $version, $name); + $states = $this->betterStates($prefstate, true); + if (!$states) { + return PEAR::raiseError('"' . $prefstate . '" is not a valid state'); } - $set = array('attribs' => array('version' => $version), '_content' => $name); - if (!isset($this->_channelInfo['servers']['primary'][$type]['function'])) { - if (!isset($this->_channelInfo['servers'])) { - $this->_channelInfo['servers'] = array('primary' => - array($type => array())); - } elseif (!isset($this->_channelInfo['servers']['primary'])) { - $this->_channelInfo['servers']['primary'] = array($type => array()); - } + $channel = $packageinfo['channel']; + $package = $packageinfo['package']; + $state = isset($packageinfo['state']) ? $packageinfo['state'] : null; + $version = isset($packageinfo['version']) ? $packageinfo['version'] : null; + $restFile = $base . 'r/' . strtolower($package) . '/allreleases2.xml'; - $this->_channelInfo['servers']['primary'][$type]['function'] = $set; - $this->_isValid = false; - return true; - } elseif (!isset($this->_channelInfo['servers']['primary'][$type]['function'][0])) { - $this->_channelInfo['servers']['primary'][$type]['function'] = array( - $this->_channelInfo['servers']['primary'][$type]['function']); + $info = $this->_rest->retrieveData($restFile, false, false, $channel); + if (PEAR::isError($info)) { + return PEAR::raiseError('No releases available for package "' . + $channel . '/' . $package . '"'); } - $this->_channelInfo['servers']['primary'][$type]['function'][] = $set; - return true; - } - /** - * Add a protocol to a mirror's provides section - * @param string mirror name (server) - * @param string protocol type - * @param string protocol version - * @param string protocol name, if any - */ - function addMirrorFunction($mirror, $type, $version, $name = '') - { - if (!isset($this->_channelInfo['servers']['mirror'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, - array('mirror' => $mirror)); + if (!isset($info['r'])) { return false; } - $setmirror = false; - if (isset($this->_channelInfo['servers']['mirror'][0])) { - foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { - if ($mirror == $mir['attribs']['host']) { - $setmirror = &$this->_channelInfo['servers']['mirror'][$i]; - break; - } - } - } else { - if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { - $setmirror = &$this->_channelInfo['servers']['mirror']; - } + $release = $found = false; + if (!is_array($info['r']) || !isset($info['r'][0])) { + $info['r'] = array($info['r']); } - if (!$setmirror) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, - array('mirror' => $mirror)); - return false; - } - - $set = array('attribs' => array('version' => $version), '_content' => $name); - if (!isset($setmirror[$type]['function'])) { - $setmirror[$type]['function'] = $set; - $this->_isValid = false; - return true; - } elseif (!isset($setmirror[$type]['function'][0])) { - $setmirror[$type]['function'] = array($setmirror[$type]['function']); - } - - $setmirror[$type]['function'][] = $set; - $this->_isValid = false; - return true; - } - - /** - * @param string Resource Type this url links to - * @param string URL - * @param string|false mirror name, if this is not a primary server REST base URL - */ - function setBaseURL($resourceType, $url, $mirror = false) - { - if ($mirror) { - if (!isset($this->_channelInfo['servers']['mirror'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, - array('mirror' => $mirror)); - return false; + $skippedphp = false; + foreach ($info['r'] as $release) { + if (!isset($this->_rest->_options['force']) && ($installed && + version_compare($release['v'], $installed, '<'))) { + continue; } - $setmirror = false; - if (isset($this->_channelInfo['servers']['mirror'][0])) { - foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { - if ($mirror == $mir['attribs']['host']) { - $setmirror = &$this->_channelInfo['servers']['mirror'][$i]; - break; + if (isset($state)) { + // try our preferred state first + if ($release['s'] == $state) { + if (!isset($version) && version_compare($release['m'], phpversion(), '>')) { + // skip releases that require a PHP version newer than our PHP version + $skippedphp = $release; + continue; + } + $found = true; + break; + } + + // see if there is something newer and more stable + // bug #7221 + if (in_array($release['s'], $this->betterStates($state), true)) { + if (!isset($version) && version_compare($release['m'], phpversion(), '>')) { + // skip releases that require a PHP version newer than our PHP version + $skippedphp = $release; + continue; + } + $found = true; + break; + } + } elseif (isset($version)) { + if ($release['v'] == $version) { + if (!isset($this->_rest->_options['force']) && + !isset($version) && + version_compare($release['m'], phpversion(), '>')) { + // skip releases that require a PHP version newer than our PHP version + $skippedphp = $release; + continue; } + $found = true; + break; } } else { - if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { - $setmirror = &$this->_channelInfo['servers']['mirror']; + if (in_array($release['s'], $states)) { + if (version_compare($release['m'], phpversion(), '>')) { + // skip releases that require a PHP version newer than our PHP version + $skippedphp = $release; + continue; + } + $found = true; + break; } } - } else { - $setmirror = &$this->_channelInfo['servers']['primary']; } - $set = array('attribs' => array('type' => $resourceType), '_content' => $url); - if (!isset($setmirror['rest'])) { - $setmirror['rest'] = array(); + if (!$found && $skippedphp) { + $found = null; } - if (!isset($setmirror['rest']['baseurl'])) { - $setmirror['rest']['baseurl'] = $set; - $this->_isValid = false; - return true; - } elseif (!isset($setmirror['rest']['baseurl'][0])) { - $setmirror['rest']['baseurl'] = array($setmirror['rest']['baseurl']); - } + return $this->_returnDownloadURL($base, $package, $release, $info, $found, $skippedphp, $channel); + } - foreach ($setmirror['rest']['baseurl'] as $i => $url) { - if ($url['attribs']['type'] == $resourceType) { - $this->_isValid = false; - $setmirror['rest']['baseurl'][$i] = $set; - return true; - } + function getDepDownloadURL($base, $xsdversion, $dependency, $deppackage, + $prefstate = 'stable', $installed = false, $channel = false) + { + $states = $this->betterStates($prefstate, true); + if (!$states) { + return PEAR::raiseError('"' . $prefstate . '" is not a valid state'); } - $setmirror['rest']['baseurl'][] = $set; - $this->_isValid = false; - return true; - } + $channel = $dependency['channel']; + $package = $dependency['name']; + $state = isset($dependency['state']) ? $dependency['state'] : null; + $version = isset($dependency['version']) ? $dependency['version'] : null; + $restFile = $base . 'r/' . strtolower($package) .'/allreleases2.xml'; - /** - * @param string mirror server - * @param int mirror http port - * @return boolean - */ - function addMirror($server, $port = null) - { - if ($this->_channelInfo['name'] == '__uri') { - return false; // the __uri channel cannot have mirrors by definition + $info = $this->_rest->retrieveData($restFile, false, false, $channel); + if (PEAR::isError($info)) { + return PEAR::raiseError('Package "' . $deppackage['channel'] . '/' . $deppackage['package'] + . '" dependency "' . $channel . '/' . $package . '" has no releases'); } - $set = array('attribs' => array('host' => $server)); - if (is_numeric($port)) { - $set['attribs']['port'] = $port; + if (!is_array($info) || !isset($info['r'])) { + return false; } - if (!isset($this->_channelInfo['servers']['mirror'])) { - $this->_channelInfo['servers']['mirror'] = $set; - return true; + $exclude = array(); + $min = $max = $recommended = false; + if ($xsdversion == '1.0') { + $pinfo['package'] = $dependency['name']; + $pinfo['channel'] = 'pear.php.net'; // this is always true - don't change this + switch ($dependency['rel']) { + case 'ge' : + $min = $dependency['version']; + break; + case 'gt' : + $min = $dependency['version']; + $exclude = array($dependency['version']); + break; + case 'eq' : + $recommended = $dependency['version']; + break; + case 'lt' : + $max = $dependency['version']; + $exclude = array($dependency['version']); + break; + case 'le' : + $max = $dependency['version']; + break; + case 'ne' : + $exclude = array($dependency['version']); + break; + } + } else { + $pinfo['package'] = $dependency['name']; + $min = isset($dependency['min']) ? $dependency['min'] : false; + $max = isset($dependency['max']) ? $dependency['max'] : false; + $recommended = isset($dependency['recommended']) ? + $dependency['recommended'] : false; + if (isset($dependency['exclude'])) { + if (!isset($dependency['exclude'][0])) { + $exclude = array($dependency['exclude']); + } + } } - if (!isset($this->_channelInfo['servers']['mirror'][0])) { - $this->_channelInfo['servers']['mirror'] = - array($this->_channelInfo['servers']['mirror']); + $skippedphp = $found = $release = false; + if (!is_array($info['r']) || !isset($info['r'][0])) { + $info['r'] = array($info['r']); } - $this->_channelInfo['servers']['mirror'][] = $set; - return true; - } + foreach ($info['r'] as $release) { + if (!isset($this->_rest->_options['force']) && ($installed && + version_compare($release['v'], $installed, '<'))) { + continue; + } - /** - * Retrieve the name of the validation package for this channel - * @return string|false - */ - function getValidationPackage() - { - if (!$this->_isValid && !$this->validate()) { - return false; - } + if (in_array($release['v'], $exclude)) { // skip excluded versions + continue; + } - if (!isset($this->_channelInfo['validatepackage'])) { - return array('attribs' => array('version' => 'default'), - '_content' => 'PEAR_Validate'); - } + // allow newer releases to say "I'm OK with the dependent package" + if ($xsdversion == '2.0' && isset($release['co'])) { + if (!is_array($release['co']) || !isset($release['co'][0])) { + $release['co'] = array($release['co']); + } - return $this->_channelInfo['validatepackage']; - } + foreach ($release['co'] as $entry) { + if (isset($entry['x']) && !is_array($entry['x'])) { + $entry['x'] = array($entry['x']); + } elseif (!isset($entry['x'])) { + $entry['x'] = array(); + } - /** - * Retrieve the object that can be used for custom validation - * @param string|false the name of the package to validate. If the package is - * the channel validation package, PEAR_Validate is returned - * @return PEAR_Validate|false false is returned if the validation package - * cannot be located - */ - function &getValidationObject($package = false) - { - if (!class_exists('PEAR_Validate')) { - require_once 'PEAR/Validate.php'; - } + if ($entry['c'] == $deppackage['channel'] && + strtolower($entry['p']) == strtolower($deppackage['package']) && + version_compare($deppackage['version'], $entry['min'], '>=') && + version_compare($deppackage['version'], $entry['max'], '<=') && + !in_array($release['v'], $entry['x'])) { + if (version_compare($release['m'], phpversion(), '>')) { + // skip dependency releases that require a PHP version + // newer than our PHP version + $skippedphp = $release; + continue; + } - if (!$this->_isValid) { - if (!$this->validate()) { - $a = false; - return $a; + $recommended = $release['v']; + break; + } + } } - } - if (isset($this->_channelInfo['validatepackage'])) { - if ($package == $this->_channelInfo['validatepackage']) { - // channel validation packages are always validated by PEAR_Validate - $val = &new PEAR_Validate; - return $val; - } + if ($recommended) { + if ($release['v'] != $recommended) { // if we want a specific + // version, then skip all others + continue; + } - if (!class_exists(str_replace('.', '_', - $this->_channelInfo['validatepackage']['_content']))) { - if ($this->isIncludeable(str_replace('_', '/', - $this->_channelInfo['validatepackage']['_content']) . '.php')) { - include_once str_replace('_', '/', - $this->_channelInfo['validatepackage']['_content']) . '.php'; - $vclass = str_replace('.', '_', - $this->_channelInfo['validatepackage']['_content']); - $val = &new $vclass; - } else { - $a = false; - return $a; + if (!in_array($release['s'], $states)) { + // the stability is too low, but we must return the + // recommended version if possible + return $this->_returnDownloadURL($base, $package, $release, $info, true, false, $channel); } - } else { - $vclass = str_replace('.', '_', - $this->_channelInfo['validatepackage']['_content']); - $val = &new $vclass; } - } else { - $val = &new PEAR_Validate; - } - return $val; - } + if ($min && version_compare($release['v'], $min, 'lt')) { // skip too old versions + continue; + } - function isIncludeable($path) - { - $possibilities = explode(PATH_SEPARATOR, ini_get('include_path')); - foreach ($possibilities as $dir) { - if (file_exists($dir . DIRECTORY_SEPARATOR . $path) - && is_readable($dir . DIRECTORY_SEPARATOR . $path)) { - return true; + if ($max && version_compare($release['v'], $max, 'gt')) { // skip too new versions + continue; } - } - return false; - } + if ($installed && version_compare($release['v'], $installed, '<')) { + continue; + } - /** - * This function is used by the channel updater and retrieves a value set by - * the registry, or the current time if it has not been set - * @return string - */ - function lastModified() - { - if (isset($this->_channelInfo['_lastmodified'])) { - return $this->_channelInfo['_lastmodified']; + if (in_array($release['s'], $states)) { // if in the preferred state... + if (version_compare($release['m'], phpversion(), '>')) { + // skip dependency releases that require a PHP version + // newer than our PHP version + $skippedphp = $release; + continue; + } + + $found = true; // ... then use it + break; + } } - return time(); + if (!$found && $skippedphp) { + $found = null; + } + + return $this->_returnDownloadURL($base, $package, $release, $info, $found, $skippedphp, $channel); } -}PEAR-1.8.0/PEAR/Command.php100664 764 764 30707 100664 10152 - read/write version * * PHP versions 4 and 5 * * @category pear * @package PEAR - * @author Stig Bakken * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Command.php,v 1.41 2009/02/24 23:38:22 dufuz Exp $ + * @version CVS: $Id: rw.php 276385 2009-02-24 23:46:03Z dufuz $ * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/** - * Needed for error handling - */ -require_once 'PEAR.php'; -require_once 'PEAR/Frontend.php'; -require_once 'PEAR/XMLParser.php'; - -/** - * List of commands and what classes they are implemented in. - * @var array command => implementing class - */ -$GLOBALS['_PEAR_Command_commandlist'] = array(); - -/** - * List of commands and their descriptions - * @var array command => description - */ -$GLOBALS['_PEAR_Command_commanddesc'] = array(); - -/** - * List of shortcuts to common commands. - * @var array shortcut => command + * @since File available since Release 1.4.0a10 */ -$GLOBALS['_PEAR_Command_shortcuts'] = array(); - /** - * Array of command objects - * @var array class => object + * Base class */ -$GLOBALS['_PEAR_Command_objects'] = array(); - +require_once 'PEAR/Task/Postinstallscript.php'; /** - * PEAR command class, a simple factory class for administrative - * commands. - * - * How to implement command classes: - * - * - The class must be called PEAR_Command_Nnn, installed in the - * "PEAR/Common" subdir, with a method called getCommands() that - * returns an array of the commands implemented by the class (see - * PEAR/Command/Install.php for an example). - * - * - The class must implement a run() function that is called with three - * params: - * - * (string) command name - * (array) assoc array with options, freely defined by each - * command, for example: - * array('force' => true) - * (array) list of the other parameters - * - * The run() function returns a PEAR_CommandResponse object. Use - * these methods to get information: - * - * int getStatus() Returns PEAR_COMMAND_(SUCCESS|FAILURE|PARTIAL) - * *_PARTIAL means that you need to issue at least - * one more command to complete the operation - * (used for example for validation steps). - * - * string getMessage() Returns a message for the user. Remember, - * no HTML or other interface-specific markup. - * - * If something unexpected happens, run() returns a PEAR error. - * - * - DON'T OUTPUT ANYTHING! Return text for output instead. - * - * - DON'T USE HTML! The text you return will be used from both Gtk, - * web and command-line interfaces, so for now, keep everything to - * plain text. - * - * - DON'T USE EXIT OR DIE! Always use pear errors. From static - * classes do PEAR::raiseError(), from other classes do - * $this->raiseError(). + * Abstracts the postinstallscript file task xml. * @category pear * @package PEAR - * @author Stig Bakken * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 + * @since Class available since Release 1.4.0a10 */ -class PEAR_Command +class PEAR_Task_Postinstallscript_rw extends PEAR_Task_Postinstallscript { - // {{{ factory() - /** - * Get the right object for executing a command. - * - * @param string $command The name of the command - * @param object $config Instance of PEAR_Config object + * parent package file object * - * @return object the command object or a PEAR error + * @var PEAR_PackageFile_v2_rw + */ + var $_pkg; + /** + * Enter description here... * - * @access public - * @static + * @param PEAR_PackageFile_v2_rw $pkg + * @param PEAR_Config $config + * @param PEAR_Frontend $logger + * @param array $fileXml + * @return PEAR_Task_Postinstallscript_rw */ - function &factory($command, &$config) + function PEAR_Task_Postinstallscript_rw(&$pkg, &$config, &$logger, $fileXml) { - if (empty($GLOBALS['_PEAR_Command_commandlist'])) { - PEAR_Command::registerCommands(); - } - if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) { - $command = $GLOBALS['_PEAR_Command_shortcuts'][$command]; - } - if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) { - $a = PEAR::raiseError("unknown command `$command'"); - return $a; - } - $class = $GLOBALS['_PEAR_Command_commandlist'][$command]; - if (!class_exists($class)) { - require_once $GLOBALS['_PEAR_Command_objects'][$class]; - } - if (!class_exists($class)) { - $a = PEAR::raiseError("unknown command `$command'"); - return $a; - } - $ui =& PEAR_Command::getFrontendObject(); - $obj = &new $class($ui, $config); - return $obj; + parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE); + $this->_contents = $fileXml; + $this->_pkg = &$pkg; + $this->_params = array(); } - // }}} - // {{{ & getObject() - function &getObject($command) + function validate() { - $class = $GLOBALS['_PEAR_Command_commandlist'][$command]; - if (!class_exists($class)) { - require_once $GLOBALS['_PEAR_Command_objects'][$class]; - } - if (!class_exists($class)) { - return PEAR::raiseError("unknown command `$command'"); - } - $ui =& PEAR_Command::getFrontendObject(); - $config = &PEAR_Config::singleton(); - $obj = &new $class($ui, $config); - return $obj; + return $this->validateXml($this->_pkg, $this->_params, $this->config, $this->_contents); } - // }}} - // {{{ & getFrontendObject() - - /** - * Get instance of frontend object. - * - * @return object|PEAR_Error - * @static - */ - function &getFrontendObject() + function getName() { - $a = &PEAR_Frontend::singleton(); - return $a; + return 'postinstallscript'; } - // }}} - // {{{ & setFrontendClass() - /** - * Load current frontend class. + * add a simple to the post-install script * - * @param string $uiclass Name of class implementing the frontend + * Order is significant, so call this method in the same + * sequence the users should see the paramgroups. The $params + * parameter should either be the result of a call to {@link getParam()} + * or an array of calls to getParam(). * - * @return object the frontend object, or a PEAR error - * @static + * Use {@link addConditionTypeGroup()} to add a containing + * a tag + * @param string $id id as seen by the script + * @param array|false $params array of getParam() calls, or false for no params + * @param string|false $instructions */ - function &setFrontendClass($uiclass) + function addParamGroup($id, $params = false, $instructions = false) { - $a = &PEAR_Frontend::setFrontendClass($uiclass); - return $a; + if ($params && isset($params[0]) && !isset($params[1])) { + $params = $params[0]; + } + $stuff = + array( + $this->_pkg->getTasksNs() . ':id' => $id, + ); + if ($instructions) { + $stuff[$this->_pkg->getTasksNs() . ':instructions'] = $instructions; + } + if ($params) { + $stuff[$this->_pkg->getTasksNs() . ':param'] = $params; + } + $this->_params[$this->_pkg->getTasksNs() . ':paramgroup'][] = $stuff; } - // }}} - // {{{ setFrontendType() - /** - * Set current frontend. + * add a complex to the post-install script with conditions * - * @param string $uitype Name of the frontend type (for example "CLI") + * This inserts a with * - * @return object the frontend object, or a PEAR error - * @static + * Order is significant, so call this method in the same + * sequence the users should see the paramgroups. The $params + * parameter should either be the result of a call to {@link getParam()} + * or an array of calls to getParam(). + * + * Use {@link addParamGroup()} to add a simple + * + * @param string $id id as seen by the script + * @param string $oldgroup id of the section referenced by + * + * @param string $param name of the from the older section referenced + * by + * @param string $value value to match of the parameter + * @param string $conditiontype one of '=', '!=', 'preg_match' + * @param array|false $params array of getParam() calls, or false for no params + * @param string|false $instructions */ - function setFrontendType($uitype) - { - $uiclass = 'PEAR_Frontend_' . $uitype; - return PEAR_Command::setFrontendClass($uiclass); - } - - // }}} - // {{{ registerCommands() - - /** - * Scan through the Command directory looking for classes - * and see what commands they implement. - * - * @param bool (optional) if FALSE (default), the new list of - * commands should replace the current one. If TRUE, - * new entries will be merged with old. - * - * @param string (optional) where (what directory) to look for - * classes, defaults to the Command subdirectory of - * the directory from where this file (__FILE__) is - * included. - * - * @return bool TRUE on success, a PEAR error on failure - * - * @access public - * @static - */ - function registerCommands($merge = false, $dir = null) + function addConditionTypeGroup($id, $oldgroup, $param, $value, $conditiontype = '=', + $params = false, $instructions = false) { - $parser = new PEAR_XMLParser; - if ($dir === null) { - $dir = dirname(__FILE__) . '/Command'; - } - if (!is_dir($dir)) { - return PEAR::raiseError("registerCommands: opendir($dir) '$dir' does not exist or is not a directory"); - } - $dp = @opendir($dir); - if (empty($dp)) { - return PEAR::raiseError("registerCommands: opendir($dir) failed"); + if ($params && isset($params[0]) && !isset($params[1])) { + $params = $params[0]; } - if (!$merge) { - $GLOBALS['_PEAR_Command_commandlist'] = array(); + $stuff = array( + $this->_pkg->getTasksNs() . ':id' => $id, + ); + if ($instructions) { + $stuff[$this->_pkg->getTasksNs() . ':instructions'] = $instructions; } - while ($entry = readdir($dp)) { - if ($entry{0} == '.' || substr($entry, -4) != '.xml') { - continue; - } - $class = "PEAR_Command_".substr($entry, 0, -4); - $file = "$dir/$entry"; - $parser->parse(file_get_contents($file)); - $implements = $parser->getData(); - // List of commands - if (empty($GLOBALS['_PEAR_Command_objects'][$class])) { - $GLOBALS['_PEAR_Command_objects'][$class] = "$dir/" . substr($entry, 0, -4) . - '.php'; - } - foreach ($implements as $command => $desc) { - if ($command == 'attribs') { - continue; - } - if (isset($GLOBALS['_PEAR_Command_commandlist'][$command])) { - return PEAR::raiseError('Command "' . $command . '" already registered in ' . - 'class "' . $GLOBALS['_PEAR_Command_commandlist'][$command] . '"'); - } - $GLOBALS['_PEAR_Command_commandlist'][$command] = $class; - $GLOBALS['_PEAR_Command_commanddesc'][$command] = $desc['summary']; - if (isset($desc['shortcut'])) { - $shortcut = $desc['shortcut']; - if (isset($GLOBALS['_PEAR_Command_shortcuts'][$shortcut])) { - return PEAR::raiseError('Command shortcut "' . $shortcut . '" already ' . - 'registered to command "' . $command . '" in class "' . - $GLOBALS['_PEAR_Command_commandlist'][$command] . '"'); - } - $GLOBALS['_PEAR_Command_shortcuts'][$shortcut] = $command; - } - if (isset($desc['options']) && $desc['options']) { - foreach ($desc['options'] as $oname => $option) { - if (isset($option['shortopt']) && strlen($option['shortopt']) > 1) { - return PEAR::raiseError('Option "' . $oname . '" short option "' . - $option['shortopt'] . '" must be ' . - 'only 1 character in Command "' . $command . '" in class "' . - $class . '"'); - } - } - } - } + $stuff[$this->_pkg->getTasksNs() . ':name'] = $oldgroup . '::' . $param; + $stuff[$this->_pkg->getTasksNs() . ':conditiontype'] = $conditiontype; + $stuff[$this->_pkg->getTasksNs() . ':value'] = $value; + if ($params) { + $stuff[$this->_pkg->getTasksNs() . ':param'] = $params; } - ksort($GLOBALS['_PEAR_Command_shortcuts']); - ksort($GLOBALS['_PEAR_Command_commandlist']); - @closedir($dp); - return true; + $this->_params[$this->_pkg->getTasksNs() . ':paramgroup'][] = $stuff; } - // }}} - // {{{ getCommands() - - /** - * Get the list of currently supported commands, and what - * classes implement them. - * - * @return array command => implementing class - * - * @access public - * @static - */ - function getCommands() + function getXml() { - if (empty($GLOBALS['_PEAR_Command_commandlist'])) { - PEAR_Command::registerCommands(); - } - return $GLOBALS['_PEAR_Command_commandlist']; + return $this->_params; } - // }}} - // {{{ getShortcuts() - /** - * Get the list of command shortcuts. - * - * @return array shortcut => command - * - * @access public + * Use to set up a param tag for use in creating a paramgroup * @static */ - function getShortcuts() + function getParam($name, $prompt, $type = 'string', $default = null) { - if (empty($GLOBALS['_PEAR_Command_shortcuts'])) { - PEAR_Command::registerCommands(); + if ($default !== null) { + return + array( + $this->_pkg->getTasksNs() . ':name' => $name, + $this->_pkg->getTasksNs() . ':prompt' => $prompt, + $this->_pkg->getTasksNs() . ':type' => $type, + $this->_pkg->getTasksNs() . ':default' => $default + ); } - return $GLOBALS['_PEAR_Command_shortcuts']; + return + array( + $this->_pkg->getTasksNs() . ':name' => $name, + $this->_pkg->getTasksNs() . ':prompt' => $prompt, + $this->_pkg->getTasksNs() . ':type' => $type, + ); } - - // }}} - // {{{ getGetoptArgs() - - /** - * Compiles arguments for getopt. - * - * @param string $command command to get optstring for - * @param string $short_args (reference) short getopt format - * @param array $long_args (reference) long getopt format - * - * @return void - * - * @access public - * @static - */ - function getGetoptArgs($command, &$short_args, &$long_args) +} +?>PEAR-1.9.0/PEAR/Task/Replace/rw.php100664 764 764 3115 100664 11453 - read/write version + * + * PHP versions 4 and 5 + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: rw.php 276385 2009-02-24 23:46:03Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a10 + */ +/** + * Base class + */ +require_once 'PEAR/Task/Replace.php'; +/** + * Abstracts the replace task xml. + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a10 + */ +class PEAR_Task_Replace_rw extends PEAR_Task_Replace +{ + function PEAR_Task_Replace_rw(&$pkg, &$config, &$logger, $fileXml) { - if (empty($GLOBALS['_PEAR_Command_commandlist'])) { - PEAR_Command::registerCommands(); - } - if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) { - $command = $GLOBALS['_PEAR_Command_shortcuts'][$command]; - } - if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) { - return null; - } - $obj = &PEAR_Command::getObject($command); - return $obj->getGetoptArgs($command, $short_args, $long_args); + parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE); + $this->_contents = $fileXml; + $this->_pkg = &$pkg; + $this->_params = array(); } - // }}} - // {{{ getDescription() + function validate() + { + return $this->validateXml($this->_pkg, $this->_params, $this->config, $this->_contents); + } - /** - * Get description for a command. - * - * @param string $command Name of the command - * - * @return string command description - * - * @access public - * @static - */ - function getDescription($command) + function setInfo($from, $to, $type) { - if (!isset($GLOBALS['_PEAR_Command_commanddesc'][$command])) { - return null; - } - return $GLOBALS['_PEAR_Command_commanddesc'][$command]; + $this->_params = array('attribs' => array('from' => $from, 'to' => $to, 'type' => $type)); } - // }}} - // {{{ getHelp() + function getName() + { + return 'replace'; + } - /** - * Get help for command. - * - * @param string $command Name of the command to return help for - * - * @access public - * @static - */ - function getHelp($command) + function getXml() { - $cmds = PEAR_Command::getCommands(); - if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) { - $command = $GLOBALS['_PEAR_Command_shortcuts'][$command]; - } - if (isset($cmds[$command])) { - $obj = &PEAR_Command::getObject($command); - return $obj->getHelp($command); - } - return false; + return $this->_params; } - // }}} -}PEAR-1.8.0/PEAR/Common.php100664 764 764 63661 100664 10031 PEAR-1.9.0/PEAR/Task/Unixeol/rw.php100664 764 764 2535 100664 11530 - read/write version * * PHP versions 4 and 5 * * @category pear * @package PEAR - * @author Stig Bakken - * @author Tomas V. V. Cox * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Common.php,v 1.168 2009/03/27 19:35:47 dufuz Exp $ + * @version CVS: $Id: rw.php 276385 2009-02-24 23:46:03Z dufuz $ * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1.0 - * @deprecated File deprecated since Release 1.4.0a1 + * @since File available since Release 1.4.0a10 */ - /** - * Include error handling + * Base class */ -require_once 'PEAR.php'; - +require_once 'PEAR/Task/Unixeol.php'; /** - * PEAR_Common error when an invalid PHP file is passed to PEAR_Common::analyzeSourceCode() + * Abstracts the unixeol task xml. + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a10 */ -define('PEAR_COMMON_ERROR_INVALIDPHP', 1); -define('_PEAR_COMMON_PACKAGE_NAME_PREG', '[A-Za-z][a-zA-Z0-9_]+'); -define('PEAR_COMMON_PACKAGE_NAME_PREG', '/^' . _PEAR_COMMON_PACKAGE_NAME_PREG . '\\z/'); - -// this should allow: 1, 1.0, 1.0RC1, 1.0dev, 1.0dev123234234234, 1.0a1, 1.0b1, 1.0pl1 -define('_PEAR_COMMON_PACKAGE_VERSION_PREG', '\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?'); -define('PEAR_COMMON_PACKAGE_VERSION_PREG', '/^' . _PEAR_COMMON_PACKAGE_VERSION_PREG . '\\z/i'); - -// XXX far from perfect :-) -define('_PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '(' . _PEAR_COMMON_PACKAGE_NAME_PREG . - ')(-([.0-9a-zA-Z]+))?'); -define('PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_PACKAGE_DOWNLOAD_PREG . - '\\z/'); - -define('_PEAR_CHANNELS_NAME_PREG', '[A-Za-z][a-zA-Z0-9\.]+'); -define('PEAR_CHANNELS_NAME_PREG', '/^' . _PEAR_CHANNELS_NAME_PREG . '\\z/'); - -// this should allow any dns or IP address, plus a path - NO UNDERSCORES ALLOWED -define('_PEAR_CHANNELS_SERVER_PREG', '[a-zA-Z0-9\-]+(?:\.[a-zA-Z0-9\-]+)*(\/[a-zA-Z0-9\-]+)*'); -define('PEAR_CHANNELS_SERVER_PREG', '/^' . _PEAR_CHANNELS_SERVER_PREG . '\\z/i'); - -define('_PEAR_CHANNELS_PACKAGE_PREG', '(' ._PEAR_CHANNELS_SERVER_PREG . ')\/(' - . _PEAR_COMMON_PACKAGE_NAME_PREG . ')'); -define('PEAR_CHANNELS_PACKAGE_PREG', '/^' . _PEAR_CHANNELS_PACKAGE_PREG . '\\z/i'); - -define('_PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '(' . _PEAR_CHANNELS_NAME_PREG . ')::(' - . _PEAR_COMMON_PACKAGE_NAME_PREG . ')(-([.0-9a-zA-Z]+))?'); -define('PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_CHANNEL_DOWNLOAD_PREG . '\\z/'); +class PEAR_Task_Unixeol_rw extends PEAR_Task_Unixeol +{ + function PEAR_Task_Unixeol_rw(&$pkg, &$config, &$logger, $fileXml) + { + parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE); + $this->_contents = $fileXml; + $this->_pkg = &$pkg; + $this->_params = array(); + } -/** - * List of temporary files and directories registered by - * PEAR_Common::addTempFile(). - * @var array - */ -$GLOBALS['_PEAR_Common_tempfiles'] = array(); + function validate() + { + return true; + } -/** - * Valid maintainer roles - * @var array - */ -$GLOBALS['_PEAR_Common_maintainer_roles'] = array('lead','developer','contributor','helper'); + function getName() + { + return 'unixeol'; + } + function getXml() + { + return ''; + } +} +?>PEAR-1.9.0/PEAR/Task/Windowseol/rw.php100664 764 764 2562 100664 12237 - read/write version + * + * PHP versions 4 and 5 + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: rw.php 276385 2009-02-24 23:46:03Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a10 */ -$GLOBALS['_PEAR_Common_release_states'] = array('alpha','beta','stable','snapshot','devel'); - /** - * Valid dependency types - * @var array + * Base class */ -$GLOBALS['_PEAR_Common_dependency_types'] = array('pkg','ext','php','prog','ldlib','rtlib','os','websrv','sapi'); - +require_once 'PEAR/Task/Windowseol.php'; /** - * Valid dependency relations - * @var array + * Abstracts the windowseol task xml. + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a10 */ -$GLOBALS['_PEAR_Common_dependency_relations'] = array('has','eq','lt','le','gt','ge','not', 'ne'); +class PEAR_Task_Windowseol_rw extends PEAR_Task_Windowseol +{ + function PEAR_Task_Windowseol_rw(&$pkg, &$config, &$logger, $fileXml) + { + parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE); + $this->_contents = $fileXml; + $this->_pkg = &$pkg; + $this->_params = array(); + } -/** - * Valid file roles - * @var array - */ -$GLOBALS['_PEAR_Common_file_roles'] = array('php','ext','test','doc','data','src','script'); + function validate() + { + return true; + } -/** - * Valid replacement types - * @var array - */ -$GLOBALS['_PEAR_Common_replacement_types'] = array('php-const', 'pear-config', 'package-info'); + function getName() + { + return 'windowseol'; + } + function getXml() + { + return ''; + } +} +?>PEAR-1.9.0/PEAR/Task/Common.php100664 764 764 13736 100664 10732 + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Common.php 276394 2009-02-25 00:15:49Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 */ -$GLOBALS['_PEAR_Common_provide_types'] = array('ext', 'prog', 'class', 'function', 'feature', 'api'); - -/** - * Valid "provide" types - * @var array +/**#@+ + * Error codes for task validation routines */ -$GLOBALS['_PEAR_Common_script_phases'] = array('pre-install', 'post-install', 'pre-uninstall', 'post-uninstall', 'pre-build', 'post-build', 'pre-configure', 'post-configure', 'pre-setup', 'post-setup'); - +define('PEAR_TASK_ERROR_NOATTRIBS', 1); +define('PEAR_TASK_ERROR_MISSING_ATTRIB', 2); +define('PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE', 3); +define('PEAR_TASK_ERROR_INVALID', 4); +/**#@-*/ +define('PEAR_TASK_PACKAGE', 1); +define('PEAR_TASK_INSTALL', 2); +define('PEAR_TASK_PACKAGEANDINSTALL', 3); /** - * Class providing common functionality for PEAR administration classes. + * A task is an operation that manipulates the contents of a file. + * + * Simple tasks operate on 1 file. Multiple tasks are executed after all files have been + * processed and installed, and are designed to operate on all files containing the task. + * The Post-install script task simply takes advantage of the fact that it will be run + * after installation, replace is a simple task. + * + * Combining tasks is possible, but ordering is significant. + * + * + * + * + * + * + * This will first replace any instance of @data-dir@ in the test.php file + * with the path to the current data directory. Then, it will include the + * test.php file and run the script it contains to configure the package post-installation. * @category pear * @package PEAR - * @author Stig Bakken - * @author Tomas V. V. Cox * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 1.4.0a1 - * @deprecated This class will disappear, and its components will be spread - * into smaller classes, like the AT&T breakup, as of Release 1.4.0a1 + * @abstract */ -class PEAR_Common extends PEAR +class PEAR_Task_Common { /** - * User Interface object (PEAR_Frontend_* class). If null, - * the log() method uses print. - * @var object + * Valid types for this version are 'simple' and 'multiple' + * + * - simple tasks operate on the contents of a file and write out changes to disk + * - multiple tasks operate on the contents of many files and write out the + * changes directly to disk + * + * Child task classes must override this property. + * @access protected */ - var $ui = null; - + var $type = 'simple'; /** - * Configuration object (PEAR_Config). - * @var PEAR_Config + * Determines which install phase this task is executed under */ - var $config = null; - - /** stack of elements, gives some sort of XML context */ - var $element_stack = array(); - - /** name of currently parsed XML element */ - var $current_element; - - /** array of attributes of the currently parsed XML element */ - var $current_attributes = array(); - - /** assoc with information about a package */ - var $pkginfo = array(); - - var $current_path = null; - + var $phase = PEAR_TASK_INSTALL; /** - * Flag variable used to mark a valid package file - * @var boolean - * @access private + * @access protected */ - var $_validPackageFile; - + var $config; /** - * PEAR_Common constructor - * - * @access public + * @access protected */ - function PEAR_Common() + var $registry; + /** + * @access protected + */ + var $logger; + /** + * @access protected + */ + var $installphase; + /** + * @param PEAR_Config + * @param PEAR_Common + */ + function PEAR_Task_Common(&$config, &$logger, $phase) { - parent::PEAR(); - $this->config = &PEAR_Config::singleton(); - $this->debug = $this->config->get('verbose'); + $this->config = &$config; + $this->registry = &$config->getRegistry(); + $this->logger = &$logger; + $this->installphase = $phase; + if ($this->type == 'multiple') { + $GLOBALS['_PEAR_TASK_POSTINSTANCES'][get_class($this)][] = &$this; + } } /** - * PEAR_Common destructor - * - * @access private - */ - function _PEAR_Common() - { - // doesn't work due to bug #14744 - //$tempfiles = $this->_tempfiles; - $tempfiles =& $GLOBALS['_PEAR_Common_tempfiles']; - while ($file = array_shift($tempfiles)) { - if (@is_dir($file)) { - if (!class_exists('System')) { - require_once 'System.php'; - } - - System::rm(array('-rf', $file)); - } elseif (file_exists($file)) { - unlink($file); - } - } - } - - /** - * Register a temporary file or directory. When the destructor is - * executed, all registered temporary files and directories are - * removed. - * - * @param string $file name of file or directory - * - * @return void + * Validate the basic contents of a task tag. + * @param PEAR_PackageFile_v2 + * @param array + * @param PEAR_Config + * @param array the entire parsed tag + * @return true|array On error, return an array in format: + * array(PEAR_TASK_ERROR_???[, param1][, param2][, ...]) * - * @access public + * For PEAR_TASK_ERROR_MISSING_ATTRIB, pass the attribute name in + * For PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, pass the attribute name and an array + * of legal values in + * @static + * @abstract */ - function addTempFile($file) + function validateXml($pkg, $xml, $config, $fileXml) { - if (!class_exists('PEAR_Frontend')) { - require_once 'PEAR/Frontend.php'; - } - PEAR_Frontend::addTempFile($file); } /** - * Wrapper to System::mkDir(), creates a directory as well as - * any necessary parent directories. - * - * @param string $dir directory name - * - * @return bool TRUE on success, or a PEAR error - * - * @access public + * Initialize a task instance with the parameters + * @param array raw, parsed xml + * @param array attributes from the tag containing this task + * @param string|null last installed version of this package + * @abstract */ - function mkDirHier($dir) + function init($xml, $fileAttributes, $lastVersion) { - // Only used in Installer - move it there ? - $this->log(2, "+ create dir $dir"); - if (!class_exists('System')) { - require_once 'System.php'; - } - return System::mkDir(array('-p', $dir)); } /** - * Logging method. - * - * @param int $level log level (0 is quiet, higher is noisier) - * @param string $msg message to write to the log - * - * @return void + * Begin a task processing session. All multiple tasks will be processed after each file + * has been successfully installed, all simple tasks should perform their task here and + * return any errors using the custom throwError() method to allow forward compatibility * - * @access public - * @static + * This method MUST NOT write out any changes to disk + * @param PEAR_PackageFile_v2 + * @param string file contents + * @param string the eventual final file location (informational only) + * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail + * (use $this->throwError), otherwise return the new contents + * @abstract */ - function log($level, $msg, $append_crlf = true) + function startSession($pkg, $contents, $dest) { - if ($this->debug >= $level) { - if (!class_exists('PEAR_Frontend')) { - require_once 'PEAR/Frontend.php'; - } - - $ui = &PEAR_Frontend::singleton(); - if (is_a($ui, 'PEAR_Frontend')) { - $ui->log($msg, $append_crlf); - } else { - print "$msg\n"; - } - } } /** - * Create and register a temporary directory. - * - * @param string $tmpdir (optional) Directory to use as tmpdir. - * Will use system defaults (for example - * /tmp or c:\windows\temp) if not specified - * - * @return string name of created directory - * - * @access public + * This method is used to process each of the tasks for a particular multiple class + * type. Simple tasks need not implement this method. + * @param array an array of tasks + * @access protected + * @static + * @abstract */ - function mkTempDir($tmpdir = '') + function run($tasks) { - $topt = $tmpdir ? array('-t', $tmpdir) : array(); - $topt = array_merge($topt, array('-d', 'pear')); - if (!class_exists('System')) { - require_once 'System.php'; - } - - if (!$tmpdir = System::mktemp($topt)) { - return false; - } - - $this->addTempFile($tmpdir); - return $tmpdir; } /** - * Set object that represents the frontend to be used. - * - * @param object Reference of the frontend object - * @return void - * @access public + * @static + * @final */ - function setFrontendObject(&$ui) + function hasPostinstallTasks() { - $this->ui = &$ui; + return isset($GLOBALS['_PEAR_TASK_POSTINSTANCES']); } /** - * Return an array containing all of the states that are more stable than - * or equal to the passed in state - * - * @param string Release state - * @param boolean Determines whether to include $state in the list - * @return false|array False if $state is not a valid release state + * @static + * @final */ - function betterStates($state, $include = false) - { - static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable'); - $i = array_search($state, $states); - if ($i === false) { - return false; - } - if ($include) { - $i--; - } - return array_slice($states, $i + 1); + function runPostinstallTasks() + { + foreach ($GLOBALS['_PEAR_TASK_POSTINSTANCES'] as $class => $tasks) { + $err = call_user_func(array($class, 'run'), + $GLOBALS['_PEAR_TASK_POSTINSTANCES'][$class]); + if ($err) { + return PEAR_Task_Common::throwError($err); + } + } + unset($GLOBALS['_PEAR_TASK_POSTINSTANCES']); } /** - * Get the valid roles for a PEAR package maintainer - * - * @return array - * @static + * Determines whether a role is a script + * @return bool */ - function getUserRoles() + function isScript() { - return $GLOBALS['_PEAR_Common_maintainer_roles']; + return $this->type == 'script'; } - /** - * Get the valid package release states of packages - * - * @return array - * @static - */ - function getReleaseStates() + function throwError($msg, $code = -1) { - return $GLOBALS['_PEAR_Common_release_states']; + include_once 'PEAR.php'; + return PEAR::raiseError($msg, $code); } - +} +?>PEAR-1.9.0/PEAR/Task/Postinstallscript.php100664 764 764 34122 100664 13233 + * + * PHP versions 4 and 5 + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Postinstallscript.php 276385 2009-02-24 23:46:03Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/** + * Base class + */ +require_once 'PEAR/Task/Common.php'; +/** + * Implements the postinstallscript file task. + * + * Note that post-install scripts are handled separately from installation, by the + * "pear run-scripts" command + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Task_Postinstallscript extends PEAR_Task_Common +{ + var $type = 'script'; + var $_class; + var $_params; + var $_obj; /** - * Get the implemented dependency types (php, ext, pkg etc.) * - * @return array - * @static + * @var PEAR_PackageFile_v2 */ - function getDependencyTypes() - { - return $GLOBALS['_PEAR_Common_dependency_types']; - } + var $_pkg; + var $_contents; + var $phase = PEAR_TASK_INSTALL; /** - * Get the implemented dependency relations (has, lt, ge etc.) + * Validate the raw xml at parsing-time. * - * @return array + * This also attempts to validate the script to make sure it meets the criteria + * for a post-install script + * @param PEAR_PackageFile_v2 + * @param array The XML contents of the tag + * @param PEAR_Config + * @param array the entire parsed tag * @static */ - function getDependencyRelations() + function validateXml($pkg, $xml, $config, $fileXml) { - return $GLOBALS['_PEAR_Common_dependency_relations']; + if ($fileXml['role'] != 'php') { + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" must be role="php"'); + } + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $file = $pkg->getFileContents($fileXml['name']); + if (PEAR::isError($file)) { + PEAR::popErrorHandling(); + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" is not valid: ' . + $file->getMessage()); + } elseif ($file === null) { + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" could not be retrieved for processing!'); + } else { + $analysis = $pkg->analyzeSourceCode($file, true); + if (!$analysis) { + PEAR::popErrorHandling(); + $warnings = ''; + foreach ($pkg->getValidationWarnings() as $warn) { + $warnings .= $warn['message'] . "\n"; + } + return array(PEAR_TASK_ERROR_INVALID, 'Analysis of post-install script "' . + $fileXml['name'] . '" failed: ' . $warnings); + } + if (count($analysis['declared_classes']) != 1) { + PEAR::popErrorHandling(); + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" must declare exactly 1 class'); + } + $class = $analysis['declared_classes'][0]; + if ($class != str_replace(array('/', '.php'), array('_', ''), + $fileXml['name']) . '_postinstall') { + PEAR::popErrorHandling(); + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" class "' . $class . '" must be named "' . + str_replace(array('/', '.php'), array('_', ''), + $fileXml['name']) . '_postinstall"'); + } + if (!isset($analysis['declared_methods'][$class])) { + PEAR::popErrorHandling(); + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" must declare methods init() and run()'); + } + $methods = array('init' => 0, 'run' => 1); + foreach ($analysis['declared_methods'][$class] as $method) { + if (isset($methods[$method])) { + unset($methods[$method]); + } + } + if (count($methods)) { + PEAR::popErrorHandling(); + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" must declare methods init() and run()'); + } + } + PEAR::popErrorHandling(); + $definedparams = array(); + $tasksNamespace = $pkg->getTasksNs() . ':'; + if (!isset($xml[$tasksNamespace . 'paramgroup']) && isset($xml['paramgroup'])) { + // in order to support the older betas, which did not expect internal tags + // to also use the namespace + $tasksNamespace = ''; + } + if (isset($xml[$tasksNamespace . 'paramgroup'])) { + $params = $xml[$tasksNamespace . 'paramgroup']; + if (!is_array($params) || !isset($params[0])) { + $params = array($params); + } + foreach ($params as $param) { + if (!isset($param[$tasksNamespace . 'id'])) { + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" must have ' . + 'an ' . $tasksNamespace . 'id> tag'); + } + if (isset($param[$tasksNamespace . 'name'])) { + if (!in_array($param[$tasksNamespace . 'name'], $definedparams)) { + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" ' . $tasksNamespace . + 'paramgroup> id "' . $param[$tasksNamespace . 'id'] . + '" parameter "' . $param[$tasksNamespace . 'name'] . + '" has not been previously defined'); + } + if (!isset($param[$tasksNamespace . 'conditiontype'])) { + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" ' . $tasksNamespace . + 'paramgroup> id "' . $param[$tasksNamespace . 'id'] . + '" must have a ' . $tasksNamespace . + 'conditiontype> tag containing either "=", ' . + '"!=", or "preg_match"'); + } + if (!in_array($param[$tasksNamespace . 'conditiontype'], + array('=', '!=', 'preg_match'))) { + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" ' . $tasksNamespace . + 'paramgroup> id "' . $param[$tasksNamespace . 'id'] . + '" must have a ' . $tasksNamespace . + 'conditiontype> tag containing either "=", ' . + '"!=", or "preg_match"'); + } + if (!isset($param[$tasksNamespace . 'value'])) { + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" ' . $tasksNamespace . + 'paramgroup> id "' . $param[$tasksNamespace . 'id'] . + '" must have a ' . $tasksNamespace . + 'value> tag containing expected parameter value'); + } + } + if (isset($param[$tasksNamespace . 'instructions'])) { + if (!is_string($param[$tasksNamespace . 'instructions'])) { + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" ' . $tasksNamespace . + 'paramgroup> id "' . $param[$tasksNamespace . 'id'] . + '" ' . $tasksNamespace . 'instructions> must be simple text'); + } + } + if (!isset($param[$tasksNamespace . 'param'])) { + continue; // is no longer required + } + $subparams = $param[$tasksNamespace . 'param']; + if (!is_array($subparams) || !isset($subparams[0])) { + $subparams = array($subparams); + } + foreach ($subparams as $subparam) { + if (!isset($subparam[$tasksNamespace . 'name'])) { + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" parameter for ' . + $tasksNamespace . 'paramgroup> id "' . + $param[$tasksNamespace . 'id'] . '" must have ' . + 'a ' . $tasksNamespace . 'name> tag'); + } + if (!preg_match('/[a-zA-Z0-9]+/', + $subparam[$tasksNamespace . 'name'])) { + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" parameter "' . + $subparam[$tasksNamespace . 'name'] . + '" for ' . $tasksNamespace . 'paramgroup> id "' . + $param[$tasksNamespace . 'id'] . + '" is not a valid name. Must contain only alphanumeric characters'); + } + if (!isset($subparam[$tasksNamespace . 'prompt'])) { + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" parameter "' . + $subparam[$tasksNamespace . 'name'] . + '" for ' . $tasksNamespace . 'paramgroup> id "' . + $param[$tasksNamespace . 'id'] . + '" must have a ' . $tasksNamespace . 'prompt> tag'); + } + if (!isset($subparam[$tasksNamespace . 'type'])) { + return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "' . + $fileXml['name'] . '" parameter "' . + $subparam[$tasksNamespace . 'name'] . + '" for ' . $tasksNamespace . 'paramgroup> id "' . + $param[$tasksNamespace . 'id'] . + '" must have a ' . $tasksNamespace . 'type> tag'); + } + $definedparams[] = $param[$tasksNamespace . 'id'] . '::' . + $subparam[$tasksNamespace . 'name']; + } + } + } + return true; } /** - * Get the implemented file roles - * - * @return array - * @static + * Initialize a task instance with the parameters + * @param array raw, parsed xml + * @param array attributes from the tag containing this task + * @param string|null last installed version of this package, if any (useful for upgrades) */ - function getFileRoles() + function init($xml, $fileattribs, $lastversion) { - return $GLOBALS['_PEAR_Common_file_roles']; + $this->_class = str_replace('/', '_', $fileattribs['name']); + $this->_filename = $fileattribs['name']; + $this->_class = str_replace ('.php', '', $this->_class) . '_postinstall'; + $this->_params = $xml; + $this->_lastversion = $lastversion; } /** - * Get the implemented file replacement types in + * Strip the tasks: namespace from internal params * - * @return array - * @static + * @access private */ - function getReplacementTypes() + function _stripNamespace($params = null) { - return $GLOBALS['_PEAR_Common_replacement_types']; + if ($params === null) { + $params = array(); + if (!is_array($this->_params)) { + return; + } + foreach ($this->_params as $i => $param) { + if (is_array($param)) { + $param = $this->_stripNamespace($param); + } + $params[str_replace($this->_pkg->getTasksNs() . ':', '', $i)] = $param; + } + $this->_params = $params; + } else { + $newparams = array(); + foreach ($params as $i => $param) { + if (is_array($param)) { + $param = $this->_stripNamespace($param); + } + $newparams[str_replace($this->_pkg->getTasksNs() . ':', '', $i)] = $param; + } + return $newparams; + } } /** - * Get the implemented file replacement types in - * - * @return array - * @static + * Unlike other tasks, the installed file name is passed in instead of the file contents, + * because this task is handled post-installation + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @param string file name + * @return bool|PEAR_Error false to skip this file, PEAR_Error to fail + * (use $this->throwError) */ - function getProvideTypes() + function startSession($pkg, $contents) { - return $GLOBALS['_PEAR_Common_provide_types']; + if ($this->installphase != PEAR_TASK_INSTALL) { + return false; + } + // remove the tasks: namespace if present + $this->_pkg = $pkg; + $this->_stripNamespace(); + $this->logger->log(0, 'Including external post-installation script "' . + $contents . '" - any errors are in this script'); + include_once $contents; + if (class_exists($this->_class)) { + $this->logger->log(0, 'Inclusion succeeded'); + } else { + return $this->throwError('init of post-install script class "' . $this->_class + . '" failed'); + } + $this->_obj = new $this->_class; + $this->logger->log(1, 'running post-install script "' . $this->_class . '->init()"'); + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $res = $this->_obj->init($this->config, $pkg, $this->_lastversion); + PEAR::popErrorHandling(); + if ($res) { + $this->logger->log(0, 'init succeeded'); + } else { + return $this->throwError('init of post-install script "' . $this->_class . + '->init()" failed'); + } + $this->_contents = $contents; + return true; } /** - * Get the implemented file replacement types in - * - * @return array + * No longer used + * @see PEAR_PackageFile_v2::runPostinstallScripts() + * @param array an array of tasks + * @param string install or upgrade + * @access protected * @static */ - function getScriptPhases() + function run() { - return $GLOBALS['_PEAR_Common_script_phases']; } - +} +?>PEAR-1.9.0/PEAR/Task/Replace.php100664 764 764 15232 100664 11046 + * + * PHP versions 4 and 5 + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Replace.php 276394 2009-02-25 00:15:49Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/** + * Base class + */ +require_once 'PEAR/Task/Common.php'; +/** + * Implements the replace file task. + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Task_Replace extends PEAR_Task_Common +{ + var $type = 'simple'; + var $phase = PEAR_TASK_PACKAGEANDINSTALL; + var $_replacements; + /** - * Test whether a string contains a valid package name. - * - * @param string $name the package name to test - * - * @return bool - * - * @access public + * Validate the raw xml at parsing-time. + * @param PEAR_PackageFile_v2 + * @param array raw, parsed xml + * @param PEAR_Config + * @static */ - function validPackageName($name) + function validateXml($pkg, $xml, $config, $fileXml) { - return (bool)preg_match(PEAR_COMMON_PACKAGE_NAME_PREG, $name); + if (!isset($xml['attribs'])) { + return array(PEAR_TASK_ERROR_NOATTRIBS); + } + if (!isset($xml['attribs']['type'])) { + return array(PEAR_TASK_ERROR_MISSING_ATTRIB, 'type'); + } + if (!isset($xml['attribs']['to'])) { + return array(PEAR_TASK_ERROR_MISSING_ATTRIB, 'to'); + } + if (!isset($xml['attribs']['from'])) { + return array(PEAR_TASK_ERROR_MISSING_ATTRIB, 'from'); + } + if ($xml['attribs']['type'] == 'pear-config') { + if (!in_array($xml['attribs']['to'], $config->getKeys())) { + return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'to', $xml['attribs']['to'], + $config->getKeys()); + } + } elseif ($xml['attribs']['type'] == 'php-const') { + if (defined($xml['attribs']['to'])) { + return true; + } else { + return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'to', $xml['attribs']['to'], + array('valid PHP constant')); + } + } elseif ($xml['attribs']['type'] == 'package-info') { + if (in_array($xml['attribs']['to'], + array('name', 'summary', 'channel', 'notes', 'extends', 'description', + 'release_notes', 'license', 'release-license', 'license-uri', + 'version', 'api-version', 'state', 'api-state', 'release_date', + 'date', 'time'))) { + return true; + } else { + return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'to', $xml['attribs']['to'], + array('name', 'summary', 'channel', 'notes', 'extends', 'description', + 'release_notes', 'license', 'release-license', 'license-uri', + 'version', 'api-version', 'state', 'api-state', 'release_date', + 'date', 'time')); + } + } else { + return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'type', $xml['attribs']['type'], + array('pear-config', 'package-info', 'php-const')); + } + return true; } /** - * Test whether a string contains a valid package version. - * - * @param string $ver the package version to test + * Initialize a task instance with the parameters + * @param array raw, parsed xml + * @param unused + */ + function init($xml, $attribs) + { + $this->_replacements = isset($xml['attribs']) ? array($xml) : $xml; + } + + /** + * Do a package.xml 1.0 replacement, with additional package-info fields available * - * @return bool + * See validateXml() source for the complete list of allowed fields + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @param string file contents + * @param string the eventual final file location (informational only) + * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail + * (use $this->throwError), otherwise return the new contents + */ + function startSession($pkg, $contents, $dest) + { + $subst_from = $subst_to = array(); + foreach ($this->_replacements as $a) { + $a = $a['attribs']; + $to = ''; + if ($a['type'] == 'pear-config') { + if ($this->installphase == PEAR_TASK_PACKAGE) { + return false; + } + if ($a['to'] == 'master_server') { + $chan = $this->registry->getChannel($pkg->getChannel()); + if (!PEAR::isError($chan)) { + $to = $chan->getServer(); + } else { + $this->logger->log(0, "$dest: invalid pear-config replacement: $a[to]"); + return false; + } + } else { + if ($this->config->isDefinedLayer('ftp')) { + // try the remote config file first + $to = $this->config->get($a['to'], 'ftp', $pkg->getChannel()); + if (is_null($to)) { + // then default to local + $to = $this->config->get($a['to'], null, $pkg->getChannel()); + } + } else { + $to = $this->config->get($a['to'], null, $pkg->getChannel()); + } + } + if (is_null($to)) { + $this->logger->log(0, "$dest: invalid pear-config replacement: $a[to]"); + return false; + } + } elseif ($a['type'] == 'php-const') { + if ($this->installphase == PEAR_TASK_PACKAGE) { + return false; + } + if (defined($a['to'])) { + $to = constant($a['to']); + } else { + $this->logger->log(0, "$dest: invalid php-const replacement: $a[to]"); + return false; + } + } else { + if ($t = $pkg->packageInfo($a['to'])) { + $to = $t; + } else { + $this->logger->log(0, "$dest: invalid package-info replacement: $a[to]"); + return false; + } + } + if (!is_null($to)) { + $subst_from[] = $a['from']; + $subst_to[] = $to; + } + } + $this->logger->log(3, "doing " . sizeof($subst_from) . + " substitution(s) for $dest"); + if (sizeof($subst_from)) { + $contents = str_replace($subst_from, $subst_to, $contents); + } + return $contents; + } +} +?>PEAR-1.9.0/PEAR/Task/Unixeol.php100664 764 764 4341 100664 11075 + * + * PHP versions 4 and 5 + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Unixeol.php 276394 2009-02-25 00:15:49Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/** + * Base class + */ +require_once 'PEAR/Task/Common.php'; +/** + * Implements the unix line endings file task. + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Task_Unixeol extends PEAR_Task_Common +{ + var $type = 'simple'; + var $phase = PEAR_TASK_PACKAGE; + var $_replacements; + + /** + * Validate the raw xml at parsing-time. + * @param PEAR_PackageFile_v2 + * @param array raw, parsed xml + * @param PEAR_Config + * @static + */ + function validateXml($pkg, $xml, $config, $fileXml) + { + if ($xml != '') { + return array(PEAR_TASK_ERROR_INVALID, 'no attributes allowed'); + } + return true; + } + + /** + * Initialize a task instance with the parameters + * @param array raw, parsed xml + * @param unused + */ + function init($xml, $attribs) + { + } + + /** + * Replace all line endings with line endings customized for the current OS * - * @access public + * See validateXml() source for the complete list of allowed fields + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @param string file contents + * @param string the eventual final file location (informational only) + * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail + * (use $this->throwError), otherwise return the new contents */ - function validPackageVersion($ver) + function startSession($pkg, $contents, $dest) { - return (bool)preg_match(PEAR_COMMON_PACKAGE_VERSION_PREG, $ver); + $this->logger->log(3, "replacing all line endings with \\n in $dest"); + return preg_replace("/\r\n|\n\r|\r|\n/", "\n", $contents); } +} +?>PEAR-1.9.0/PEAR/Task/Windowseol.php100664 764 764 4335 100664 11607 + * + * PHP versions 4 and 5 + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Windowseol.php 276394 2009-02-25 00:15:49Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/** + * Base class + */ +require_once 'PEAR/Task/Common.php'; +/** + * Implements the windows line endsings file task. + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Task_Windowseol extends PEAR_Task_Common +{ + var $type = 'simple'; + var $phase = PEAR_TASK_PACKAGE; + var $_replacements; /** - * @param string $path relative or absolute include path - * @return boolean + * Validate the raw xml at parsing-time. + * @param PEAR_PackageFile_v2 + * @param array raw, parsed xml + * @param PEAR_Config * @static */ - function isIncludeable($path) + function validateXml($pkg, $xml, $config, $fileXml) { - if (file_exists($path) && is_readable($path)) { - return true; + if ($xml != '') { + return array(PEAR_TASK_ERROR_INVALID, 'no attributes allowed'); } + return true; + } - $ipath = explode(PATH_SEPARATOR, ini_get('include_path')); - foreach ($ipath as $include) { - $test = realpath($include . DIRECTORY_SEPARATOR . $path); - if (file_exists($test) && is_readable($test)) { - return true; + /** + * Initialize a task instance with the parameters + * @param array raw, parsed xml + * @param unused + */ + function init($xml, $attribs) + { + } + + /** + * Replace all line endings with windows line endings + * + * See validateXml() source for the complete list of allowed fields + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @param string file contents + * @param string the eventual final file location (informational only) + * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail + * (use $this->throwError), otherwise return the new contents + */ + function startSession($pkg, $contents, $dest) + { + $this->logger->log(3, "replacing all line endings with \\r\\n in $dest"); + return preg_replace("/\r\n|\n\r|\r|\n/", "\r\n", $contents); + } +} +?>PEAR-1.9.0/PEAR/Validator/PECL.php100664 764 764 4175 100664 11225 + * @copyright 1997-2006 The PHP Group + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: PECL.php 276383 2009-02-24 23:39:37Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a5 + */ +/** + * This is the parent class for all validators + */ +require_once 'PEAR/Validate.php'; +/** + * Channel Validator for the pecl.php.net channel + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a5 + */ +class PEAR_Validator_PECL extends PEAR_Validate +{ + function validateVersion() + { + if ($this->_state == PEAR_VALIDATE_PACKAGING) { + $version = $this->_packagexml->getVersion(); + $versioncomponents = explode('.', $version); + $last = array_pop($versioncomponents); + if (substr($last, 1, 2) == 'rc') { + $this->_addFailure('version', 'Release Candidate versions must have ' . + 'upper-case RC, not lower-case rc'); + return false; } } + return true; + } - return false; + function validatePackageName() + { + $ret = parent::validatePackageName(); + if ($this->_packagexml->getPackageType() == 'extsrc' || + $this->_packagexml->getPackageType() == 'zendextsrc') { + if (strtolower($this->_packagexml->getPackage()) != + strtolower($this->_packagexml->getProvidesExtension())) { + $this->_addWarning('providesextension', 'package name "' . + $this->_packagexml->getPackage() . '" is different from extension name "' . + $this->_packagexml->getProvidesExtension() . '"'); + } + } + return $ret; } +} +?>PEAR-1.9.0/PEAR/Autoloader.php100664 764 764 14645 100664 10677 + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Autoloader.php 276383 2009-02-24 23:39:37Z dufuz $ + * @link http://pear.php.net/manual/en/core.ppm.php#core.ppm.pear-autoloader + * @since File available since Release 0.1 + * @deprecated File deprecated in Release 1.4.0a1 + */ + +// /* vim: set expandtab tabstop=4 shiftwidth=4: */ + +if (!extension_loaded("overload")) { + // die hard without ext/overload + die("Rebuild PHP with the `overload' extension to use PEAR_Autoloader"); +} + +/** + * Include for PEAR_Error and PEAR classes + */ +require_once "PEAR.php"; + +/** + * This class is for objects where you want to separate the code for + * some methods into separate classes. This is useful if you have a + * class with not-frequently-used methods that contain lots of code + * that you would like to avoid always parsing. + * + * The PEAR_Autoloader class provides autoloading and aggregation. + * The autoloading lets you set up in which classes the separated + * methods are found. Aggregation is the technique used to import new + * methods, an instance of each class providing separated methods is + * stored and called every time the aggregated method is called. + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/manual/en/core.ppm.php#core.ppm.pear-autoloader + * @since File available since Release 0.1 + * @deprecated File deprecated in Release 1.4.0a1 + */ +class PEAR_Autoloader extends PEAR +{ + // {{{ properties /** - * Returns information about a package file. Expects the name of - * a gzipped tar file as input. + * Map of methods and classes where they are defined * - * @param string $file name of .tgz file + * @var array * - * @return array array with package information + * @access private + */ + var $_autoload_map = array(); + + /** + * Map of methods and aggregate objects * - * @access public - * @deprecated use PEAR_PackageFile->fromTgzFile() instead + * @var array * + * @access private */ - function infoFromTgzFile($file) - { - $packagefile = &new PEAR_PackageFile($this->config); - $pf = &$packagefile->fromTgzFile($file, PEAR_VALIDATE_NORMAL); - if (PEAR::isError($pf)) { - $errs = $pf->getUserinfo(); - if (is_array($errs)) { - foreach ($errs as $error) { - $e = $this->raiseError($error['message'], $error['code'], null, null, $error); - } - } + var $_method_map = array(); - return $pf; - } - - return $this->_postProcessValidPackagexml($pf); - } + // }}} + // {{{ addAutoload() /** - * Returns information about a package file. Expects the name of - * a package xml file as input. + * Add one or more autoload entries. * - * @param string $descfile name of package xml file + * @param string $method which method to autoload * - * @return array array with package information + * @param string $classname (optional) which class to find the method in. + * If the $method parameter is an array, this + * parameter may be omitted (and will be ignored + * if not), and the $method parameter will be + * treated as an associative array with method + * names as keys and class names as values. * - * @access public - * @deprecated use PEAR_PackageFile->fromPackageFile() instead + * @return void * + * @access public */ - function infoFromDescriptionFile($descfile) + function addAutoload($method, $classname = null) { - $packagefile = &new PEAR_PackageFile($this->config); - $pf = &$packagefile->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL); - if (PEAR::isError($pf)) { - $errs = $pf->getUserinfo(); - if (is_array($errs)) { - foreach ($errs as $error) { - $e = $this->raiseError($error['message'], $error['code'], null, null, $error); - } - } - - return $pf; + if (is_array($method)) { + array_walk($method, create_function('$a,&$b', '$b = strtolower($b);')); + $this->_autoload_map = array_merge($this->_autoload_map, $method); + } else { + $this->_autoload_map[strtolower($method)] = $classname; } - - return $this->_postProcessValidPackagexml($pf); } + // }}} + // {{{ removeAutoload() + /** - * Returns information about a package file. Expects the contents - * of a package xml file as input. + * Remove an autoload entry. * - * @param string $data contents of package.xml file + * @param string $method which method to remove the autoload entry for * - * @return array array with package information + * @return bool TRUE if an entry was removed, FALSE if not * * @access public - * @deprecated use PEAR_PackageFile->fromXmlstring() instead - * */ - function infoFromString($data) + function removeAutoload($method) { - $packagefile = &new PEAR_PackageFile($this->config); - $pf = &$packagefile->fromXmlString($data, PEAR_VALIDATE_NORMAL, false); - if (PEAR::isError($pf)) { - $errs = $pf->getUserinfo(); - if (is_array($errs)) { - foreach ($errs as $error) { - $e = $this->raiseError($error['message'], $error['code'], null, null, $error); - } - } - - return $pf; - } - - return $this->_postProcessValidPackagexml($pf); + $method = strtolower($method); + $ok = isset($this->_autoload_map[$method]); + unset($this->_autoload_map[$method]); + return $ok; } + // }}} + // {{{ addAggregateObject() + /** - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @return array + * Add an aggregate object to this object. If the specified class + * is not defined, loading it will be attempted following PEAR's + * file naming scheme. All the methods in the class will be + * aggregated, except private ones (name starting with an + * underscore) and constructors. + * + * @param string $classname what class to instantiate for the object. + * + * @return void + * + * @access public */ - function _postProcessValidPackagexml(&$pf) + function addAggregateObject($classname) { - if (!is_a($pf, 'PEAR_PackageFile_v2')) { - $this->pkginfo = $pf->toArray(); - return $this->pkginfo; + $classname = strtolower($classname); + if (!class_exists($classname)) { + $include_file = preg_replace('/[^a-z0-9]/i', '_', $classname); + include_once $include_file; + } + $obj =& new $classname; + $methods = get_class_methods($classname); + foreach ($methods as $method) { + // don't import priviate methods and constructors + if ($method{0} != '_' && $method != $classname) { + $this->_method_map[$method] = $obj; + } } - - // sort of make this into a package.xml 1.0-style array - // changelog is not converted to old format. - $arr = $pf->toArray(true); - $arr = array_merge($arr, $arr['old']); - unset($arr['old']); - unset($arr['xsdversion']); - unset($arr['contents']); - unset($arr['compatible']); - unset($arr['channel']); - unset($arr['uri']); - unset($arr['dependencies']); - unset($arr['phprelease']); - unset($arr['extsrcrelease']); - unset($arr['zendextsrcrelease']); - unset($arr['extbinrelease']); - unset($arr['zendextbinrelease']); - unset($arr['bundle']); - unset($arr['lead']); - unset($arr['developer']); - unset($arr['helper']); - unset($arr['contributor']); - $arr['filelist'] = $pf->getFilelist(); - $this->pkginfo = $arr; - return $arr; } + // }}} + // {{{ removeAggregateObject() + /** - * Returns package information from different sources + * Remove an aggregate object. * - * This method is able to extract information about a package - * from a .tgz archive or from a XML package definition file. + * @param string $classname the class of the object to remove + * + * @return bool TRUE if an object was removed, FALSE if not * * @access public - * @param string Filename of the source ('package.xml', '.tgz') - * @return string - * @deprecated use PEAR_PackageFile->fromAnyFile() instead */ - function infoFromAny($info) + function removeAggregateObject($classname) { - if (is_string($info) && file_exists($info)) { - $packagefile = &new PEAR_PackageFile($this->config); - $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL); - if (PEAR::isError($pf)) { - $errs = $pf->getUserinfo(); - if (is_array($errs)) { - foreach ($errs as $error) { - $e = $this->raiseError($error['message'], $error['code'], null, null, $error); - } - } - - return $pf; + $ok = false; + $classname = strtolower($classname); + reset($this->_method_map); + while (list($method, $obj) = each($this->_method_map)) { + if (is_a($obj, $classname)) { + unset($this->_method_map[$method]); + $ok = true; } - - return $this->_postProcessValidPackagexml($pf); } - - return $info; + return $ok; } + // }}} + // {{{ __call() + /** - * Return an XML document based on the package info (as returned - * by the PEAR_Common::infoFrom* methods). + * Overloaded object call handler, called each time an + * undefined/aggregated method is invoked. This method repeats + * the call in the right aggregate object and passes on the return + * value. * - * @param array $pkginfo package info + * @param string $method which method that was called * - * @return string XML data + * @param string $args An array of the parameters passed in the + * original call * - * @access public - * @deprecated use a PEAR_PackageFile_v* object's generator instead + * @return mixed The return value from the aggregated method, or a PEAR + * error if the called method was unknown. */ - function xmlFromInfo($pkginfo) + function __call($method, $args, &$retval) { - $config = &PEAR_Config::singleton(); - $packagefile = &new PEAR_PackageFile($config); - $pf = &$packagefile->fromArray($pkginfo); - $gen = &$pf->getDefaultGenerator(); - return $gen->toXml(PEAR_VALIDATE_PACKAGING); + $method = strtolower($method); + if (empty($this->_method_map[$method]) && isset($this->_autoload_map[$method])) { + $this->addAggregateObject($this->_autoload_map[$method]); + } + if (isset($this->_method_map[$method])) { + $retval = call_user_func_array(array($this->_method_map[$method], $method), $args); + return true; + } + return false; } + // }}} +} + +overload("PEAR_Autoloader"); + +?> +PEAR-1.9.0/PEAR/Builder.php100664 764 764 40120 100664 10151 + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Builder.php 276383 2009-02-24 23:39:37Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + * + * TODO: log output parameters in PECL command line + * TODO: msdev path in configuration + */ + +/** + * Needed for extending PEAR_Builder + */ +require_once 'PEAR/Common.php'; +require_once 'PEAR/PackageFile.php'; + +/** + * Class to handle building (compiling) extensions. + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since PHP 4.0.2 + * @see http://pear.php.net/manual/en/core.ppm.pear-builder.php + */ +class PEAR_Builder extends PEAR_Common +{ + var $php_api_version = 0; + var $zend_module_api_no = 0; + var $zend_extension_api_no = 0; + + var $extensions_built = array(); + /** - * Validate XML package definition file. + * @var string Used for reporting when it is not possible to pass function + * via extra parameter, e.g. log, msdevCallback + */ + var $current_callback = null; + + // used for msdev builds + var $_lastline = null; + var $_firstline = null; + + /** + * PEAR_Builder constructor. + * + * @param object $ui user interface object (instance of PEAR_Frontend_*) * - * @param string $info Filename of the package archive or of the - * package definition file - * @param array $errors Array that will contain the errors - * @param array $warnings Array that will contain the warnings - * @param string $dir_prefix (optional) directory where source files - * may be found, or empty if they are not available * @access public - * @return boolean - * @deprecated use the validation of PEAR_PackageFile objects */ - function validatePackageInfo($info, &$errors, &$warnings, $dir_prefix = '') + function PEAR_Builder(&$ui) { - $config = &PEAR_Config::singleton(); - $packagefile = &new PEAR_PackageFile($config); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - if (strpos($info, 'fromXmlString($info, PEAR_VALIDATE_NORMAL, ''); + parent::PEAR_Common(); + $this->setFrontendObject($ui); + } + + /** + * Build an extension from source on windows. + * requires msdev + */ + function _build_win32($descfile, $callback = null) + { + if (is_object($descfile)) { + $pkg = $descfile; + $descfile = $pkg->getPackageFile(); } else { - $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL); + $pf = &new PEAR_PackageFile($this->config, $this->debug); + $pkg = &$pf->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL); + if (PEAR::isError($pkg)) { + return $pkg; + } } + $dir = dirname($descfile); + $old_cwd = getcwd(); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($pf)) { - $errs = $pf->getUserinfo(); - if (is_array($errs)) { - foreach ($errs as $error) { - if ($error['level'] == 'error') { - $errors[] = $error['message']; - } else { - $warnings[] = $error['message']; - } - } + if (!file_exists($dir) || !is_dir($dir) || !chdir($dir)) { + return $this->raiseError("could not chdir to $dir"); + } + + // packages that were in a .tar have the packagefile in this directory + $vdir = $pkg->getPackage() . '-' . $pkg->getVersion(); + if (file_exists($dir) && is_dir($vdir)) { + if (!chdir($vdir)) { + return $this->raiseError("could not chdir to " . realpath($vdir)); } - return false; + $dir = getcwd(); } - return true; - } + $this->log(2, "building in $dir"); - /** - * Build a "provides" array from data returned by - * analyzeSourceCode(). The format of the built array is like - * this: - * - * array( - * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'), - * ... - * ) - * - * - * @param array $srcinfo array with information about a source file - * as returned by the analyzeSourceCode() method. - * - * @return void - * - * @access public - * - */ - function buildProvidesArray($srcinfo) - { - $file = basename($srcinfo['source_file']); - $pn = ''; - if (isset($this->_packageName)) { - $pn = $this->_packageName; + $dsp = $pkg->getPackage().'.dsp'; + if (!file_exists("$dir/$dsp")) { + return $this->raiseError("The DSP $dsp does not exist."); } + // XXX TODO: make release build type configurable + $command = 'msdev '.$dsp.' /MAKE "'.$pkg->getPackage(). ' - Release"'; - $pnl = strlen($pn); - foreach ($srcinfo['declared_classes'] as $class) { - $key = "class;$class"; - if (isset($this->pkginfo['provides'][$key])) { - continue; - } - - $this->pkginfo['provides'][$key] = - array('file'=> $file, 'type' => 'class', 'name' => $class); - if (isset($srcinfo['inheritance'][$class])) { - $this->pkginfo['provides'][$key]['extends'] = - $srcinfo['inheritance'][$class]; - } + $err = $this->_runCommand($command, array(&$this, 'msdevCallback')); + if (PEAR::isError($err)) { + return $err; } - foreach ($srcinfo['declared_methods'] as $class => $methods) { - foreach ($methods as $method) { - $function = "$class::$method"; - $key = "function;$function"; - if ($method{0} == '_' || !strcasecmp($method, $class) || - isset($this->pkginfo['provides'][$key])) { - continue; - } + // figure out the build platform and type + $platform = 'Win32'; + $buildtype = 'Release'; + if (preg_match('/.*?'.$pkg->getPackage().'\s-\s(\w+)\s(.*?)-+/i',$this->_firstline,$matches)) { + $platform = $matches[1]; + $buildtype = $matches[2]; + } - $this->pkginfo['provides'][$key] = - array('file'=> $file, 'type' => 'function', 'name' => $function); + if (preg_match('/(.*)?\s-\s(\d+).*?(\d+)/', $this->_lastline, $matches)) { + if ($matches[2]) { + // there were errors in the build + return $this->raiseError("There were errors during compilation."); } + $out = $matches[1]; + } else { + return $this->raiseError("Did not understand the completion status returned from msdev.exe."); } - foreach ($srcinfo['declared_functions'] as $function) { - $key = "function;$function"; - if ($function{0} == '_' || isset($this->pkginfo['provides'][$key])) { - continue; - } + // msdev doesn't tell us the output directory :/ + // open the dsp, find /out and use that directory + $dsptext = join(file($dsp),''); - if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) { - $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\""; - } + // this regex depends on the build platform and type having been + // correctly identified above. + $regex ='/.*?!IF\s+"\$\(CFG\)"\s+==\s+("'. + $pkg->getPackage().'\s-\s'. + $platform.'\s'. + $buildtype.'").*?'. + '\/out:"(.*?)"/is'; - $this->pkginfo['provides'][$key] = - array('file'=> $file, 'type' => 'function', 'name' => $function); + if ($dsptext && preg_match($regex, $dsptext, $matches)) { + // what we get back is a relative path to the output file itself. + $outfile = realpath($matches[2]); + } else { + return $this->raiseError("Could not retrieve output information from $dsp."); + } + // realpath returns false if the file doesn't exist + if ($outfile && copy($outfile, "$dir/$out")) { + $outfile = "$dir/$out"; } + + $built_files[] = array( + 'file' => "$outfile", + 'php_api' => $this->php_api_version, + 'zend_mod_api' => $this->zend_module_api_no, + 'zend_ext_api' => $this->zend_extension_api_no, + ); + + return $built_files; } + // }}} - /** - * Analyze the source code of the given PHP file - * - * @param string Filename of the PHP file - * @return mixed - * @access public - */ - function analyzeSourceCode($file) + // {{{ msdevCallback() + function msdevCallback($what, $data) { - if (!class_exists('PEAR_PackageFile_v2_Validator')) { - require_once 'PEAR/PackageFile/v2/Validator.php'; - } - - $a = new PEAR_PackageFile_v2_Validator; - return $a->analyzeSourceCode($file); + if (!$this->_firstline) + $this->_firstline = $data; + $this->_lastline = $data; + call_user_func($this->current_callback, $what, $data); } - function detectDependencies($any, $status_callback = null) + /** + * @param string + * @param string + * @param array + * @access private + */ + function _harvestInstDir($dest_prefix, $dirname, &$built_files) { - if (!function_exists("token_get_all")) { + $d = opendir($dirname); + if (!$d) return false; - } - - if (PEAR::isError($info = $this->infoFromAny($any))) { - return $this->raiseError($info); - } - if (!is_array($info)) { - return false; - } + $ret = true; + while (($ent = readdir($d)) !== false) { + if ($ent{0} == '.') + continue; - $deps = array(); - $used_c = $decl_c = $decl_f = $decl_m = array(); - foreach ($info['filelist'] as $file => $fa) { - $tmp = $this->analyzeSourceCode($file); - $used_c = @array_merge($used_c, $tmp['used_classes']); - $decl_c = @array_merge($decl_c, $tmp['declared_classes']); - $decl_f = @array_merge($decl_f, $tmp['declared_functions']); - $decl_m = @array_merge($decl_m, $tmp['declared_methods']); - $inheri = @array_merge($inheri, $tmp['inheritance']); + $full = $dirname . DIRECTORY_SEPARATOR . $ent; + if (is_dir($full)) { + if (!$this->_harvestInstDir( + $dest_prefix . DIRECTORY_SEPARATOR . $ent, + $full, $built_files)) { + $ret = false; + break; + } + } else { + $dest = $dest_prefix . DIRECTORY_SEPARATOR . $ent; + $built_files[] = array( + 'file' => $full, + 'dest' => $dest, + 'php_api' => $this->php_api_version, + 'zend_mod_api' => $this->zend_module_api_no, + 'zend_ext_api' => $this->zend_extension_api_no, + ); + } } - - $used_c = array_unique($used_c); - $decl_c = array_unique($decl_c); - $undecl_c = array_diff($used_c, $decl_c); - - return array('used_classes' => $used_c, - 'declared_classes' => $decl_c, - 'declared_methods' => $decl_m, - 'declared_functions' => $decl_f, - 'undeclared_classes' => $undecl_c, - 'inheritance' => $inheri, - ); + closedir($d); + return $ret; } /** - * Download a file through HTTP. Considers suggested file name in - * Content-disposition: header and can run a callback function for - * different events. The callback will be called with two - * parameters: the callback type, and parameters. The implemented - * callback types are: - * - * 'setup' called at the very beginning, parameter is a UI object - * that should be used for all output - * 'message' the parameter is a string with an informational message - * 'saveas' may be used to save with a different file name, the - * parameter is the filename that is about to be used. - * If a 'saveas' callback returns a non-empty string, - * that file name will be used as the filename instead. - * Note that $save_dir will not be affected by this, only - * the basename of the file. - * 'start' download is starting, parameter is number of bytes - * that are expected, or -1 if unknown - * 'bytesread' parameter is the number of bytes read so far - * 'done' download is complete, parameter is the total number - * of bytes read - * 'connfailed' if the TCP connection fails, this callback is called - * with array(host,port,errno,errmsg) - * 'writefailed' if writing to disk fails, this callback is called - * with array(destfile,errmsg) + * Build an extension from source. Runs "phpize" in the source + * directory, but compiles in a temporary directory + * (/var/tmp/pear-build-USER/PACKAGE-VERSION). * - * If an HTTP proxy has been configured (http_proxy PEAR_Config - * setting), the proxy will be used. + * @param string|PEAR_PackageFile_v* $descfile path to XML package description file, or + * a PEAR_PackageFile object * - * @param string $url the URL to download - * @param object $ui PEAR_Frontend_* instance - * @param object $config PEAR_Config instance - * @param string $save_dir (optional) directory to save file in - * @param mixed $callback (optional) function/method to call for status - * updates + * @param mixed $callback callback function used to report output, + * see PEAR_Builder::_runCommand for details * - * @return string Returns the full path of the downloaded file or a PEAR - * error on failure. If the error is caused by - * socket-related errors, the error object will - * have the fsockopen error code available through - * getCode(). + * @return array an array of associative arrays with built files, + * format: + * array( array( 'file' => '/path/to/ext.so', + * 'php_api' => YYYYMMDD, + * 'zend_mod_api' => YYYYMMDD, + * 'zend_ext_api' => YYYYMMDD ), + * ... ) * * @access public - * @deprecated in favor of PEAR_Downloader::downloadHttp() + * + * @see PEAR_Builder::_runCommand */ - function downloadHttp($url, &$ui, $save_dir = '.', $callback = null) + function build($descfile, $callback = null) { - if (!class_exists('PEAR_Downloader')) { - require_once 'PEAR/Downloader.php'; + if (preg_match('/(\\/|\\\\|^)([^\\/\\\\]+)?php(.+)?$/', + $this->config->get('php_bin'), $matches)) { + if (isset($matches[2]) && strlen($matches[2]) && + trim($matches[2]) != trim($this->config->get('php_prefix'))) { + $this->log(0, 'WARNING: php_bin ' . $this->config->get('php_bin') . + ' appears to have a prefix ' . $matches[2] . ', but' . + ' config variable php_prefix does not match'); + } + if (isset($matches[3]) && strlen($matches[3]) && + trim($matches[3]) != trim($this->config->get('php_suffix'))) { + $this->log(0, 'WARNING: php_bin ' . $this->config->get('php_bin') . + ' appears to have a suffix ' . $matches[3] . ', but' . + ' config variable php_suffix does not match'); + } } - return PEAR_Downloader::downloadHttp($url, $ui, $save_dir, $callback); - } -} - -require_once 'PEAR/Config.php'; -require_once 'PEAR/PackageFile.php';PEAR-1.8.0/PEAR/Config.php100664 764 764 204247 100664 10023 - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Config.php,v 1.157 2009/02/25 00:23:26 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ -/** - * Required for error handling - */ -require_once 'PEAR.php'; -require_once 'PEAR/Registry.php'; -require_once 'PEAR/Installer/Role.php'; -require_once 'System.php'; -/** - * Last created PEAR_Config instance. - * @var object - */ -$GLOBALS['_PEAR_Config_instance'] = null; -if (!defined('PEAR_INSTALL_DIR') || !PEAR_INSTALL_DIR) { - $PEAR_INSTALL_DIR = PHP_LIBDIR . DIRECTORY_SEPARATOR . 'pear'; -} else { - $PEAR_INSTALL_DIR = PEAR_INSTALL_DIR; -} + $this->current_callback = $callback; + if (PEAR_OS == "Windows") { + return $this->_build_win32($descfile, $callback); + } + if (PEAR_OS != 'Unix') { + return $this->raiseError("building extensions not supported on this platform"); + } + if (is_object($descfile)) { + $pkg = $descfile; + $descfile = $pkg->getPackageFile(); + if (is_a($pkg, 'PEAR_PackageFile_v1')) { + $dir = dirname($descfile); + } else { + $dir = $pkg->_config->get('temp_dir') . '/' . $pkg->getName(); + // automatically delete at session end + $this->addTempFile($dir); + } + } else { + $pf = &new PEAR_PackageFile($this->config); + $pkg = &$pf->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL); + if (PEAR::isError($pkg)) { + return $pkg; + } + $dir = dirname($descfile); + } + $old_cwd = getcwd(); + if (!file_exists($dir) || !is_dir($dir) || !chdir($dir)) { + return $this->raiseError("could not chdir to $dir"); + } + $vdir = $pkg->getPackage() . '-' . $pkg->getVersion(); + if (is_dir($vdir)) { + chdir($vdir); + } + $dir = getcwd(); + $this->log(2, "building in $dir"); + putenv('PATH=' . $this->config->get('bin_dir') . ':' . getenv('PATH')); + $err = $this->_runCommand($this->config->get('php_prefix') + . "phpize" . + $this->config->get('php_suffix'), + array(&$this, 'phpizeCallback')); + if (PEAR::isError($err)) { + return $err; + } + if (!$err) { + return $this->raiseError("`phpize' failed"); + } -// Below we define constants with default values for all configuration -// parameters except username/password. All of them can have their -// defaults set through environment variables. The reason we use the -// PHP_ prefix is for some security, PHP protects environment -// variables starting with PHP_*. - -// default channel and preferred mirror is based on whether we are invoked through -// the "pear" or the "pecl" command -if (!defined('PEAR_RUNTYPE')) { - define('PEAR_RUNTYPE', 'pear'); -} - -if (PEAR_RUNTYPE == 'pear') { - define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pear.php.net'); -} else { - define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pecl.php.net'); -} - -if (getenv('PHP_PEAR_SYSCONF_DIR')) { - define('PEAR_CONFIG_SYSCONFDIR', getenv('PHP_PEAR_SYSCONF_DIR')); -} elseif (getenv('SystemRoot')) { - define('PEAR_CONFIG_SYSCONFDIR', getenv('SystemRoot')); -} else { - define('PEAR_CONFIG_SYSCONFDIR', PHP_SYSCONFDIR); -} - -// Default for master_server -if (getenv('PHP_PEAR_MASTER_SERVER')) { - define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', getenv('PHP_PEAR_MASTER_SERVER')); -} else { - define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', 'pear.php.net'); -} + // {{{ start of interactive part + $configure_command = "$dir/configure"; + $configure_options = $pkg->getConfigureOptions(); + if ($configure_options) { + foreach ($configure_options as $o) { + $default = array_key_exists('default', $o) ? $o['default'] : null; + list($r) = $this->ui->userDialog('build', + array($o['prompt']), + array('text'), + array($default)); + if (substr($o['name'], 0, 5) == 'with-' && + ($r == 'yes' || $r == 'autodetect')) { + $configure_command .= " --$o[name]"; + } else { + $configure_command .= " --$o[name]=".trim($r); + } + } + } + // }}} end of interactive part -// Default for http_proxy -if (getenv('PHP_PEAR_HTTP_PROXY')) { - define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('PHP_PEAR_HTTP_PROXY')); -} elseif (getenv('http_proxy')) { - define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('http_proxy')); -} else { - define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', ''); -} + // FIXME make configurable + if(!$user=getenv('USER')){ + $user='defaultuser'; + } + $build_basedir = "/var/tmp/pear-build-$user"; + $build_dir = "$build_basedir/$vdir"; + $inst_dir = "$build_basedir/install-$vdir"; + $this->log(1, "building in $build_dir"); + if (is_dir($build_dir)) { + System::rm(array('-rf', $build_dir)); + } + if (!System::mkDir(array('-p', $build_dir))) { + return $this->raiseError("could not create build dir: $build_dir"); + } + $this->addTempFile($build_dir); + if (!System::mkDir(array('-p', $inst_dir))) { + return $this->raiseError("could not create temporary install dir: $inst_dir"); + } + $this->addTempFile($inst_dir); -// Default for php_dir -if (getenv('PHP_PEAR_INSTALL_DIR')) { - define('PEAR_CONFIG_DEFAULT_PHP_DIR', getenv('PHP_PEAR_INSTALL_DIR')); -} else { - if (@file_exists($PEAR_INSTALL_DIR) && is_dir($PEAR_INSTALL_DIR)) { - define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR); - } else { - define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR); + if (getenv('MAKE')) { + $make_command = getenv('MAKE'); + } else { + $make_command = 'make'; + } + $to_run = array( + $configure_command, + $make_command, + "$make_command INSTALL_ROOT=\"$inst_dir\" install", + "find \"$inst_dir\" | xargs ls -dils" + ); + if (!file_exists($build_dir) || !is_dir($build_dir) || !chdir($build_dir)) { + return $this->raiseError("could not chdir to $build_dir"); + } + putenv('PHP_PEAR_VERSION=1.9.0'); + foreach ($to_run as $cmd) { + $err = $this->_runCommand($cmd, $callback); + if (PEAR::isError($err)) { + chdir($old_cwd); + return $err; + } + if (!$err) { + chdir($old_cwd); + return $this->raiseError("`$cmd' failed"); + } + } + if (!($dp = opendir("modules"))) { + chdir($old_cwd); + return $this->raiseError("no `modules' directory found"); + } + $built_files = array(); + $prefix = exec($this->config->get('php_prefix') + . "php-config" . + $this->config->get('php_suffix') . " --prefix"); + $this->_harvestInstDir($prefix, $inst_dir . DIRECTORY_SEPARATOR . $prefix, $built_files); + chdir($old_cwd); + return $built_files; } -} -// Default for ext_dir -if (getenv('PHP_PEAR_EXTENSION_DIR')) { - define('PEAR_CONFIG_DEFAULT_EXT_DIR', getenv('PHP_PEAR_EXTENSION_DIR')); -} else { - if (ini_get('extension_dir')) { - define('PEAR_CONFIG_DEFAULT_EXT_DIR', ini_get('extension_dir')); - } elseif (defined('PEAR_EXTENSION_DIR') && - file_exists(PEAR_EXTENSION_DIR) && is_dir(PEAR_EXTENSION_DIR)) { - define('PEAR_CONFIG_DEFAULT_EXT_DIR', PEAR_EXTENSION_DIR); - } elseif (defined('PHP_EXTENSION_DIR')) { - define('PEAR_CONFIG_DEFAULT_EXT_DIR', PHP_EXTENSION_DIR); - } else { - define('PEAR_CONFIG_DEFAULT_EXT_DIR', '.'); + /** + * Message callback function used when running the "phpize" + * program. Extracts the API numbers used. Ignores other message + * types than "cmdoutput". + * + * @param string $what the type of message + * @param mixed $data the message + * + * @return void + * + * @access public + */ + function phpizeCallback($what, $data) + { + if ($what != 'cmdoutput') { + return; + } + $this->log(1, rtrim($data)); + if (preg_match('/You should update your .aclocal.m4/', $data)) { + return; + } + $matches = array(); + if (preg_match('/^\s+(\S[^:]+):\s+(\d{8})/', $data, $matches)) { + $member = preg_replace('/[^a-z]/', '_', strtolower($matches[1])); + $apino = (int)$matches[2]; + if (isset($this->$member)) { + $this->$member = $apino; + //$msg = sprintf("%-22s : %d", $matches[1], $apino); + //$this->log(1, $msg); + } + } } -} - -// Default for doc_dir -if (getenv('PHP_PEAR_DOC_DIR')) { - define('PEAR_CONFIG_DEFAULT_DOC_DIR', getenv('PHP_PEAR_DOC_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_DOC_DIR', - $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'docs'); -} - -// Default for bin_dir -if (getenv('PHP_PEAR_BIN_DIR')) { - define('PEAR_CONFIG_DEFAULT_BIN_DIR', getenv('PHP_PEAR_BIN_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_BIN_DIR', PHP_BINDIR); -} - -// Default for data_dir -if (getenv('PHP_PEAR_DATA_DIR')) { - define('PEAR_CONFIG_DEFAULT_DATA_DIR', getenv('PHP_PEAR_DATA_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_DATA_DIR', - $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'data'); -} - -// Default for cfg_dir -if (getenv('PHP_PEAR_CFG_DIR')) { - define('PEAR_CONFIG_DEFAULT_CFG_DIR', getenv('PHP_PEAR_CFG_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_CFG_DIR', - $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'cfg'); -} - -// Default for www_dir -if (getenv('PHP_PEAR_WWW_DIR')) { - define('PEAR_CONFIG_DEFAULT_WWW_DIR', getenv('PHP_PEAR_WWW_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_WWW_DIR', - $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'www'); -} -// Default for test_dir -if (getenv('PHP_PEAR_TEST_DIR')) { - define('PEAR_CONFIG_DEFAULT_TEST_DIR', getenv('PHP_PEAR_TEST_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_TEST_DIR', - $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'tests'); -} + /** + * Run an external command, using a message callback to report + * output. The command will be run through popen and output is + * reported for every line with a "cmdoutput" message with the + * line string, including newlines, as payload. + * + * @param string $command the command to run + * + * @param mixed $callback (optional) function to use as message + * callback + * + * @return bool whether the command was successful (exit code 0 + * means success, any other means failure) + * + * @access private + */ + function _runCommand($command, $callback = null) + { + $this->log(1, "running: $command"); + $pp = popen("$command 2>&1", "r"); + if (!$pp) { + return $this->raiseError("failed to run `$command'"); + } + if ($callback && $callback[0]->debug == 1) { + $olddbg = $callback[0]->debug; + $callback[0]->debug = 2; + } -// Default for temp_dir -if (getenv('PHP_PEAR_TEMP_DIR')) { - define('PEAR_CONFIG_DEFAULT_TEMP_DIR', getenv('PHP_PEAR_TEMP_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_TEMP_DIR', - System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' . - DIRECTORY_SEPARATOR . 'temp'); -} + while ($line = fgets($pp, 1024)) { + if ($callback) { + call_user_func($callback, 'cmdoutput', $line); + } else { + $this->log(2, rtrim($line)); + } + } + if ($callback && isset($olddbg)) { + $callback[0]->debug = $olddbg; + } -// Default for cache_dir -if (getenv('PHP_PEAR_CACHE_DIR')) { - define('PEAR_CONFIG_DEFAULT_CACHE_DIR', getenv('PHP_PEAR_CACHE_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_CACHE_DIR', - System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' . - DIRECTORY_SEPARATOR . 'cache'); -} + $exitcode = is_resource($pp) ? pclose($pp) : -1; + return ($exitcode == 0); + } -// Default for download_dir -if (getenv('PHP_PEAR_DOWNLOAD_DIR')) { - define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR', getenv('PHP_PEAR_DOWNLOAD_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR', - System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' . - DIRECTORY_SEPARATOR . 'download'); -} + function log($level, $msg) + { + if ($this->current_callback) { + if ($this->debug >= $level) { + call_user_func($this->current_callback, 'output', $msg); + } + return; + } + return PEAR_Common::log($level, $msg); + } +}PEAR-1.9.0/PEAR/ChannelFile.php100664 764 764 143353 100664 10767 + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: ChannelFile.php 286951 2009-08-09 14:41:22Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ -// Default for php_bin -if (getenv('PHP_PEAR_PHP_BIN')) { - define('PEAR_CONFIG_DEFAULT_PHP_BIN', getenv('PHP_PEAR_PHP_BIN')); -} else { - define('PEAR_CONFIG_DEFAULT_PHP_BIN', PEAR_CONFIG_DEFAULT_BIN_DIR. - DIRECTORY_SEPARATOR.'php'.(OS_WINDOWS ? '.exe' : '')); -} +/** + * Needed for error handling + */ +require_once 'PEAR/ErrorStack.php'; +require_once 'PEAR/XMLParser.php'; +require_once 'PEAR/Common.php'; -// Default for verbose -if (getenv('PHP_PEAR_VERBOSE')) { - define('PEAR_CONFIG_DEFAULT_VERBOSE', getenv('PHP_PEAR_VERBOSE')); -} else { - define('PEAR_CONFIG_DEFAULT_VERBOSE', 1); -} +/** + * Error code if the channel.xml tag does not contain a valid version + */ +define('PEAR_CHANNELFILE_ERROR_NO_VERSION', 1); +/** + * Error code if the channel.xml tag version is not supported (version 1.0 is the only supported version, + * currently + */ +define('PEAR_CHANNELFILE_ERROR_INVALID_VERSION', 2); -// Default for preferred_state -if (getenv('PHP_PEAR_PREFERRED_STATE')) { - define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', getenv('PHP_PEAR_PREFERRED_STATE')); -} else { - define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', 'stable'); -} +/** + * Error code if parsing is attempted with no xml extension + */ +define('PEAR_CHANNELFILE_ERROR_NO_XML_EXT', 3); -// Default for umask -if (getenv('PHP_PEAR_UMASK')) { - define('PEAR_CONFIG_DEFAULT_UMASK', getenv('PHP_PEAR_UMASK')); -} else { - define('PEAR_CONFIG_DEFAULT_UMASK', decoct(umask())); -} +/** + * Error code if creating the xml parser resource fails + */ +define('PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER', 4); -// Default for cache_ttl -if (getenv('PHP_PEAR_CACHE_TTL')) { - define('PEAR_CONFIG_DEFAULT_CACHE_TTL', getenv('PHP_PEAR_CACHE_TTL')); -} else { - define('PEAR_CONFIG_DEFAULT_CACHE_TTL', 3600); -} +/** + * Error code used for all sax xml parsing errors + */ +define('PEAR_CHANNELFILE_ERROR_PARSER_ERROR', 5); -// Default for sig_type -if (getenv('PHP_PEAR_SIG_TYPE')) { - define('PEAR_CONFIG_DEFAULT_SIG_TYPE', getenv('PHP_PEAR_SIG_TYPE')); -} else { - define('PEAR_CONFIG_DEFAULT_SIG_TYPE', 'gpg'); -} +/**#@+ + * Validation errors + */ +/** + * Error code when channel name is missing + */ +define('PEAR_CHANNELFILE_ERROR_NO_NAME', 6); +/** + * Error code when channel name is invalid + */ +define('PEAR_CHANNELFILE_ERROR_INVALID_NAME', 7); +/** + * Error code when channel summary is missing + */ +define('PEAR_CHANNELFILE_ERROR_NO_SUMMARY', 8); +/** + * Error code when channel summary is multi-line + */ +define('PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY', 9); +/** + * Error code when channel server is missing for protocol + */ +define('PEAR_CHANNELFILE_ERROR_NO_HOST', 10); +/** + * Error code when channel server is invalid for protocol + */ +define('PEAR_CHANNELFILE_ERROR_INVALID_HOST', 11); +/** + * Error code when a mirror name is invalid + */ +define('PEAR_CHANNELFILE_ERROR_INVALID_MIRROR', 21); +/** + * Error code when a mirror type is invalid + */ +define('PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE', 22); +/** + * Error code when an attempt is made to generate xml, but the parsed content is invalid + */ +define('PEAR_CHANNELFILE_ERROR_INVALID', 23); +/** + * Error code when an empty package name validate regex is passed in + */ +define('PEAR_CHANNELFILE_ERROR_EMPTY_REGEX', 24); +/** + * Error code when a tag has no version + */ +define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION', 25); +/** + * Error code when a tag has no name + */ +define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME', 26); +/** + * Error code when a tag has no name + */ +define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME', 27); +/** + * Error code when a tag has no version attribute + */ +define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION', 28); +/** + * Error code when a mirror does not exist but is called for in one of the set* + * methods. + */ +define('PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND', 32); +/** + * Error code when a server port is not numeric + */ +define('PEAR_CHANNELFILE_ERROR_INVALID_PORT', 33); +/** + * Error code when contains no version attribute + */ +define('PEAR_CHANNELFILE_ERROR_NO_STATICVERSION', 34); +/** + * Error code when contains no type attribute in a protocol definition + */ +define('PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE', 35); +/** + * Error code when a mirror is defined and the channel.xml represents the __uri pseudo-channel + */ +define('PEAR_CHANNELFILE_URI_CANT_MIRROR', 36); +/** + * Error code when ssl attribute is present and is not "yes" + */ +define('PEAR_CHANNELFILE_ERROR_INVALID_SSL', 37); +/**#@-*/ -// Default for sig_bin -if (getenv('PHP_PEAR_SIG_BIN')) { - define('PEAR_CONFIG_DEFAULT_SIG_BIN', getenv('PHP_PEAR_SIG_BIN')); -} else { - define('PEAR_CONFIG_DEFAULT_SIG_BIN', - System::which( - 'gpg', OS_WINDOWS ? 'c:\gnupg\gpg.exe' : '/usr/local/bin/gpg')); -} +/** + * Mirror types allowed. Currently only internet servers are recognized. + */ +$GLOBALS['_PEAR_CHANNELS_MIRROR_TYPES'] = array('server'); -// Default for sig_keydir -if (getenv('PHP_PEAR_SIG_KEYDIR')) { - define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR', getenv('PHP_PEAR_SIG_KEYDIR')); -} else { - define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR', - PEAR_CONFIG_SYSCONFDIR . DIRECTORY_SEPARATOR . 'pearkeys'); -} /** - * This is a class for storing configuration data, keeping track of - * which are system-defined, user-defined or defaulted. + * The Channel handling class + * * @category pear * @package PEAR - * @author Stig Bakken * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 + * @since Class available since Release 1.4.0a1 */ -class PEAR_Config extends PEAR +class PEAR_ChannelFile { /** - * Array of config files used. - * - * @var array layer => config file - */ - var $files = array( - 'system' => '', - 'user' => '', - ); - - var $layers = array(); - - /** - * Configuration data, two-dimensional array where the first - * dimension is the config layer ('user', 'system' and 'default'), - * and the second dimension is keyname => value. - * - * The order in the first dimension is important! Earlier - * layers will shadow later ones when a config value is - * requested (if a 'user' value exists, it will be returned first, - * then 'system' and finally 'default'). - * - * @var array layer => array(keyname => value, ...) + * @access private + * @var PEAR_ErrorStack + * @access private */ - var $configuration = array( - 'user' => array(), - 'system' => array(), - 'default' => array(), - ); + var $_stack; /** - * Configuration values that can be set for a channel - * - * All other configuration values can only have a global value + * Supported channel.xml versions, for parsing * @var array * @access private */ - var $_channelConfigInfo = array( - 'php_dir', 'ext_dir', 'doc_dir', 'bin_dir', 'data_dir', 'cfg_dir', - 'test_dir', 'www_dir', 'php_bin', 'php_prefix', 'php_suffix', 'username', - 'password', 'verbose', 'preferred_state', 'umask', 'preferred_mirror', 'php_ini' - ); + var $_supportedVersions = array('1.0'); /** - * Channels that can be accessed - * @see setChannels() + * Parsed channel information * @var array * @access private */ - var $_channels = array('pear.php.net', 'pecl.php.net', '__uri'); + var $_channelInfo; /** - * This variable is used to control the directory values returned - * @see setInstallRoot(); - * @var string|false + * index into the subchannels array, used for parsing xml + * @var int * @access private */ - var $_installRoot = false; - - /** - * If requested, this will always refer to the registry - * contained in php_dir - * @var PEAR_Registry - */ - var $_registry = array(); + var $_subchannelIndex; /** - * @var array + * index into the mirrors array, used for parsing xml + * @var int * @access private */ - var $_regInitialized = array(); + var $_mirrorIndex; /** - * @var bool + * Flag used to determine the validity of parsed content + * @var boolean * @access private */ - var $_noRegistry = false; + var $_isValid = false; - /** - * amount of errors found while parsing config - * @var integer - * @access private - */ - var $_errorsFound = 0; - var $_lastError = null; + function PEAR_ChannelFile() + { + $this->_stack = &new PEAR_ErrorStack('PEAR_ChannelFile'); + $this->_stack->setErrorMessageTemplate($this->_getErrorMessage()); + $this->_isValid = false; + } /** - * Information about the configuration data. Stores the type, - * default value and a documentation string for each configuration - * value. - * - * @var array layer => array(infotype => value, ...) + * @return array + * @access protected */ - var $configuration_info = array( - // Channels/Internet Access - 'default_channel' => array( - 'type' => 'string', - 'default' => PEAR_CONFIG_DEFAULT_CHANNEL, - 'doc' => 'the default channel to use for all non explicit commands', - 'prompt' => 'Default Channel', - 'group' => 'Internet Access', - ), - 'preferred_mirror' => array( - 'type' => 'string', - 'default' => PEAR_CONFIG_DEFAULT_CHANNEL, - 'doc' => 'the default server or mirror to use for channel actions', - 'prompt' => 'Default Channel Mirror', - 'group' => 'Internet Access', - ), - 'remote_config' => array( - 'type' => 'password', - 'default' => '', - 'doc' => 'ftp url of remote configuration file to use for synchronized install', - 'prompt' => 'Remote Configuration File', - 'group' => 'Internet Access', - ), - 'auto_discover' => array( - 'type' => 'integer', - 'default' => 0, - 'doc' => 'whether to automatically discover new channels', - 'prompt' => 'Auto-discover new Channels', - 'group' => 'Internet Access', - ), - // Internet Access - 'master_server' => array( - 'type' => 'string', - 'default' => 'pear.php.net', - 'doc' => 'name of the main PEAR server [NOT USED IN THIS VERSION]', - 'prompt' => 'PEAR server [DEPRECATED]', - 'group' => 'Internet Access', - ), - 'http_proxy' => array( - 'type' => 'string', - 'default' => PEAR_CONFIG_DEFAULT_HTTP_PROXY, - 'doc' => 'HTTP proxy (host:port) to use when downloading packages', - 'prompt' => 'HTTP Proxy Server Address', - 'group' => 'Internet Access', - ), - // File Locations - 'php_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_PHP_DIR, - 'doc' => 'directory where .php files are installed', - 'prompt' => 'PEAR directory', - 'group' => 'File Locations', - ), - 'ext_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_EXT_DIR, - 'doc' => 'directory where loadable extensions are installed', - 'prompt' => 'PHP extension directory', - 'group' => 'File Locations', - ), - 'doc_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_DOC_DIR, - 'doc' => 'directory where documentation is installed', - 'prompt' => 'PEAR documentation directory', - 'group' => 'File Locations', - ), - 'bin_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_BIN_DIR, - 'doc' => 'directory where executables are installed', - 'prompt' => 'PEAR executables directory', - 'group' => 'File Locations', - ), - 'data_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_DATA_DIR, - 'doc' => 'directory where data files are installed', - 'prompt' => 'PEAR data directory', - 'group' => 'File Locations (Advanced)', - ), - 'cfg_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_CFG_DIR, - 'doc' => 'directory where modifiable configuration files are installed', - 'prompt' => 'PEAR configuration file directory', - 'group' => 'File Locations (Advanced)', - ), - 'www_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_WWW_DIR, - 'doc' => 'directory where www frontend files (html/js) are installed', - 'prompt' => 'PEAR www files directory', - 'group' => 'File Locations (Advanced)', - ), - 'test_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_TEST_DIR, - 'doc' => 'directory where regression tests are installed', - 'prompt' => 'PEAR test directory', - 'group' => 'File Locations (Advanced)', - ), - 'cache_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_CACHE_DIR, - 'doc' => 'directory which is used for web service cache', - 'prompt' => 'PEAR Installer cache directory', - 'group' => 'File Locations (Advanced)', - ), - 'temp_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_TEMP_DIR, - 'doc' => 'directory which is used for all temp files', - 'prompt' => 'PEAR Installer temp directory', - 'group' => 'File Locations (Advanced)', - ), - 'download_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR, - 'doc' => 'directory which is used for all downloaded files', - 'prompt' => 'PEAR Installer download directory', - 'group' => 'File Locations (Advanced)', - ), - 'php_bin' => array( - 'type' => 'file', - 'default' => PEAR_CONFIG_DEFAULT_PHP_BIN, - 'doc' => 'PHP CLI/CGI binary for executing scripts', - 'prompt' => 'PHP CLI/CGI binary', - 'group' => 'File Locations (Advanced)', - ), - 'php_prefix' => array( - 'type' => 'string', - 'default' => '', - 'doc' => '--program-prefix for php_bin\'s ./configure, used for pecl installs', - 'prompt' => '--program-prefix passed to PHP\'s ./configure', - 'group' => 'File Locations (Advanced)', - ), - 'php_suffix' => array( - 'type' => 'string', - 'default' => '', - 'doc' => '--program-suffix for php_bin\'s ./configure, used for pecl installs', - 'prompt' => '--program-suffix passed to PHP\'s ./configure', - 'group' => 'File Locations (Advanced)', - ), - 'php_ini' => array( - 'type' => 'file', - 'default' => '', - 'doc' => 'location of php.ini in which to enable PECL extensions on install', - 'prompt' => 'php.ini location', - 'group' => 'File Locations (Advanced)', - ), - // Maintainers - 'username' => array( - 'type' => 'string', - 'default' => '', - 'doc' => '(maintainers) your PEAR account name', - 'prompt' => 'PEAR username (for maintainers)', - 'group' => 'Maintainers', - ), - 'password' => array( - 'type' => 'password', - 'default' => '', - 'doc' => '(maintainers) your PEAR account password', - 'prompt' => 'PEAR password (for maintainers)', - 'group' => 'Maintainers', - ), - // Advanced - 'verbose' => array( - 'type' => 'integer', - 'default' => PEAR_CONFIG_DEFAULT_VERBOSE, - 'doc' => 'verbosity level -0: really quiet -1: somewhat quiet -2: verbose -3: debug', - 'prompt' => 'Debug Log Level', - 'group' => 'Advanced', - ), - 'preferred_state' => array( - 'type' => 'set', - 'default' => PEAR_CONFIG_DEFAULT_PREFERRED_STATE, - 'doc' => 'the installer will prefer releases with this state when installing packages without a version or state specified', - 'valid_set' => array( - 'stable', 'beta', 'alpha', 'devel', 'snapshot'), - 'prompt' => 'Preferred Package State', - 'group' => 'Advanced', - ), - 'umask' => array( - 'type' => 'mask', - 'default' => PEAR_CONFIG_DEFAULT_UMASK, - 'doc' => 'umask used when creating files (Unix-like systems only)', - 'prompt' => 'Unix file mask', - 'group' => 'Advanced', - ), - 'cache_ttl' => array( - 'type' => 'integer', - 'default' => PEAR_CONFIG_DEFAULT_CACHE_TTL, - 'doc' => 'amount of secs where the local cache is used and not updated', - 'prompt' => 'Cache TimeToLive', - 'group' => 'Advanced', - ), - 'sig_type' => array( - 'type' => 'set', - 'default' => PEAR_CONFIG_DEFAULT_SIG_TYPE, - 'doc' => 'which package signature mechanism to use', - 'valid_set' => array('gpg'), - 'prompt' => 'Package Signature Type', - 'group' => 'Maintainers', - ), - 'sig_bin' => array( - 'type' => 'string', - 'default' => PEAR_CONFIG_DEFAULT_SIG_BIN, - 'doc' => 'which package signature mechanism to use', - 'prompt' => 'Signature Handling Program', - 'group' => 'Maintainers', - ), - 'sig_keyid' => array( - 'type' => 'string', - 'default' => '', - 'doc' => 'which key to use for signing with', - 'prompt' => 'Signature Key Id', - 'group' => 'Maintainers', - ), - 'sig_keydir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_SIG_KEYDIR, - 'doc' => 'directory where signature keys are located', - 'prompt' => 'Signature Key Directory', - 'group' => 'Maintainers', - ), - // __channels is reserved - used for channel-specific configuration - ); + function _getErrorMessage() + { + return + array( + PEAR_CHANNELFILE_ERROR_INVALID_VERSION => + 'While parsing channel.xml, an invalid version number "%version% was passed in, expecting one of %versions%', + PEAR_CHANNELFILE_ERROR_NO_VERSION => + 'No version number found in tag', + PEAR_CHANNELFILE_ERROR_NO_XML_EXT => + '%error%', + PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER => + 'Unable to create XML parser', + PEAR_CHANNELFILE_ERROR_PARSER_ERROR => + '%error%', + PEAR_CHANNELFILE_ERROR_NO_NAME => + 'Missing channel name', + PEAR_CHANNELFILE_ERROR_INVALID_NAME => + 'Invalid channel %tag% "%name%"', + PEAR_CHANNELFILE_ERROR_NO_SUMMARY => + 'Missing channel summary', + PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY => + 'Channel summary should be on one line, but is multi-line', + PEAR_CHANNELFILE_ERROR_NO_HOST => + 'Missing channel server for %type% server', + PEAR_CHANNELFILE_ERROR_INVALID_HOST => + 'Server name "%server%" is invalid for %type% server', + PEAR_CHANNELFILE_ERROR_INVALID_MIRROR => + 'Invalid mirror name "%name%", mirror type %type%', + PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE => + 'Invalid mirror type "%type%"', + PEAR_CHANNELFILE_ERROR_INVALID => + 'Cannot generate xml, contents are invalid', + PEAR_CHANNELFILE_ERROR_EMPTY_REGEX => + 'packagenameregex cannot be empty', + PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION => + '%parent% %protocol% function has no version', + PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME => + '%parent% %protocol% function has no name', + PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE => + '%parent% rest baseurl has no type', + PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME => + 'Validation package has no name in tag', + PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION => + 'Validation package "%package%" has no version', + PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND => + 'Mirror "%mirror%" does not exist', + PEAR_CHANNELFILE_ERROR_INVALID_PORT => + 'Port "%port%" must be numeric', + PEAR_CHANNELFILE_ERROR_NO_STATICVERSION => + ' tag must contain version attribute', + PEAR_CHANNELFILE_URI_CANT_MIRROR => + 'The __uri pseudo-channel cannot have mirrors', + PEAR_CHANNELFILE_ERROR_INVALID_SSL => + '%server% has invalid ssl attribute "%ssl%" can only be yes or not present', + ); + } /** - * Constructor. - * - * @param string file to read user-defined options from - * @param string file to read system-wide defaults from - * @param bool determines whether a registry object "follows" - * the value of php_dir (is automatically created - * and moved when php_dir is changed) - * @param bool if true, fails if configuration files cannot be loaded - * - * @access public - * - * @see PEAR_Config::singleton + * @param string contents of package.xml file + * @return bool success of parsing */ - function PEAR_Config($user_file = '', $system_file = '', $ftp_file = false, - $strict = true) + function fromXmlString($data) { - $this->PEAR(); - PEAR_Installer_Role::initializeConfig($this); - $sl = DIRECTORY_SEPARATOR; - if (empty($user_file)) { - if (OS_WINDOWS) { - $user_file = PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini'; - } else { - $user_file = getenv('HOME') . $sl . '.pearrc'; - } - } - - if (empty($system_file)) { - $system_file = PEAR_CONFIG_SYSCONFDIR . $sl; - if (OS_WINDOWS) { - $system_file .= 'pearsys.ini'; - } else { - $system_file .= 'pear.conf'; - } - } - - $this->layers = array_keys($this->configuration); - $this->files['user'] = $user_file; - $this->files['system'] = $system_file; - if ($user_file && file_exists($user_file)) { - $this->pushErrorHandling(PEAR_ERROR_RETURN); - $this->readConfigFile($user_file, 'user', $strict); - $this->popErrorHandling(); - if ($this->_errorsFound > 0) { - return; + if (preg_match('/_supportedVersions)) { + $this->_stack->push(PEAR_CHANNELFILE_ERROR_INVALID_VERSION, 'error', + array('version' => $channelversion[1])); + return false; } - } - - if ($system_file && @file_exists($system_file)) { - $this->mergeConfigFile($system_file, false, 'system', $strict); - if ($this->_errorsFound > 0) { - return; + $parser = new PEAR_XMLParser; + $result = $parser->parse($data); + if ($result !== true) { + if ($result->getCode() == 1) { + $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_XML_EXT, 'error', + array('error' => $result->getMessage())); + } else { + $this->_stack->push(PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER, 'error'); + } + return false; } - - } - - if (!$ftp_file) { - $ftp_file = $this->get('remote_config'); - } - - if ($ftp_file && defined('PEAR_REMOTEINSTALL_OK')) { - $this->readFTPConfigFile($ftp_file); + $this->_channelInfo = $parser->getData(); + return true; + } else { + $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_VERSION, 'error', array('xml' => $data)); + return false; } + } - foreach ($this->configuration_info as $key => $info) { - $this->configuration['default'][$key] = $info['default']; + /** + * @return array + */ + function toArray() + { + if (!$this->_isValid && !$this->validate()) { + return false; } - - $this->_registry['default'] = &new PEAR_Registry($this->configuration['default']['php_dir']); - $this->_registry['default']->setConfig($this, false); - $this->_regInitialized['default'] = false; - //$GLOBALS['_PEAR_Config_instance'] = &$this; + return $this->_channelInfo; } /** - * Return the default locations of user and system configuration files + * @param array * @static + * @return PEAR_ChannelFile|false false if invalid */ - function getDefaultConfigFiles() + function &fromArray($data, $compatibility = false, $stackClass = 'PEAR_ErrorStack') { - $sl = DIRECTORY_SEPARATOR; - if (OS_WINDOWS) { - return array( - 'user' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini', - 'system' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pearsys.ini' - ); + $a = new PEAR_ChannelFile($compatibility, $stackClass); + $a->_fromArray($data); + if (!$a->validate()) { + $a = false; + return $a; } - - return array( - 'user' => getenv('HOME') . $sl . '.pearrc', - 'system' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.conf' - ); + return $a; } /** - * Static singleton method. If you want to keep only one instance - * of this class in use, this method will give you a reference to - * the last created PEAR_Config object if one exists, or create a - * new object. - * - * @param string (optional) file to read user-defined options from - * @param string (optional) file to read system-wide defaults from - * - * @return object an existing or new PEAR_Config instance - * - * @access public - * - * @see PEAR_Config::PEAR_Config + * Unlike {@link fromArray()} this does not do any validation + * @param array + * @static + * @return PEAR_ChannelFile */ - function &singleton($user_file = '', $system_file = '', $strict = true) + function &fromArrayWithErrors($data, $compatibility = false, + $stackClass = 'PEAR_ErrorStack') { - if (is_object($GLOBALS['_PEAR_Config_instance'])) { - return $GLOBALS['_PEAR_Config_instance']; - } - - $t_conf = &new PEAR_Config($user_file, $system_file, false, $strict); - if ($t_conf->_errorsFound > 0) { - return $t_conf->lastError; - } - - $GLOBALS['_PEAR_Config_instance'] = &$t_conf; - return $GLOBALS['_PEAR_Config_instance']; + $a = new PEAR_ChannelFile($compatibility, $stackClass); + $a->_fromArray($data); + return $a; } /** - * Determine whether any configuration files have been detected, and whether a - * registry object can be retrieved from this configuration. - * @return bool - * @since PEAR 1.4.0a1 + * @param array + * @access private */ - function validConfiguration() + function _fromArray($data) { - if ($this->isDefinedLayer('user') || $this->isDefinedLayer('system')) { - return true; - } - - return false; + $this->_channelInfo = $data; } /** - * Reads configuration data from a file. All existing values in - * the config layer are discarded and replaced with data from the - * file. - * @param string file to read from, if NULL or not specified, the - * last-used file for the same layer (second param) is used - * @param string config layer to insert data into ('user' or 'system') - * @return bool TRUE on success or a PEAR error on failure + * Wrapper to {@link PEAR_ErrorStack::getErrors()} + * @param boolean determines whether to purge the error stack after retrieving + * @return array */ - function readConfigFile($file = null, $layer = 'user', $strict = true) + function getErrors($purge = false) { - if (empty($this->files[$layer])) { - return $this->raiseError("unknown config layer `$layer'"); - } - - if ($file === null) { - $file = $this->files[$layer]; - } + return $this->_stack->getErrors($purge); + } - $data = $this->_readConfigDataFrom($file); - if (PEAR::isError($data)) { - if (!$strict) { - return true; + /** + * Unindent given string (?) + * + * @param string $str The string that has to be unindented. + * @return string + * @access private + */ + function _unIndent($str) + { + // remove leading newlines + $str = preg_replace('/^[\r\n]+/', '', $str); + // find whitespace at the beginning of the first line + $indent_len = strspn($str, " \t"); + $indent = substr($str, 0, $indent_len); + $data = ''; + // remove the same amount of whitespace from following lines + foreach (explode("\n", $str) as $line) { + if (substr($line, 0, $indent_len) == $indent) { + $data .= substr($line, $indent_len) . "\n"; } - - $this->_errorsFound++; - $this->lastError = $data; - - return $data; - } - - $this->files[$layer] = $file; - $this->_decodeInput($data); - $this->configuration[$layer] = $data; - $this->_setupChannels(); - if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) { - $this->_registry[$layer] = &new PEAR_Registry($phpdir); - $this->_registry[$layer]->setConfig($this, false); - $this->_regInitialized[$layer] = false; - } else { - unset($this->_registry[$layer]); } - return true; + return $data; } /** - * @param string url to the remote config file, like ftp://www.example.com/pear/config.ini - * @return true|PEAR_Error + * Parse a channel.xml file. Expects the name of + * a channel xml file as input. + * + * @param string $descfile name of channel xml file + * @return bool success of parsing */ - function readFTPConfigFile($path) + function fromXmlFile($descfile) { - do { // poor man's try - if (!class_exists('PEAR_FTP')) { - if (!class_exists('PEAR_Common')) { - require_once 'PEAR/Common.php'; - } - if (PEAR_Common::isIncludeable('PEAR/FTP.php')) { - require_once 'PEAR/FTP.php'; - } - } - - if (!class_exists('PEAR_FTP')) { - return PEAR::raiseError('PEAR_RemoteInstaller must be installed to use remote config'); - } - - $this->_ftp = &new PEAR_FTP; - $this->_ftp->pushErrorHandling(PEAR_ERROR_RETURN); - $e = $this->_ftp->init($path); - if (PEAR::isError($e)) { - $this->_ftp->popErrorHandling(); - return $e; - } - - $tmp = System::mktemp('-d'); - PEAR_Common::addTempFile($tmp); - $e = $this->_ftp->get(basename($path), $tmp . DIRECTORY_SEPARATOR . - 'pear.ini', false, FTP_BINARY); - if (PEAR::isError($e)) { - $this->_ftp->popErrorHandling(); - return $e; - } - - PEAR_Common::addTempFile($tmp . DIRECTORY_SEPARATOR . 'pear.ini'); - $this->_ftp->disconnect(); - $this->_ftp->popErrorHandling(); - $this->files['ftp'] = $tmp . DIRECTORY_SEPARATOR . 'pear.ini'; - $e = $this->readConfigFile(null, 'ftp'); - if (PEAR::isError($e)) { - return $e; - } - - $fail = array(); - foreach ($this->configuration_info as $key => $val) { - if (in_array($this->getGroup($key), - array('File Locations', 'File Locations (Advanced)')) && - $this->getType($key) == 'directory') { - // any directory configs must be set for this to work - if (!isset($this->configuration['ftp'][$key])) { - $fail[] = $key; - } - } - } - - if (!count($fail)) { - return true; - } + if (!file_exists($descfile) || !is_file($descfile) || !is_readable($descfile) || + (!$fp = fopen($descfile, 'r'))) { + require_once 'PEAR.php'; + return PEAR::raiseError("Unable to open $descfile"); + } - $fail = '"' . implode('", "', $fail) . '"'; - unset($this->files['ftp']); - unset($this->configuration['ftp']); - return PEAR::raiseError('ERROR: Ftp configuration file must set all ' . - 'directory configuration variables. These variables were not set: ' . - $fail); - } while (false); // poor man's catch - unset($this->files['ftp']); - return PEAR::raiseError('no remote host specified'); + // read the whole thing so we only get one cdata callback + // for each block of cdata + fclose($fp); + $data = file_get_contents($descfile); + return $this->fromXmlString($data); } /** - * Reads the existing configurations and creates the _channels array from it + * Parse channel information from different sources + * + * This method is able to extract information about a channel + * from an .xml file or a string + * + * @access public + * @param string Filename of the source or the source itself + * @return bool */ - function _setupChannels() + function fromAny($info) { - $set = array_flip(array_values($this->_channels)); - foreach ($this->configuration as $layer => $data) { - $i = 1000; - if (isset($data['__channels']) && is_array($data['__channels'])) { - foreach ($data['__channels'] as $channel => $info) { - $set[$channel] = $i++; + if (is_string($info) && file_exists($info) && strlen($info) < 255) { + $tmp = substr($info, -4); + if ($tmp == '.xml') { + $info = $this->fromXmlFile($info); + } else { + $fp = fopen($info, "r"); + $test = fread($fp, 5); + fclose($fp); + if ($test == "fromXmlFile($info); } } + if (PEAR::isError($info)) { + require_once 'PEAR.php'; + return PEAR::raiseError($info); + } } - $this->_channels = array_values(array_flip($set)); - $this->setChannels($this->_channels); + if (is_string($info)) { + $info = $this->fromXmlString($info); + } + return $info; } - function deleteChannel($channel) + /** + * Return an XML document based on previous parsing and modifications + * + * @return string XML data + * + * @access public + */ + function toXml() { - $ch = strtolower($channel); - foreach ($this->configuration as $layer => $data) { - if (isset($data['__channels']) && isset($data['__channels'][$ch])) { - unset($this->configuration[$layer]['__channels'][$ch]); - } + if (!$this->_isValid && !$this->validate()) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID); + return false; } - - $this->_channels = array_flip($this->_channels); - unset($this->_channels[$ch]); - $this->_channels = array_flip($this->_channels); + if (!isset($this->_channelInfo['attribs']['version'])) { + $this->_channelInfo['attribs']['version'] = '1.0'; + } + $channelInfo = $this->_channelInfo; + $ret = "\n"; + $ret .= " + $channelInfo[name] + " . htmlspecialchars($channelInfo['summary'])." +"; + if (isset($channelInfo['suggestedalias'])) { + $ret .= ' ' . $channelInfo['suggestedalias'] . "\n"; + } + if (isset($channelInfo['validatepackage'])) { + $ret .= ' ' . + htmlspecialchars($channelInfo['validatepackage']['_content']) . + "\n"; + } + $ret .= " \n"; + $ret .= ' _makeRestXml($channelInfo['servers']['primary']['rest'], ' '); + } + $ret .= " \n"; + if (isset($channelInfo['servers']['mirror'])) { + $ret .= $this->_makeMirrorsXml($channelInfo); + } + $ret .= " \n"; + $ret .= ""; + return str_replace("\r", "\n", str_replace("\r\n", "\n", $ret)); } /** - * Merges data into a config layer from a file. Does the same - * thing as readConfigFile, except it does not replace all - * existing values in the config layer. - * @param string file to read from - * @param bool whether to overwrite existing data (default TRUE) - * @param string config layer to insert data into ('user' or 'system') - * @param string if true, errors are returned if file opening fails - * @return bool TRUE on success or a PEAR error on failure + * Generate the tag + * @access private */ - function mergeConfigFile($file, $override = true, $layer = 'user', $strict = true) + function _makeRestXml($info, $indent) { - if (empty($this->files[$layer])) { - return $this->raiseError("unknown config layer `$layer'"); - } - - if ($file === null) { - $file = $this->files[$layer]; + $ret = $indent . "\n"; + if (isset($info['baseurl']) && !isset($info['baseurl'][0])) { + $info['baseurl'] = array($info['baseurl']); } - $data = $this->_readConfigDataFrom($file); - if (PEAR::isError($data)) { - if (!$strict) { - return true; + if (isset($info['baseurl'])) { + foreach ($info['baseurl'] as $url) { + $ret .= "$indent \n"; } - - $this->_errorsFound++; - $this->lastError = $data; - - return $data; } + $ret .= $indent . "\n"; + return $ret; + } - $this->_decodeInput($data); - if ($override) { - $this->configuration[$layer] = - PEAR_Config::arrayMergeRecursive($this->configuration[$layer], $data); - } else { - $this->configuration[$layer] = - PEAR_Config::arrayMergeRecursive($data, $this->configuration[$layer]); + /** + * Generate the tag + * @access private + */ + function _makeMirrorsXml($channelInfo) + { + $ret = ""; + if (!isset($channelInfo['servers']['mirror'][0])) { + $channelInfo['servers']['mirror'] = array($channelInfo['servers']['mirror']); } - - $this->_setupChannels(); - if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) { - $this->_registry[$layer] = &new PEAR_Registry($phpdir); - $this->_registry[$layer]->setConfig($this, false); - $this->_regInitialized[$layer] = false; - } else { - unset($this->_registry[$layer]); + foreach ($channelInfo['servers']['mirror'] as $mirror) { + $ret .= ' _makeRestXml($mirror['rest'], ' '); + } + $ret .= " \n"; + } else { + $ret .= "/>\n"; + } } - return true; + return $ret; } /** - * @param array - * @param array - * @return array - * @static + * Generate the tag + * @access private */ - function arrayMergeRecursive($arr2, $arr1) + function _makeFunctionsXml($functions, $indent, $rest = false) { - $ret = array(); - foreach ($arr2 as $key => $data) { - if (!isset($arr1[$key])) { - $ret[$key] = $data; - unset($arr1[$key]); - continue; - } - if (is_array($data)) { - if (!is_array($arr1[$key])) { - $ret[$key] = $arr1[$key]; - unset($arr1[$key]); - continue; - } - $ret[$key] = PEAR_Config::arrayMergeRecursive($arr1[$key], $arr2[$key]); - unset($arr1[$key]); + $ret = ''; + if (!isset($functions[0])) { + $functions = array($functions); + } + foreach ($functions as $function) { + $ret .= "$indent\n"; } + return $ret; + } - return array_merge($ret, $arr1); + /** + * Validation error. Also marks the object contents as invalid + * @param error code + * @param array error information + * @access private + */ + function _validateError($code, $params = array()) + { + $this->_stack->push($code, 'error', $params); + $this->_isValid = false; } /** - * Writes data into a config layer from a file. + * Validation warning. Does not mark the object contents invalid. + * @param error code + * @param array error information + * @access private + */ + function _validateWarning($code, $params = array()) + { + $this->_stack->push($code, 'warning', $params); + } + + /** + * Validate parsed file. * - * @param string|null file to read from, or null for default - * @param string config layer to insert data into ('user' or - * 'system') - * @param string|null data to write to config file or null for internal data [DEPRECATED] - * @return bool TRUE on success or a PEAR error on failure + * @access public + * @return boolean */ - function writeConfigFile($file = null, $layer = 'user', $data = null) + function validate() { - $this->_lazyChannelSetup($layer); - if ($layer == 'both' || $layer == 'all') { - foreach ($this->files as $type => $file) { - $err = $this->writeConfigFile($file, $type, $data); - if (PEAR::isError($err)) { - return $err; - } + $this->_isValid = true; + $info = $this->_channelInfo; + if (empty($info['name'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_NAME); + } elseif (!$this->validChannelServer($info['name'])) { + if ($info['name'] != '__uri') { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, array('tag' => 'name', + 'name' => $info['name'])); } - return true; } - - if (empty($this->files[$layer])) { - return $this->raiseError("unknown config file type `$layer'"); + if (empty($info['summary'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY); + } elseif (strpos(trim($info['summary']), "\n") !== false) { + $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY, + array('summary' => $info['summary'])); } - - if ($file === null) { - $file = $this->files[$layer]; + if (isset($info['suggestedalias'])) { + if (!$this->validChannelServer($info['suggestedalias'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, + array('tag' => 'suggestedalias', 'name' =>$info['suggestedalias'])); + } } - - $data = ($data === null) ? $this->configuration[$layer] : $data; - $this->_encodeOutput($data); - $opt = array('-p', dirname($file)); - if (!@System::mkDir($opt)) { - return $this->raiseError("could not create directory: " . dirname($file)); + if (isset($info['localalias'])) { + if (!$this->validChannelServer($info['localalias'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, + array('tag' => 'localalias', 'name' =>$info['localalias'])); + } + } + if (isset($info['validatepackage'])) { + if (!isset($info['validatepackage']['_content'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME); + } + if (!isset($info['validatepackage']['attribs']['version'])) { + $content = isset($info['validatepackage']['_content']) ? + $info['validatepackage']['_content'] : + null; + $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION, + array('package' => $content)); + } } - if (file_exists($file) && is_file($file) && !is_writeable($file)) { - return $this->raiseError("no write access to $file!"); + if (isset($info['servers']['primary']['attribs'], $info['servers']['primary']['attribs']['port']) && + !is_numeric($info['servers']['primary']['attribs']['port'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_PORT, + array('port' => $info['servers']['primary']['attribs']['port'])); } - $fp = @fopen($file, "w"); - if (!$fp) { - return $this->raiseError("PEAR_Config::writeConfigFile fopen('$file','w') failed ($php_errormsg)"); + if (isset($info['servers']['primary']['attribs'], $info['servers']['primary']['attribs']['ssl']) && + $info['servers']['primary']['attribs']['ssl'] != 'yes') { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL, + array('ssl' => $info['servers']['primary']['attribs']['ssl'], + 'server' => $info['name'])); } - $contents = "#PEAR_Config 0.9\n" . serialize($data); - if (!@fwrite($fp, $contents)) { - return $this->raiseError("PEAR_Config::writeConfigFile: fwrite failed ($php_errormsg)"); + if (isset($info['servers']['primary']['rest']) && + isset($info['servers']['primary']['rest']['baseurl'])) { + $this->_validateFunctions('rest', $info['servers']['primary']['rest']['baseurl']); } - return true; + if (isset($info['servers']['mirror'])) { + if ($this->_channelInfo['name'] == '__uri') { + $this->_validateError(PEAR_CHANNELFILE_URI_CANT_MIRROR); + } + if (!isset($info['servers']['mirror'][0])) { + $info['servers']['mirror'] = array($info['servers']['mirror']); + } + foreach ($info['servers']['mirror'] as $mirror) { + if (!isset($mirror['attribs']['host'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_HOST, + array('type' => 'mirror')); + } elseif (!$this->validChannelServer($mirror['attribs']['host'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_HOST, + array('server' => $mirror['attribs']['host'], 'type' => 'mirror')); + } + if (isset($mirror['attribs']['ssl']) && $mirror['attribs']['ssl'] != 'yes') { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL, + array('ssl' => $info['ssl'], 'server' => $mirror['attribs']['host'])); + } + if (isset($mirror['rest'])) { + $this->_validateFunctions('rest', $mirror['rest']['baseurl'], + $mirror['attribs']['host']); + } + } + } + return $this->_isValid; } /** - * Reads configuration data from a file and returns the parsed data - * in an array. - * - * @param string file to read from - * @return array configuration data or a PEAR error on failure - * @access private + * @param string rest - protocol name this function applies to + * @param array the functions + * @param string the name of the parent element (mirror name, for instance) */ - function _readConfigDataFrom($file) + function _validateFunctions($protocol, $functions, $parent = '') { - $fp = false; - if (file_exists($file)) { - $fp = @fopen($file, "r"); + if (!isset($functions[0])) { + $functions = array($functions); } - if (!$fp) { - return $this->raiseError("PEAR_Config::readConfigFile fopen('$file','r') failed"); - } + foreach ($functions as $function) { + if (!isset($function['_content']) || empty($function['_content'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME, + array('parent' => $parent, 'protocol' => $protocol)); + } - $size = filesize($file); - $rt = get_magic_quotes_runtime(); - set_magic_quotes_runtime(0); - fclose($fp); - $contents = file_get_contents($file); - if (empty($contents)) { - return $this->raiseError('Configuration file "' . $file . '" is empty'); - } - - set_magic_quotes_runtime($rt); - - $version = false; - if (preg_match('/^#PEAR_Config\s+(\S+)\s+/si', $contents, $matches)) { - $version = $matches[1]; - $contents = substr($contents, strlen($matches[0])); - } else { - // Museum config file - if (substr($contents,0,2) == 'a:') { - $version = '0.1'; - } - } - - if ($version && version_compare("$version", '1', '<')) { - // no '@', it is possible that unserialize - // raises a notice but it seems to block IO to - // STDOUT if a '@' is used and a notice is raise - $data = unserialize($contents); - - if (!is_array($data) && !$data) { - if ($contents == serialize(false)) { - $data = array(); - } else { - $err = $this->raiseError("PEAR_Config: bad data in $file"); - return $err; + if ($protocol == 'rest') { + if (!isset($function['attribs']['type']) || + empty($function['attribs']['type'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE, + array('parent' => $parent, 'protocol' => $protocol)); } - } - if (!is_array($data)) { - if (strlen(trim($contents)) > 0) { - $error = "PEAR_Config: bad data in $file"; - $err = $this->raiseError($error); - return $err; + } else { + if (!isset($function['attribs']['version']) || + empty($function['attribs']['version'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION, + array('parent' => $parent, 'protocol' => $protocol)); } - - $data = array(); } - // add parsing of newer formats here... - } else { - $err = $this->raiseError("$file: unknown version `$version'"); - return $err; } - - return $data; } /** - * Gets the file used for storing the config for a layer - * - * @param string $layer 'user' or 'system' - */ - function getConfFile($layer) + * Test whether a string contains a valid channel server. + * @param string $ver the package version to test + * @return bool + */ + function validChannelServer($server) { - return $this->files[$layer]; + if ($server == '__uri') { + return true; + } + return (bool) preg_match(PEAR_CHANNELS_SERVER_PREG, $server); } /** - * @param string Configuration class name, used for detecting duplicate calls - * @param array information on a role as parsed from its xml file - * @return true|PEAR_Error - * @access private + * @return string|false */ - function _addConfigVars($class, $vars) + function getName() { - static $called = array(); - if (isset($called[$class])) { - return; - } - - $called[$class] = 1; - if (count($vars) > 3) { - return $this->raiseError('Roles can only define 3 new config variables or less'); + if (isset($this->_channelInfo['name'])) { + return $this->_channelInfo['name']; } - foreach ($vars as $name => $var) { - if (!is_array($var)) { - return $this->raiseError('Configuration information must be an array'); - } + return false; + } - if (!isset($var['type'])) { - return $this->raiseError('Configuration information must contain a type'); - } elseif (!in_array($var['type'], - array('string', 'mask', 'password', 'directory', 'file', 'set'))) { - return $this->raiseError( - 'Configuration type must be one of directory, file, string, ' . - 'mask, set, or password'); - } - if (!isset($var['default'])) { - return $this->raiseError( - 'Configuration information must contain a default value ("default" index)'); - } + /** + * @return string|false + */ + function getServer() + { + if (isset($this->_channelInfo['name'])) { + return $this->_channelInfo['name']; + } - if (is_array($var['default'])) { - $real_default = ''; - foreach ($var['default'] as $config_var => $val) { - if (strpos($config_var, 'text') === 0) { - $real_default .= $val; - } elseif (strpos($config_var, 'constant') === 0) { - if (!defined($val)) { - return $this->raiseError( - 'Unknown constant "' . $val . '" requested in ' . - 'default value for configuration variable "' . - $name . '"'); - } + return false; + } - $real_default .= constant($val); - } elseif (isset($this->configuration_info[$config_var])) { - $real_default .= - $this->configuration_info[$config_var]['default']; - } else { - return $this->raiseError( - 'Unknown request for "' . $config_var . '" value in ' . - 'default value for configuration variable "' . - $name . '"'); - } + /** + * @return int|80 port number to connect to + */ + function getPort($mirror = false) + { + if ($mirror) { + if ($mir = $this->getMirror($mirror)) { + if (isset($mir['attribs']['port'])) { + return $mir['attribs']['port']; } - $var['default'] = $real_default; - } - - if ($var['type'] == 'integer') { - $var['default'] = (integer) $var['default']; - } - if (!isset($var['doc'])) { - return $this->raiseError( - 'Configuration information must contain a summary ("doc" index)'); - } + if ($this->getSSL($mirror)) { + return 443; + } - if (!isset($var['prompt'])) { - return $this->raiseError( - 'Configuration information must contain a simple prompt ("prompt" index)'); + return 80; } - if (!isset($var['group'])) { - return $this->raiseError( - 'Configuration information must contain a simple group ("group" index)'); - } + return false; + } - if (isset($this->configuration_info[$name])) { - return $this->raiseError('Configuration variable "' . $name . - '" already exists'); - } + if (isset($this->_channelInfo['servers']['primary']['attribs']['port'])) { + return $this->_channelInfo['servers']['primary']['attribs']['port']; + } - $this->configuration_info[$name] = $var; - // fix bug #7351: setting custom config variable in a channel fails - $this->_channelConfigInfo[] = $name; + if ($this->getSSL()) { + return 443; } - return true; + return 80; } /** - * Encodes/scrambles configuration data before writing to files. - * Currently, 'password' values will be base64-encoded as to avoid - * that people spot cleartext passwords by accident. - * - * @param array (reference) array to encode values in - * @return bool TRUE on success - * @access private + * @return bool Determines whether secure sockets layer (SSL) is used to connect to this channel */ - function _encodeOutput(&$data) + function getSSL($mirror = false) { - foreach ($data as $key => $value) { - if ($key == '__channels') { - foreach ($data['__channels'] as $channel => $blah) { - $this->_encodeOutput($data['__channels'][$channel]); + if ($mirror) { + if ($mir = $this->getMirror($mirror)) { + if (isset($mir['attribs']['ssl'])) { + return true; } - } - if (!isset($this->configuration_info[$key])) { - continue; + return false; } - $type = $this->configuration_info[$key]['type']; - switch ($type) { - // we base64-encode passwords so they are at least - // not shown in plain by accident - case 'password': { - $data[$key] = base64_encode($data[$key]); - break; - } - case 'mask': { - $data[$key] = octdec($data[$key]); - break; - } - } + return false; } - return true; + if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) { + return true; + } + + return false; } /** - * Decodes/unscrambles configuration data after reading from files. - * - * @param array (reference) array to encode values in - * @return bool TRUE on success - * @access private - * - * @see PEAR_Config::_encodeOutput + * @return string|false */ - function _decodeInput(&$data) + function getSummary() { - if (!is_array($data)) { - return true; - } - - foreach ($data as $key => $value) { - if ($key == '__channels') { - foreach ($data['__channels'] as $channel => $blah) { - $this->_decodeInput($data['__channels'][$channel]); - } - } - - if (!isset($this->configuration_info[$key])) { - continue; - } - - $type = $this->configuration_info[$key]['type']; - switch ($type) { - case 'password': { - $data[$key] = base64_decode($data[$key]); - break; - } - case 'mask': { - $data[$key] = decoct($data[$key]); - break; - } - } + if (isset($this->_channelInfo['summary'])) { + return $this->_channelInfo['summary']; } - return true; + return false; } /** - * Retrieve the default channel. - * - * On startup, channels are not initialized, so if the default channel is not - * pear.php.net, then initialize the config. - * @param string registry layer - * @return string|false + * @param string protocol type + * @param string Mirror name + * @return array|false */ - function getDefaultChannel($layer = null) + function getFunctions($protocol, $mirror = false) { - $ret = false; - if ($layer === null) { - foreach ($this->layers as $layer) { - if (isset($this->configuration[$layer]['default_channel'])) { - $ret = $this->configuration[$layer]['default_channel']; - break; + if ($this->getName() == '__uri') { + return false; + } + + $function = $protocol == 'rest' ? 'baseurl' : 'function'; + if ($mirror) { + if ($mir = $this->getMirror($mirror)) { + if (isset($mir[$protocol][$function])) { + return $mir[$protocol][$function]; } } - } elseif (isset($this->configuration[$layer]['default_channel'])) { - $ret = $this->configuration[$layer]['default_channel']; - } - if ($ret == 'pear.php.net' && defined('PEAR_RUNTYPE') && PEAR_RUNTYPE == 'pecl') { - $ret = 'pecl.php.net'; + return false; } - if ($ret) { - if ($ret != 'pear.php.net') { - $this->_lazyChannelSetup(); - } - - return $ret; + if (isset($this->_channelInfo['servers']['primary'][$protocol][$function])) { + return $this->_channelInfo['servers']['primary'][$protocol][$function]; } - return PEAR_CONFIG_DEFAULT_CHANNEL; + return false; } /** - * Returns a configuration value, prioritizing layers as per the - * layers property. - * - * @param string config key - * @return mixed the config value, or NULL if not found - * @access public + * @param string Protocol type + * @param string Function name (null to return the + * first protocol of the type requested) + * @param string Mirror name, if any + * @return array */ - function get($key, $layer = null, $channel = false) - { - if (!isset($this->configuration_info[$key])) { - return null; - } - - if ($key == '__channels') { - return null; - } - - if ($key == 'default_channel') { - return $this->getDefaultChannel($layer); + function getFunction($type, $name = null, $mirror = false) + { + $protocols = $this->getFunctions($type, $mirror); + if (!$protocols) { + return false; } - if (!$channel) { - $channel = $this->getDefaultChannel(); - } elseif ($channel != 'pear.php.net') { - $this->_lazyChannelSetup(); - } - $channel = strtolower($channel); + foreach ($protocols as $protocol) { + if ($name === null) { + return $protocol; + } - $test = (in_array($key, $this->_channelConfigInfo)) ? - $this->_getChannelValue($key, $layer, $channel) : - null; - if ($test !== null) { - if ($this->_installRoot) { - if (in_array($this->getGroup($key), - array('File Locations', 'File Locations (Advanced)')) && - $this->getType($key) == 'directory') { - return $this->_prependPath($test, $this->_installRoot); - } + if ($protocol['_content'] != $name) { + continue; } - return $test; + + return $protocol; } - if ($layer === null) { - foreach ($this->layers as $layer) { - if (isset($this->configuration[$layer][$key])) { - $test = $this->configuration[$layer][$key]; - if ($this->_installRoot) { - if (in_array($this->getGroup($key), - array('File Locations', 'File Locations (Advanced)')) && - $this->getType($key) == 'directory') { - return $this->_prependPath($test, $this->_installRoot); - } - } + return false; + } - if ($key == 'preferred_mirror') { - $reg = &$this->getRegistry(); - if (is_object($reg)) { - $chan = &$reg->getChannel($channel); - if (PEAR::isError($chan)) { - return $channel; - } + /** + * @param string protocol type + * @param string protocol name + * @param string version + * @param string mirror name + * @return boolean + */ + function supports($type, $name = null, $mirror = false, $version = '1.0') + { + $protocols = $this->getFunctions($type, $mirror); + if (!$protocols) { + return false; + } - if (!$chan->getMirror($test) && $chan->getName() != $test) { - return $channel; // mirror does not exist - } - } - } - return $test; - } - } - } elseif (isset($this->configuration[$layer][$key])) { - $test = $this->configuration[$layer][$key]; - if ($this->_installRoot) { - if (in_array($this->getGroup($key), - array('File Locations', 'File Locations (Advanced)')) && - $this->getType($key) == 'directory') { - return $this->_prependPath($test, $this->_installRoot); - } + foreach ($protocols as $protocol) { + if ($protocol['attribs']['version'] != $version) { + continue; } - if ($key == 'preferred_mirror') { - $reg = &$this->getRegistry(); - if (is_object($reg)) { - $chan = &$reg->getChannel($channel); - if (PEAR::isError($chan)) { - return $channel; - } + if ($name === null) { + return true; + } - if (!$chan->getMirror($test) && $chan->getName() != $test) { - return $channel; // mirror does not exist - } - } + if ($protocol['_content'] != $name) { + continue; } - return $test; + return true; } - return null; + return false; } /** - * Returns a channel-specific configuration value, prioritizing layers as per the - * layers property. - * - * @param string config key - * @return mixed the config value, or NULL if not found - * @access private + * Determines whether a channel supports Representational State Transfer (REST) protocols + * for retrieving channel information + * @param string + * @return bool */ - function _getChannelValue($key, $layer, $channel) + function supportsREST($mirror = false) { - if ($key == '__channels' || $channel == 'pear.php.net') { - return null; + if ($mirror == $this->_channelInfo['name']) { + $mirror = false; } - $ret = null; - if ($layer === null) { - foreach ($this->layers as $ilayer) { - if (isset($this->configuration[$ilayer]['__channels'][$channel][$key])) { - $ret = $this->configuration[$ilayer]['__channels'][$channel][$key]; - break; - } + if ($mirror) { + if ($mir = $this->getMirror($mirror)) { + return isset($mir['rest']); } - } elseif (isset($this->configuration[$layer]['__channels'][$channel][$key])) { - $ret = $this->configuration[$layer]['__channels'][$channel][$key]; - } - if ($key != 'preferred_mirror') { - return $ret; + return false; } + return isset($this->_channelInfo['servers']['primary']['rest']); + } - if ($ret !== null) { - $reg = &$this->getRegistry($layer); - if (is_object($reg)) { - $chan = &$reg->getChannel($channel); - if (PEAR::isError($chan)) { - return $channel; - } + /** + * Get the URL to access a base resource. + * + * Hyperlinks in the returned xml will be used to retrieve the proper information + * needed. This allows extreme extensibility and flexibility in implementation + * @param string Resource Type to retrieve + */ + function getBaseURL($resourceType, $mirror = false) + { + if ($mirror == $this->_channelInfo['name']) { + $mirror = false; + } - if (!$chan->getMirror($ret) && $chan->getName() != $ret) { - return $channel; // mirror does not exist - } + if ($mirror) { + $mir = $this->getMirror($mirror); + if (!$mir) { + return false; } - return $ret; + $rest = $mir['rest']; + } else { + $rest = $this->_channelInfo['servers']['primary']['rest']; } - if ($channel != $this->getDefaultChannel($layer)) { - return $channel; // we must use the channel name as the preferred mirror - // if the user has not chosen an alternate + if (!isset($rest['baseurl'][0])) { + $rest['baseurl'] = array($rest['baseurl']); } - return $this->getDefaultChannel($layer); + foreach ($rest['baseurl'] as $baseurl) { + if (strtolower($baseurl['attribs']['type']) == strtolower($resourceType)) { + return $baseurl['_content']; + } + } + + return false; } /** - * Set a config value in a specific layer (defaults to 'user'). - * Enforces the types defined in the configuration_info array. An - * integer config variable will be cast to int, and a set config - * variable will be validated against its legal values. - * - * @param string config key - * @param string config value - * @param string (optional) config layer - * @param string channel to set this value for, or null for global value - * @return bool TRUE on success, FALSE on failure + * Since REST does not implement RPC, provide this as a logical wrapper around + * resetFunctions for REST + * @param string|false mirror name, if any */ - function set($key, $value, $layer = 'user', $channel = false) + function resetREST($mirror = false) { - if ($key == '__channels') { - return false; - } - - if (!isset($this->configuration[$layer])) { - return false; - } + return $this->resetFunctions('rest', $mirror); + } - if ($key == 'default_channel') { - // can only set this value globally - $channel = 'pear.php.net'; - if ($value != 'pear.php.net') { - $this->_lazyChannelSetup($layer); - } - } + /** + * Empty all protocol definitions + * @param string protocol type + * @param string|false mirror name, if any + */ + function resetFunctions($type, $mirror = false) + { + if ($mirror) { + if (isset($this->_channelInfo['servers']['mirror'])) { + $mirrors = $this->_channelInfo['servers']['mirror']; + if (!isset($mirrors[0])) { + $mirrors = array($mirrors); + } - if ($key == 'preferred_mirror') { - if ($channel == '__uri') { - return false; // can't set the __uri pseudo-channel's mirror - } + foreach ($mirrors as $i => $mir) { + if ($mir['attribs']['host'] == $mirror) { + if (isset($this->_channelInfo['servers']['mirror'][$i][$type])) { + unset($this->_channelInfo['servers']['mirror'][$i][$type]); + } - $reg = &$this->getRegistry($layer); - if (is_object($reg)) { - $chan = &$reg->getChannel($channel ? $channel : 'pear.php.net'); - if (PEAR::isError($chan)) { - return false; + return true; + } } - if (!$chan->getMirror($value) && $chan->getName() != $value) { - return false; // mirror does not exist - } + return false; } - } - if (!isset($this->configuration_info[$key])) { return false; } - extract($this->configuration_info[$key]); - switch ($type) { - case 'integer': - $value = (int)$value; - break; - case 'set': { - // If a valid_set is specified, require the value to - // be in the set. If there is no valid_set, accept - // any value. - if ($valid_set) { - reset($valid_set); - if ((key($valid_set) === 0 && !in_array($value, $valid_set)) || - (key($valid_set) !== 0 && empty($valid_set[$value]))) - { - return false; - } - } - break; - } + if (isset($this->_channelInfo['servers']['primary'][$type])) { + unset($this->_channelInfo['servers']['primary'][$type]); } - if (!$channel) { - $channel = $this->get('default_channel', null, 'pear.php.net'); - } + return true; + } - if (!in_array($channel, $this->_channels)) { - $this->_lazyChannelSetup($layer); - $reg = &$this->getRegistry($layer); - if ($reg) { - $channel = $reg->channelName($channel); - } + /** + * Set a channel's protocols to the protocols supported by pearweb + */ + function setDefaultPEARProtocols($version = '1.0', $mirror = false) + { + switch ($version) { + case '1.0' : + $this->resetREST($mirror); - if (!in_array($channel, $this->_channels)) { + if (!isset($this->_channelInfo['servers'])) { + $this->_channelInfo['servers'] = array('primary' => + array('rest' => array())); + } elseif (!isset($this->_channelInfo['servers']['primary'])) { + $this->_channelInfo['servers']['primary'] = array('rest' => array()); + } + + return true; + break; + default : return false; - } + break; } + } - if ($channel != 'pear.php.net') { - if (in_array($key, $this->_channelConfigInfo)) { - $this->configuration[$layer]['__channels'][$channel][$key] = $value; - return true; + /** + * @return array + */ + function getMirrors() + { + if (isset($this->_channelInfo['servers']['mirror'])) { + $mirrors = $this->_channelInfo['servers']['mirror']; + if (!isset($mirrors[0])) { + $mirrors = array($mirrors); } - return false; + return $mirrors; } - if ($key == 'default_channel') { - if (!isset($reg)) { - $reg = &$this->getRegistry($layer); - if (!$reg) { - $reg = &$this->getRegistry(); - } - } + return array(); + } - if ($reg) { - $value = $reg->channelName($value); + /** + * Get the unserialized XML representing a mirror + * @return array|false + */ + function getMirror($server) + { + foreach ($this->getMirrors() as $mirror) { + if ($mirror['attribs']['host'] == $server) { + return $mirror; } + } - if (!$value) { + return false; + } + + /** + * @param string + * @return string|false + * @error PEAR_CHANNELFILE_ERROR_NO_NAME + * @error PEAR_CHANNELFILE_ERROR_INVALID_NAME + */ + function setName($name) + { + return $this->setServer($name); + } + + /** + * Set the socket number (port) that is used to connect to this channel + * @param integer + * @param string|false name of the mirror server, or false for the primary + */ + function setPort($port, $mirror = false) + { + if ($mirror) { + if (!isset($this->_channelInfo['servers']['mirror'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, + array('mirror' => $mirror)); return false; } - } - $this->configuration[$layer][$key] = $value; - if ($key == 'php_dir' && !$this->_noRegistry) { - if (!isset($this->_registry[$layer]) || - $value != $this->_registry[$layer]->install_dir) { - $this->_registry[$layer] = &new PEAR_Registry($value); - $this->_regInitialized[$layer] = false; - $this->_registry[$layer]->setConfig($this, false); + if (isset($this->_channelInfo['servers']['mirror'][0])) { + foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { + if ($mirror == $mir['attribs']['host']) { + $this->_channelInfo['servers']['mirror'][$i]['attribs']['port'] = $port; + return true; + } + } + + return false; + } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { + $this->_channelInfo['servers']['mirror']['attribs']['port'] = $port; + $this->_isValid = false; + return true; } } + $this->_channelInfo['servers']['primary']['attribs']['port'] = $port; + $this->_isValid = false; return true; } - function _lazyChannelSetup($uselayer = false) + /** + * Set the socket number (port) that is used to connect to this channel + * @param bool Determines whether to turn on SSL support or turn it off + * @param string|false name of the mirror server, or false for the primary + */ + function setSSL($ssl = true, $mirror = false) { - if ($this->_noRegistry) { - return; - } - - $merge = false; - foreach ($this->_registry as $layer => $p) { - if ($uselayer && $uselayer != $layer) { - continue; + if ($mirror) { + if (!isset($this->_channelInfo['servers']['mirror'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, + array('mirror' => $mirror)); + return false; } - if (!$this->_regInitialized[$layer]) { - if ($layer == 'default' && isset($this->_registry['user']) || - isset($this->_registry['system'])) { - // only use the default registry if there are no alternatives - continue; + if (isset($this->_channelInfo['servers']['mirror'][0])) { + foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { + if ($mirror == $mir['attribs']['host']) { + if (!$ssl) { + if (isset($this->_channelInfo['servers']['mirror'][$i] + ['attribs']['ssl'])) { + unset($this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl']); + } + } else { + $this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl'] = 'yes'; + } + + return true; + } } - if (!is_object($this->_registry[$layer])) { - if ($phpdir = $this->get('php_dir', $layer, 'pear.php.net')) { - $this->_registry[$layer] = &new PEAR_Registry($phpdir); - $this->_registry[$layer]->setConfig($this, false); - $this->_regInitialized[$layer] = false; - } else { - unset($this->_registry[$layer]); - return; + return false; + } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { + if (!$ssl) { + if (isset($this->_channelInfo['servers']['mirror']['attribs']['ssl'])) { + unset($this->_channelInfo['servers']['mirror']['attribs']['ssl']); } + } else { + $this->_channelInfo['servers']['mirror']['attribs']['ssl'] = 'yes'; } - $this->setChannels($this->_registry[$layer]->listChannels(), $merge); - $this->_regInitialized[$layer] = true; - $merge = true; + $this->_isValid = false; + return true; + } + } + + if ($ssl) { + $this->_channelInfo['servers']['primary']['attribs']['ssl'] = 'yes'; + } else { + if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) { + unset($this->_channelInfo['servers']['primary']['attribs']['ssl']); } } + + $this->_isValid = false; + return true; } /** - * Set the list of channels. - * - * This should be set via a call to {@link PEAR_Registry::listChannels()} - * @param array - * @param bool - * @return bool success of operation + * @param string + * @return string|false + * @error PEAR_CHANNELFILE_ERROR_NO_SERVER + * @error PEAR_CHANNELFILE_ERROR_INVALID_SERVER */ - function setChannels($channels, $merge = false) + function setServer($server, $mirror = false) { - if (!is_array($channels)) { + if (empty($server)) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SERVER); + return false; + } elseif (!$this->validChannelServer($server)) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, + array('tag' => 'name', 'name' => $server)); return false; } - if ($merge) { - $this->_channels = array_merge($this->_channels, $channels); - } else { - $this->_channels = $channels; - } - - foreach ($channels as $channel) { - $channel = strtolower($channel); - if ($channel == 'pear.php.net') { - continue; + if ($mirror) { + $found = false; + foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { + if ($mirror == $mir['attribs']['host']) { + $found = true; + break; + } } - foreach ($this->layers as $layer) { - if (!isset($this->configuration[$layer]['__channels'])) { - $this->configuration[$layer]['__channels'] = array(); - } - if (!isset($this->configuration[$layer]['__channels'][$channel]) - || !is_array($this->configuration[$layer]['__channels'][$channel])) { - $this->configuration[$layer]['__channels'][$channel] = array(); - } + if (!$found) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, + array('mirror' => $mirror)); + return false; } + + $this->_channelInfo['mirror'][$i]['attribs']['host'] = $server; + return true; } + $this->_channelInfo['name'] = $server; return true; } /** - * Get the type of a config value. - * - * @param string config key - * - * @return string type, one of "string", "integer", "file", - * "directory", "set" or "password". - * - * @access public - * + * @param string + * @return boolean success + * @error PEAR_CHANNELFILE_ERROR_NO_SUMMARY + * @warning PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY */ - function getType($key) + function setSummary($summary) { - if (isset($this->configuration_info[$key])) { - return $this->configuration_info[$key]['type']; + if (empty($summary)) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY); + return false; + } elseif (strpos(trim($summary), "\n") !== false) { + $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY, + array('summary' => $summary)); } - return false; + + $this->_channelInfo['summary'] = $summary; + return true; } /** - * Get the documentation for a config value. - * - * @param string config key - * @return string documentation string - * - * @access public - * + * @param string + * @param boolean determines whether the alias is in channel.xml or local + * @return boolean success */ - function getDocs($key) + function setAlias($alias, $local = false) { - if (isset($this->configuration_info[$key])) { - return $this->configuration_info[$key]['doc']; + if (!$this->validChannelServer($alias)) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, + array('tag' => 'suggestedalias', 'name' => $alias)); + return false; } - return false; - } - - /** - * Get the short documentation for a config value. - * - * @param string config key - * @return string short documentation string - * - * @access public - * - */ - function getPrompt($key) - { - if (isset($this->configuration_info[$key])) { - return $this->configuration_info[$key]['prompt']; + if ($local) { + $this->_channelInfo['localalias'] = $alias; + } else { + $this->_channelInfo['suggestedalias'] = $alias; } - return false; + return true; } /** - * Get the parameter group for a config key. - * - * @param string config key - * @return string parameter group - * - * @access public - * + * @return string */ - function getGroup($key) + function getAlias() { - if (isset($this->configuration_info[$key])) { - return $this->configuration_info[$key]['group']; + if (isset($this->_channelInfo['localalias'])) { + return $this->_channelInfo['localalias']; } - - return false; + if (isset($this->_channelInfo['suggestedalias'])) { + return $this->_channelInfo['suggestedalias']; + } + if (isset($this->_channelInfo['name'])) { + return $this->_channelInfo['name']; + } + return ''; } /** - * Get the list of parameter groups. - * - * @return array list of parameter groups - * - * @access public - * + * Set the package validation object if it differs from PEAR's default + * The class must be includeable via changing _ in the classname to path separator, + * but no checking of this is made. + * @param string|false pass in false to reset to the default packagename regex + * @return boolean success */ - function getGroups() + function setValidationPackage($validateclass, $version) { - $tmp = array(); - foreach ($this->configuration_info as $key => $info) { - $tmp[$info['group']] = 1; + if (empty($validateclass)) { + unset($this->_channelInfo['validatepackage']); } - - return array_keys($tmp); + $this->_channelInfo['validatepackage'] = array('_content' => $validateclass); + $this->_channelInfo['validatepackage']['attribs'] = array('version' => $version); } /** - * Get the list of the parameters in a group. - * - * @param string $group parameter group - * @return array list of parameters in $group - * - * @access public - * + * Add a protocol to the provides section + * @param string protocol type + * @param string protocol version + * @param string protocol name, if any + * @param string mirror name, if this is a mirror's protocol + * @return bool */ - function getGroupKeys($group) + function addFunction($type, $version, $name = '', $mirror = false) { - $keys = array(); - foreach ($this->configuration_info as $key => $info) { - if ($info['group'] == $group) { - $keys[] = $key; - } + if ($mirror) { + return $this->addMirrorFunction($mirror, $type, $version, $name); } - return $keys; - } - - /** - * Get the list of allowed set values for a config value. Returns - * NULL for config values that are not sets. - * - * @param string config key - * @return array enumerated array of set values, or NULL if the - * config key is unknown or not a set - * - * @access public - * - */ - function getSetValues($key) - { - if (isset($this->configuration_info[$key]) && - isset($this->configuration_info[$key]['type']) && - $this->configuration_info[$key]['type'] == 'set') - { - $valid_set = $this->configuration_info[$key]['valid_set']; - reset($valid_set); - if (key($valid_set) === 0) { - return $valid_set; + $set = array('attribs' => array('version' => $version), '_content' => $name); + if (!isset($this->_channelInfo['servers']['primary'][$type]['function'])) { + if (!isset($this->_channelInfo['servers'])) { + $this->_channelInfo['servers'] = array('primary' => + array($type => array())); + } elseif (!isset($this->_channelInfo['servers']['primary'])) { + $this->_channelInfo['servers']['primary'] = array($type => array()); } - return array_keys($valid_set); + $this->_channelInfo['servers']['primary'][$type]['function'] = $set; + $this->_isValid = false; + return true; + } elseif (!isset($this->_channelInfo['servers']['primary'][$type]['function'][0])) { + $this->_channelInfo['servers']['primary'][$type]['function'] = array( + $this->_channelInfo['servers']['primary'][$type]['function']); } - return null; + $this->_channelInfo['servers']['primary'][$type]['function'][] = $set; + return true; } - /** - * Get all the current config keys. - * - * @return array simple array of config keys - * - * @access public + * Add a protocol to a mirror's provides section + * @param string mirror name (server) + * @param string protocol type + * @param string protocol version + * @param string protocol name, if any */ - function getKeys() + function addMirrorFunction($mirror, $type, $version, $name = '') { - $keys = array(); - foreach ($this->layers as $layer) { - $test = $this->configuration[$layer]; - if (isset($test['__channels'])) { - foreach ($test['__channels'] as $channel => $configs) { - $keys = array_merge($keys, $configs); - } - } - - unset($test['__channels']); - $keys = array_merge($keys, $test); - + if (!isset($this->_channelInfo['servers']['mirror'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, + array('mirror' => $mirror)); + return false; } - return array_keys($keys); - } - /** - * Remove the a config key from a specific config layer. - * - * @param string config key - * @param string (optional) config layer - * @return bool TRUE on success, FALSE on failure - * - * @access public - */ - function remove($key, $layer = 'user') - { - $channel = $this->getDefaultChannel(); - if ($channel !== 'pear.php.net') { - if (isset($this->configuration[$layer]['__channels'][$channel][$key])) { - unset($this->configuration[$layer]['__channels'][$channel][$key]); - return true; + $setmirror = false; + if (isset($this->_channelInfo['servers']['mirror'][0])) { + foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { + if ($mirror == $mir['attribs']['host']) { + $setmirror = &$this->_channelInfo['servers']['mirror'][$i]; + break; + } + } + } else { + if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { + $setmirror = &$this->_channelInfo['servers']['mirror']; } } - if (isset($this->configuration[$layer][$key])) { - unset($this->configuration[$layer][$key]); - return true; + if (!$setmirror) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, + array('mirror' => $mirror)); + return false; } - return false; - } - - /** - * Temporarily remove an entire config layer. USE WITH CARE! - * - * @param string config key - * @param string (optional) config layer - * @return bool TRUE on success, FALSE on failure - * - * @access public - */ - function removeLayer($layer) - { - if (isset($this->configuration[$layer])) { - $this->configuration[$layer] = array(); + $set = array('attribs' => array('version' => $version), '_content' => $name); + if (!isset($setmirror[$type]['function'])) { + $setmirror[$type]['function'] = $set; + $this->_isValid = false; return true; + } elseif (!isset($setmirror[$type]['function'][0])) { + $setmirror[$type]['function'] = array($setmirror[$type]['function']); } - return false; + $setmirror[$type]['function'][] = $set; + $this->_isValid = false; + return true; } /** - * Stores configuration data in a layer. - * - * @param string config layer to store - * @return bool TRUE on success, or PEAR error on failure - * - * @access public + * @param string Resource Type this url links to + * @param string URL + * @param string|false mirror name, if this is not a primary server REST base URL */ - function store($layer = 'user', $data = null) + function setBaseURL($resourceType, $url, $mirror = false) { - return $this->writeConfigFile(null, $layer, $data); - } + if ($mirror) { + if (!isset($this->_channelInfo['servers']['mirror'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, + array('mirror' => $mirror)); + return false; + } - /** - * Tells what config layer that gets to define a key. - * - * @param string config key - * @param boolean return the defining channel - * - * @return string|array the config layer, or an empty string if not found. - * - * if $returnchannel, the return is an array array('layer' => layername, - * 'channel' => channelname), or an empty string if not found - * - * @access public - */ - function definedBy($key, $returnchannel = false) - { - foreach ($this->layers as $layer) { - $channel = $this->getDefaultChannel(); - if ($channel !== 'pear.php.net') { - if (isset($this->configuration[$layer]['__channels'][$channel][$key])) { - if ($returnchannel) { - return array('layer' => $layer, 'channel' => $channel); + $setmirror = false; + if (isset($this->_channelInfo['servers']['mirror'][0])) { + foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { + if ($mirror == $mir['attribs']['host']) { + $setmirror = &$this->_channelInfo['servers']['mirror'][$i]; + break; } - return $layer; } - } - - if (isset($this->configuration[$layer][$key])) { - if ($returnchannel) { - return array('layer' => $layer, 'channel' => 'pear.php.net'); + } else { + if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { + $setmirror = &$this->_channelInfo['servers']['mirror']; } - return $layer; } + } else { + $setmirror = &$this->_channelInfo['servers']['primary']; } - return ''; - } + $set = array('attribs' => array('type' => $resourceType), '_content' => $url); + if (!isset($setmirror['rest'])) { + $setmirror['rest'] = array(); + } - /** - * Tells whether a given key exists as a config value. - * - * @param string config key - * @return bool whether exists in this object - * - * @access public - */ - function isDefined($key) - { - foreach ($this->layers as $layer) { - if (isset($this->configuration[$layer][$key])) { + if (!isset($setmirror['rest']['baseurl'])) { + $setmirror['rest']['baseurl'] = $set; + $this->_isValid = false; + return true; + } elseif (!isset($setmirror['rest']['baseurl'][0])) { + $setmirror['rest']['baseurl'] = array($setmirror['rest']['baseurl']); + } + + foreach ($setmirror['rest']['baseurl'] as $i => $url) { + if ($url['attribs']['type'] == $resourceType) { + $this->_isValid = false; + $setmirror['rest']['baseurl'][$i] = $set; return true; } } - return false; + $setmirror['rest']['baseurl'][] = $set; + $this->_isValid = false; + return true; } /** - * Tells whether a given config layer exists. - * - * @param string config layer - * @return bool whether exists in this object - * - * @access public + * @param string mirror server + * @param int mirror http port + * @return boolean */ - function isDefinedLayer($layer) + function addMirror($server, $port = null) { - return isset($this->configuration[$layer]); - } + if ($this->_channelInfo['name'] == '__uri') { + return false; // the __uri channel cannot have mirrors by definition + } - /** - * Returns the layers defined (except the 'default' one) - * - * @return array of the defined layers - */ - function getLayers() - { - $cf = $this->configuration; - unset($cf['default']); - return array_keys($cf); - } + $set = array('attribs' => array('host' => $server)); + if (is_numeric($port)) { + $set['attribs']['port'] = $port; + } - function apiVersion() - { - return '1.1'; - } + if (!isset($this->_channelInfo['servers']['mirror'])) { + $this->_channelInfo['servers']['mirror'] = $set; + return true; + } - /** - * @return PEAR_Registry - */ - function &getRegistry($use = null) - { - $layer = $use === null ? 'user' : $use; - if (isset($this->_registry[$layer])) { - return $this->_registry[$layer]; - } elseif ($use === null && isset($this->_registry['system'])) { - return $this->_registry['system']; - } elseif ($use === null && isset($this->_registry['default'])) { - return $this->_registry['default']; - } elseif ($use) { - $a = false; - return $a; + if (!isset($this->_channelInfo['servers']['mirror'][0])) { + $this->_channelInfo['servers']['mirror'] = + array($this->_channelInfo['servers']['mirror']); } - // only go here if null was passed in - echo "CRITICAL ERROR: Registry could not be initialized from any value"; - exit(1); + $this->_channelInfo['servers']['mirror'][] = $set; + return true; } /** - * This is to allow customization like the use of installroot - * @param PEAR_Registry - * @return bool + * Retrieve the name of the validation package for this channel + * @return string|false */ - function setRegistry(&$reg, $layer = 'user') + function getValidationPackage() { - if ($this->_noRegistry) { - return false; - } - - if (!in_array($layer, array('user', 'system'))) { + if (!$this->_isValid && !$this->validate()) { return false; } - $this->_registry[$layer] = &$reg; - if (is_object($reg)) { - $this->_registry[$layer]->setConfig($this, false); + if (!isset($this->_channelInfo['validatepackage'])) { + return array('attribs' => array('version' => 'default'), + '_content' => 'PEAR_Validate'); } - return true; - } - - function noRegistry() - { - $this->_noRegistry = true; + return $this->_channelInfo['validatepackage']; } /** - * @return PEAR_REST + * Retrieve the object that can be used for custom validation + * @param string|false the name of the package to validate. If the package is + * the channel validation package, PEAR_Validate is returned + * @return PEAR_Validate|false false is returned if the validation package + * cannot be located */ - function &getREST($version, $options = array()) + function &getValidationObject($package = false) { - $version = str_replace('.', '', $version); - if (!class_exists($class = 'PEAR_REST_' . $version)) { - require_once 'PEAR/REST/' . $version . '.php'; + if (!class_exists('PEAR_Validate')) { + require_once 'PEAR/Validate.php'; } - $remote = &new $class($this, $options); - return $remote; - } + if (!$this->_isValid) { + if (!$this->validate()) { + $a = false; + return $a; + } + } - /** - * The ftp server is set in {@link readFTPConfigFile()}. It exists only if a - * remote configuration file has been specified - * @return PEAR_FTP|false - */ - function &getFTP() - { - if (isset($this->_ftp)) { - return $this->_ftp; + if (isset($this->_channelInfo['validatepackage'])) { + if ($package == $this->_channelInfo['validatepackage']) { + // channel validation packages are always validated by PEAR_Validate + $val = &new PEAR_Validate; + return $val; + } + + if (!class_exists(str_replace('.', '_', + $this->_channelInfo['validatepackage']['_content']))) { + if ($this->isIncludeable(str_replace('_', '/', + $this->_channelInfo['validatepackage']['_content']) . '.php')) { + include_once str_replace('_', '/', + $this->_channelInfo['validatepackage']['_content']) . '.php'; + $vclass = str_replace('.', '_', + $this->_channelInfo['validatepackage']['_content']); + $val = &new $vclass; + } else { + $a = false; + return $a; + } + } else { + $vclass = str_replace('.', '_', + $this->_channelInfo['validatepackage']['_content']); + $val = &new $vclass; + } + } else { + $val = &new PEAR_Validate; } - $a = false; - return $a; + return $val; } - function _prependPath($path, $prepend) + function isIncludeable($path) { - if (strlen($prepend) > 0) { - if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) { - if (preg_match('/^[a-z]:/i', $prepend)) { - $prepend = substr($prepend, 2); - } elseif ($prepend{0} != '\\') { - $prepend = "\\$prepend"; - } - $path = substr($path, 0, 2) . $prepend . substr($path, 2); - } else { - $path = $prepend . $path; + $possibilities = explode(PATH_SEPARATOR, ini_get('include_path')); + foreach ($possibilities as $dir) { + if (file_exists($dir . DIRECTORY_SEPARATOR . $path) + && is_readable($dir . DIRECTORY_SEPARATOR . $path)) { + return true; } } - return $path; + + return false; } /** - * @param string|false installation directory to prepend to all _dir variables, or false to - * disable + * This function is used by the channel updater and retrieves a value set by + * the registry, or the current time if it has not been set + * @return string */ - function setInstallRoot($root) + function lastModified() { - if (substr($root, -1) == DIRECTORY_SEPARATOR) { - $root = substr($root, 0, -1); - } - $old = $this->_installRoot; - $this->_installRoot = $root; - if (($old != $root) && !$this->_noRegistry) { - foreach (array_keys($this->_registry) as $layer) { - if ($layer == 'ftp' || !isset($this->_registry[$layer])) { - continue; - } - $this->_registry[$layer] = - &new PEAR_Registry($this->get('php_dir', $layer, 'pear.php.net')); - $this->_registry[$layer]->setConfig($this, false); - $this->_regInitialized[$layer] = false; - } + if (isset($this->_channelInfo['_lastmodified'])) { + return $this->_channelInfo['_lastmodified']; } + + return time(); } -} -PEAR-1.8.0/PEAR/DependencyDB.php100664 764 764 57540 100664 11064 + * @author Stig Bakken * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: DependencyDB.php,v 1.44 2009/03/21 15:15:26 dufuz Exp $ + * @version CVS: $Id: Command.php 286494 2009-07-29 06:57:11Z dufuz $ * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 + * @since File available since Release 0.1 */ /** * Needed for error handling */ require_once 'PEAR.php'; -require_once 'PEAR/Config.php'; +require_once 'PEAR/Frontend.php'; +require_once 'PEAR/XMLParser.php'; -$GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'] = array(); /** - * Track dependency relationships between installed packages + * List of commands and what classes they are implemented in. + * @var array command => implementing class + */ +$GLOBALS['_PEAR_Command_commandlist'] = array(); + +/** + * List of commands and their descriptions + * @var array command => description + */ +$GLOBALS['_PEAR_Command_commanddesc'] = array(); + +/** + * List of shortcuts to common commands. + * @var array shortcut => command + */ +$GLOBALS['_PEAR_Command_shortcuts'] = array(); + +/** + * Array of command objects + * @var array class => object + */ +$GLOBALS['_PEAR_Command_objects'] = array(); + +/** + * PEAR command class, a simple factory class for administrative + * commands. + * + * How to implement command classes: + * + * - The class must be called PEAR_Command_Nnn, installed in the + * "PEAR/Common" subdir, with a method called getCommands() that + * returns an array of the commands implemented by the class (see + * PEAR/Command/Install.php for an example). + * + * - The class must implement a run() function that is called with three + * params: + * + * (string) command name + * (array) assoc array with options, freely defined by each + * command, for example: + * array('force' => true) + * (array) list of the other parameters + * + * The run() function returns a PEAR_CommandResponse object. Use + * these methods to get information: + * + * int getStatus() Returns PEAR_COMMAND_(SUCCESS|FAILURE|PARTIAL) + * *_PARTIAL means that you need to issue at least + * one more command to complete the operation + * (used for example for validation steps). + * + * string getMessage() Returns a message for the user. Remember, + * no HTML or other interface-specific markup. + * + * If something unexpected happens, run() returns a PEAR error. + * + * - DON'T OUTPUT ANYTHING! Return text for output instead. + * + * - DON'T USE HTML! The text you return will be used from both Gtk, + * web and command-line interfaces, so for now, keep everything to + * plain text. + * + * - DON'T USE EXIT OR DIE! Always use pear errors. From static + * classes do PEAR::raiseError(), from other classes do + * $this->raiseError(). * @category pear * @package PEAR + * @author Stig Bakken * @author Greg Beaver - * @author Tomas V.V.Cox * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 + * @since Class available since Release 0.1 */ -class PEAR_DependencyDB +class PEAR_Command { - // {{{ properties - - /** - * This is initialized by {@link setConfig()} - * @var PEAR_Config - * @access private - */ - var $_config; - /** - * This is initialized by {@link setConfig()} - * @var PEAR_Registry - * @access private - */ - var $_registry; - /** - * Filename of the dependency DB (usually .depdb) - * @var string - * @access private - */ - var $_depdb = false; - /** - * File name of the lockfile (usually .depdblock) - * @var string - * @access private - */ - var $_lockfile = false; - /** - * Open file resource for locking the lockfile - * @var resource|false - * @access private - */ - var $_lockFp = false; - /** - * API version of this class, used to validate a file on-disk - * @var string - * @access private - */ - var $_version = '1.0'; - /** - * Cached dependency database file - * @var array|null - * @access private - */ - var $_cache; - - // }}} - // {{{ & singleton() + // {{{ factory() /** - * Get a raw dependency database. Calls setConfig() and assertDepsDB() - * @param PEAR_Config - * @param string|false full path to the dependency database, or false to use default - * @return PEAR_DependencyDB|PEAR_Error + * Get the right object for executing a command. + * + * @param string $command The name of the command + * @param object $config Instance of PEAR_Config object + * + * @return object the command object or a PEAR error + * + * @access public * @static */ - function &singleton(&$config, $depdb = false) + function &factory($command, &$config) { - $phpdir = $config->get('php_dir', null, 'pear.php.net'); - if (!isset($GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir])) { - $a = new PEAR_DependencyDB; - $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir] = &$a; - $a->setConfig($config, $depdb); - $e = $a->assertDepsDB(); - if (PEAR::isError($e)) { - return $e; - } + if (empty($GLOBALS['_PEAR_Command_commandlist'])) { + PEAR_Command::registerCommands(); } - - return $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir]; - } - - /** - * Set up the registry/location of dependency DB - * @param PEAR_Config|false - * @param string|false full path to the dependency database, or false to use default - */ - function setConfig(&$config, $depdb = false) - { - if (!$config) { - $this->_config = &PEAR_Config::singleton(); - } else { - $this->_config = &$config; + if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) { + $command = $GLOBALS['_PEAR_Command_shortcuts'][$command]; } - - $this->_registry = &$this->_config->getRegistry(); - if (!$depdb) { - $this->_depdb = $this->_config->get('php_dir', null, 'pear.php.net') . - DIRECTORY_SEPARATOR . '.depdb'; - } else { - $this->_depdb = $depdb; + if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) { + $a = PEAR::raiseError("unknown command `$command'"); + return $a; } - - $this->_lockfile = dirname($this->_depdb) . DIRECTORY_SEPARATOR . '.depdblock'; + $class = $GLOBALS['_PEAR_Command_commandlist'][$command]; + if (!class_exists($class)) { + require_once $GLOBALS['_PEAR_Command_objects'][$class]; + } + if (!class_exists($class)) { + $a = PEAR::raiseError("unknown command `$command'"); + return $a; + } + $ui =& PEAR_Command::getFrontendObject(); + $obj = &new $class($ui, $config); + return $obj; } - // }}} - function hasWriteAccess() + // }}} + // {{{ & getObject() + function &getObject($command) { - if (!file_exists($this->_depdb)) { - $dir = $this->_depdb; - while ($dir && $dir != '.') { - $dir = dirname($dir); // cd .. - if ($dir != '.' && file_exists($dir)) { - if (is_writeable($dir)) { - return true; - } - - return false; - } - } - - return false; + $class = $GLOBALS['_PEAR_Command_commandlist'][$command]; + if (!class_exists($class)) { + require_once $GLOBALS['_PEAR_Command_objects'][$class]; } - - return is_writeable($this->_depdb); + if (!class_exists($class)) { + return PEAR::raiseError("unknown command `$command'"); + } + $ui =& PEAR_Command::getFrontendObject(); + $config = &PEAR_Config::singleton(); + $obj = &new $class($ui, $config); + return $obj; } - // {{{ assertDepsDB() + // }}} + // {{{ & getFrontendObject() /** - * Create the dependency database, if it doesn't exist. Error if the database is - * newer than the code reading it. - * @return void|PEAR_Error + * Get instance of frontend object. + * + * @return object|PEAR_Error + * @static */ - function assertDepsDB() + function &getFrontendObject() { - if (!is_file($this->_depdb)) { - $this->rebuildDB(); - } else { - $depdb = $this->_getDepDB(); - // Datatype format has been changed, rebuild the Deps DB - if ($depdb['_version'] < $this->_version) { - $this->rebuildDB(); - } - - if ($depdb['_version']{0} > $this->_version{0}) { - return PEAR::raiseError('Dependency database is version ' . - $depdb['_version'] . ', and we are version ' . - $this->_version . ', cannot continue'); - } - } + $a = &PEAR_Frontend::singleton(); + return $a; } - /** - * Get a list of installed packages that depend on this package - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array - * @return array|false - */ - function getDependentPackages(&$pkg) - { - $data = $this->_getDepDB(); - if (is_object($pkg)) { - $channel = strtolower($pkg->getChannel()); - $package = strtolower($pkg->getPackage()); - } else { - $channel = strtolower($pkg['channel']); - $package = strtolower($pkg['package']); - } - - if (isset($data['packages'][$channel][$package])) { - return $data['packages'][$channel][$package]; - } - - return false; - } + // }}} + // {{{ & setFrontendClass() /** - * Get a list of the actual dependencies of installed packages that depend on - * a package. - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array - * @return array|false + * Load current frontend class. + * + * @param string $uiclass Name of class implementing the frontend + * + * @return object the frontend object, or a PEAR error + * @static */ - function getDependentPackageDependencies(&$pkg) + function &setFrontendClass($uiclass) { - $data = $this->_getDepDB(); - if (is_object($pkg)) { - $channel = strtolower($pkg->getChannel()); - $package = strtolower($pkg->getPackage()); - } else { - $channel = strtolower($pkg['channel']); - $package = strtolower($pkg['package']); - } - - $depend = $this->getDependentPackages($pkg); - if (!$depend) { - return false; - } - - $dependencies = array(); - foreach ($depend as $info) { - $temp = $this->getDependencies($info); - foreach ($temp as $dep) { - if (isset($dep['dep'], $dep['dep']['channel'], $dep['dep']['name']) && - strtolower($dep['dep']['channel']) == $channel && - strtolower($dep['dep']['name']) == $package - ) { - if (!isset($dependencies[$info['channel']])) { - $dependencies[$info['channel']] = array(); - } - - if (!isset($dependencies[$info['channel']][$info['package']])) { - $dependencies[$info['channel']][$info['package']] = array(); - } - $dependencies[$info['channel']][$info['package']][] = $dep; - } - } - } - - return $dependencies; + $a = &PEAR_Frontend::setFrontendClass($uiclass); + return $a; } + // }}} + // {{{ setFrontendType() + /** - * Get a list of dependencies of this installed package - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array - * @return array|false + * Set current frontend. + * + * @param string $uitype Name of the frontend type (for example "CLI") + * + * @return object the frontend object, or a PEAR error + * @static */ - function getDependencies(&$pkg) + function setFrontendType($uitype) { - if (is_object($pkg)) { - $channel = strtolower($pkg->getChannel()); - $package = strtolower($pkg->getPackage()); - } else { - $channel = strtolower($pkg['channel']); - $package = strtolower($pkg['package']); - } - - $data = $this->_getDepDB(); - if (isset($data['dependencies'][$channel][$package])) { - return $data['dependencies'][$channel][$package]; - } - - return false; + $uiclass = 'PEAR_Frontend_' . $uitype; + return PEAR_Command::setFrontendClass($uiclass); } + // }}} + // {{{ registerCommands() + /** - * Determine whether $parent depends on $child, near or deep - * @param array|PEAR_PackageFile_v2|PEAR_PackageFile_v2 - * @param array|PEAR_PackageFile_v2|PEAR_PackageFile_v2 + * Scan through the Command directory looking for classes + * and see what commands they implement. + * + * @param bool (optional) if FALSE (default), the new list of + * commands should replace the current one. If TRUE, + * new entries will be merged with old. + * + * @param string (optional) where (what directory) to look for + * classes, defaults to the Command subdirectory of + * the directory from where this file (__FILE__) is + * included. + * + * @return bool TRUE on success, a PEAR error on failure + * + * @access public + * @static */ - function dependsOn($parent, $child) - { - $c = array(); - $this->_getDepDB(); - return $this->_dependsOn($parent, $child, $c); - } - - function _dependsOn($parent, $child, &$checked) + function registerCommands($merge = false, $dir = null) { - if (is_object($parent)) { - $channel = strtolower($parent->getChannel()); - $package = strtolower($parent->getPackage()); - } else { - $channel = strtolower($parent['channel']); - $package = strtolower($parent['package']); + $parser = new PEAR_XMLParser; + if ($dir === null) { + $dir = dirname(__FILE__) . '/Command'; } - - if (is_object($child)) { - $depchannel = strtolower($child->getChannel()); - $deppackage = strtolower($child->getPackage()); - } else { - $depchannel = strtolower($child['channel']); - $deppackage = strtolower($child['package']); + if (!is_dir($dir)) { + return PEAR::raiseError("registerCommands: opendir($dir) '$dir' does not exist or is not a directory"); } - - if (isset($checked[$channel][$package][$depchannel][$deppackage])) { - return false; // avoid endless recursion + $dp = @opendir($dir); + if (empty($dp)) { + return PEAR::raiseError("registerCommands: opendir($dir) failed"); } - - $checked[$channel][$package][$depchannel][$deppackage] = true; - if (!isset($this->_cache['dependencies'][$channel][$package])) { - return false; + if (!$merge) { + $GLOBALS['_PEAR_Command_commandlist'] = array(); } - foreach ($this->_cache['dependencies'][$channel][$package] as $info) { - if (isset($info['dep']['uri'])) { - if (is_object($child)) { - if ($info['dep']['uri'] == $child->getURI()) { - return true; - } - } elseif (isset($child['uri'])) { - if ($info['dep']['uri'] == $child['uri']) { - return true; - } - } - return false; + while ($file = readdir($dp)) { + if ($file{0} == '.' || substr($file, -4) != '.xml') { + continue; } - if (strtolower($info['dep']['channel']) == $depchannel && - strtolower($info['dep']['name']) == $deppackage) { - return true; + $f = substr($file, 0, -4); + $class = "PEAR_Command_" . $f; + // List of commands + if (empty($GLOBALS['_PEAR_Command_objects'][$class])) { + $GLOBALS['_PEAR_Command_objects'][$class] = "$dir/" . $f . '.php'; } - } - foreach ($this->_cache['dependencies'][$channel][$package] as $info) { - if (isset($info['dep']['uri'])) { - if ($this->_dependsOn(array( - 'uri' => $info['dep']['uri'], - 'package' => $info['dep']['name']), $child, $checked)) { - return true; + $parser->parse(file_get_contents("$dir/$file")); + $implements = $parser->getData(); + foreach ($implements as $command => $desc) { + if ($command == 'attribs') { + continue; } - } else { - if ($this->_dependsOn(array( - 'channel' => $info['dep']['channel'], - 'package' => $info['dep']['name']), $child, $checked)) { - return true; + + if (isset($GLOBALS['_PEAR_Command_commandlist'][$command])) { + return PEAR::raiseError('Command "' . $command . '" already registered in ' . + 'class "' . $GLOBALS['_PEAR_Command_commandlist'][$command] . '"'); + } + + $GLOBALS['_PEAR_Command_commandlist'][$command] = $class; + $GLOBALS['_PEAR_Command_commanddesc'][$command] = $desc['summary']; + if (isset($desc['shortcut'])) { + $shortcut = $desc['shortcut']; + if (isset($GLOBALS['_PEAR_Command_shortcuts'][$shortcut])) { + return PEAR::raiseError('Command shortcut "' . $shortcut . '" already ' . + 'registered to command "' . $command . '" in class "' . + $GLOBALS['_PEAR_Command_commandlist'][$command] . '"'); + } + $GLOBALS['_PEAR_Command_shortcuts'][$shortcut] = $command; + } + + if (isset($desc['options']) && $desc['options']) { + foreach ($desc['options'] as $oname => $option) { + if (isset($option['shortopt']) && strlen($option['shortopt']) > 1) { + return PEAR::raiseError('Option "' . $oname . '" short option "' . + $option['shortopt'] . '" must be ' . + 'only 1 character in Command "' . $command . '" in class "' . + $class . '"'); + } + } } } } - return false; + ksort($GLOBALS['_PEAR_Command_shortcuts']); + ksort($GLOBALS['_PEAR_Command_commandlist']); + @closedir($dp); + return true; } + // }}} + // {{{ getCommands() + /** - * Register dependencies of a package that is being installed or upgraded - * @param PEAR_PackageFile_v2|PEAR_PackageFile_v2 + * Get the list of currently supported commands, and what + * classes implement them. + * + * @return array command => implementing class + * + * @access public + * @static */ - function installPackage(&$package) + function getCommands() { - $data = $this->_getDepDB(); - unset($this->_cache); - $this->_setPackageDeps($data, $package); - $this->_writeDepDB($data); + if (empty($GLOBALS['_PEAR_Command_commandlist'])) { + PEAR_Command::registerCommands(); + } + return $GLOBALS['_PEAR_Command_commandlist']; } + // }}} + // {{{ getShortcuts() + /** - * Remove dependencies of a package that is being uninstalled, or upgraded. + * Get the list of command shortcuts. * - * Upgraded packages first uninstall, then install - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array If an array, then it must have - * indices 'channel' and 'package' + * @return array shortcut => command + * + * @access public + * @static */ - function uninstallPackage(&$pkg) + function getShortcuts() { - $data = $this->_getDepDB(); - unset($this->_cache); - if (is_object($pkg)) { - $channel = strtolower($pkg->getChannel()); - $package = strtolower($pkg->getPackage()); - } else { - $channel = strtolower($pkg['channel']); - $package = strtolower($pkg['package']); - } - - if (!isset($data['dependencies'][$channel][$package])) { - return true; + if (empty($GLOBALS['_PEAR_Command_shortcuts'])) { + PEAR_Command::registerCommands(); } + return $GLOBALS['_PEAR_Command_shortcuts']; + } - foreach ($data['dependencies'][$channel][$package] as $dep) { - $found = false; - $depchannel = isset($dep['dep']['uri']) ? '__uri' : strtolower($dep['dep']['channel']); - $depname = strtolower($dep['dep']['name']); - if (isset($data['packages'][$depchannel][$depname])) { - foreach ($data['packages'][$depchannel][$depname] as $i => $info) { - if ($info['channel'] == $channel && $info['package'] == $package) { - $found = true; - break; - } - } - } - - if ($found) { - unset($data['packages'][$depchannel][$depname][$i]); - if (!count($data['packages'][$depchannel][$depname])) { - unset($data['packages'][$depchannel][$depname]); - if (!count($data['packages'][$depchannel])) { - unset($data['packages'][$depchannel]); - } - } else { - $data['packages'][$depchannel][$depname] = - array_values($data['packages'][$depchannel][$depname]); - } - } - } + // }}} + // {{{ getGetoptArgs() - unset($data['dependencies'][$channel][$package]); - if (!count($data['dependencies'][$channel])) { - unset($data['dependencies'][$channel]); + /** + * Compiles arguments for getopt. + * + * @param string $command command to get optstring for + * @param string $short_args (reference) short getopt format + * @param array $long_args (reference) long getopt format + * + * @return void + * + * @access public + * @static + */ + function getGetoptArgs($command, &$short_args, &$long_args) + { + if (empty($GLOBALS['_PEAR_Command_commandlist'])) { + PEAR_Command::registerCommands(); } - - if (!count($data['dependencies'])) { - unset($data['dependencies']); + if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) { + $command = $GLOBALS['_PEAR_Command_shortcuts'][$command]; } - - if (!count($data['packages'])) { - unset($data['packages']); + if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) { + return null; } - - $this->_writeDepDB($data); + $obj = &PEAR_Command::getObject($command); + return $obj->getGetoptArgs($command, $short_args, $long_args); } + // }}} + // {{{ getDescription() + /** - * Rebuild the dependency DB by reading registry entries. - * @return true|PEAR_Error + * Get description for a command. + * + * @param string $command Name of the command + * + * @return string command description + * + * @access public + * @static */ - function rebuildDB() + function getDescription($command) { - $depdb = array('_version' => $this->_version); - if (!$this->hasWriteAccess()) { - // allow startup for read-only with older Registry - return $depdb; - } - - $packages = $this->_registry->listAllPackages(); - if (PEAR::isError($packages)) { - return $packages; - } - - foreach ($packages as $channel => $ps) { - foreach ($ps as $package) { - $package = $this->_registry->getPackage($package, $channel); - if (PEAR::isError($package)) { - return $package; - } - $this->_setPackageDeps($depdb, $package); - } - } - - $error = $this->_writeDepDB($depdb); - if (PEAR::isError($error)) { - return $error; + if (!isset($GLOBALS['_PEAR_Command_commanddesc'][$command])) { + return null; } - - $this->_cache = $depdb; - return true; + return $GLOBALS['_PEAR_Command_commanddesc'][$command]; } + // }}} + // {{{ getHelp() + /** - * Register usage of the dependency DB to prevent race conditions - * @param int one of the LOCK_* constants - * @return true|PEAR_Error - * @access private + * Get help for command. + * + * @param string $command Name of the command to return help for + * + * @access public + * @static */ - function _lock($mode = LOCK_EX) + function getHelp($command) { - if (stristr(php_uname(), 'Windows 9')) { - return true; + $cmds = PEAR_Command::getCommands(); + if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) { + $command = $GLOBALS['_PEAR_Command_shortcuts'][$command]; } - - if ($mode != LOCK_UN && is_resource($this->_lockFp)) { - // XXX does not check type of lock (LOCK_SH/LOCK_EX) - return true; + if (isset($cmds[$command])) { + $obj = &PEAR_Command::getObject($command); + return $obj->getHelp($command); } - - $open_mode = 'w'; - // XXX People reported problems with LOCK_SH and 'w' - if ($mode === LOCK_SH) { - if (!file_exists($this->_lockfile)) { - touch($this->_lockfile); - } elseif (!is_file($this->_lockfile)) { - return PEAR::raiseError('could not create Dependency lock file, ' . - 'it exists and is not a regular file'); - } - $open_mode = 'r'; - } - - if (!is_resource($this->_lockFp)) { - $this->_lockFp = @fopen($this->_lockfile, $open_mode); - } - - if (!is_resource($this->_lockFp)) { - return PEAR::raiseError("could not create Dependency lock file" . - (isset($php_errormsg) ? ": " . $php_errormsg : "")); - } - - if (!(int)flock($this->_lockFp, $mode)) { - switch ($mode) { - case LOCK_SH: $str = 'shared'; break; - case LOCK_EX: $str = 'exclusive'; break; - case LOCK_UN: $str = 'unlock'; break; - default: $str = 'unknown'; break; - } - - return PEAR::raiseError("could not acquire $str lock ($this->_lockfile)"); - } - - return true; - } - - /** - * Release usage of dependency DB - * @return true|PEAR_Error - * @access private - */ - function _unlock() - { - $ret = $this->_lock(LOCK_UN); - if (is_resource($this->_lockFp)) { - fclose($this->_lockFp); - } - $this->_lockFp = null; - return $ret; - } - - /** - * Load the dependency database from disk, or return the cache - * @return array|PEAR_Error - */ - function _getDepDB() - { - if (!$this->hasWriteAccess()) { - return array('_version' => $this->_version); - } - - if (isset($this->_cache)) { - return $this->_cache; - } - - if (!$fp = fopen($this->_depdb, 'r')) { - $err = PEAR::raiseError("Could not open dependencies file `".$this->_depdb."'"); - return $err; - } - - $rt = get_magic_quotes_runtime(); - set_magic_quotes_runtime(0); - clearstatcache(); - fclose($fp); - $data = unserialize(file_get_contents($this->_depdb)); - set_magic_quotes_runtime($rt); - $this->_cache = $data; - return $data; - } - - /** - * Write out the dependency database to disk - * @param array the database - * @return true|PEAR_Error - * @access private - */ - function _writeDepDB(&$deps) - { - if (PEAR::isError($e = $this->_lock(LOCK_EX))) { - return $e; - } - - if (!$fp = fopen($this->_depdb, 'wb')) { - $this->_unlock(); - return PEAR::raiseError("Could not open dependencies file `".$this->_depdb."' for writing"); - } - - $rt = get_magic_quotes_runtime(); - set_magic_quotes_runtime(0); - fwrite($fp, serialize($deps)); - set_magic_quotes_runtime($rt); - fclose($fp); - $this->_unlock(); - $this->_cache = $deps; - return true; + return false; } + // }}} +}PEAR-1.9.0/PEAR/Common.php100664 764 764 62255 100664 10030 + * @author Tomas V. V. Cox + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Common.php 282969 2009-06-28 23:09:27Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1.0 + * @deprecated File deprecated since Release 1.4.0a1 + */ - /** - * Register all dependencies from a package in the dependencies database, in essence - * "installing" the package's dependency information - * @param array the database - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @access private - */ - function _setPackageDeps(&$data, &$pkg) - { - $pkg->setConfig($this->_config); - if ($pkg->getPackagexmlVersion() == '1.0') { - $gen = &$pkg->getDefaultGenerator(); - $deps = $gen->dependenciesToV2(); - } else { - $deps = $pkg->getDeps(true); - } - - if (!$deps) { - return; - } - - if (!is_array($data)) { - $data = array(); - } - - if (!isset($data['dependencies'])) { - $data['dependencies'] = array(); - } - - $channel = strtolower($pkg->getChannel()); - $package = strtolower($pkg->getPackage()); - - if (!isset($data['dependencies'][$channel])) { - $data['dependencies'][$channel] = array(); - } - - $data['dependencies'][$channel][$package] = array(); - if (isset($deps['required']['package'])) { - if (!isset($deps['required']['package'][0])) { - $deps['required']['package'] = array($deps['required']['package']); - } - - foreach ($deps['required']['package'] as $dep) { - $this->_registerDep($data, $pkg, $dep, 'required'); - } - } - - if (isset($deps['optional']['package'])) { - if (!isset($deps['optional']['package'][0])) { - $deps['optional']['package'] = array($deps['optional']['package']); - } - - foreach ($deps['optional']['package'] as $dep) { - $this->_registerDep($data, $pkg, $dep, 'optional'); - } - } - - if (isset($deps['required']['subpackage'])) { - if (!isset($deps['required']['subpackage'][0])) { - $deps['required']['subpackage'] = array($deps['required']['subpackage']); - } - - foreach ($deps['required']['subpackage'] as $dep) { - $this->_registerDep($data, $pkg, $dep, 'required'); - } - } - - if (isset($deps['optional']['subpackage'])) { - if (!isset($deps['optional']['subpackage'][0])) { - $deps['optional']['subpackage'] = array($deps['optional']['subpackage']); - } - - foreach ($deps['optional']['subpackage'] as $dep) { - $this->_registerDep($data, $pkg, $dep, 'optional'); - } - } - - if (isset($deps['group'])) { - if (!isset($deps['group'][0])) { - $deps['group'] = array($deps['group']); - } +/** + * Include error handling + */ +require_once 'PEAR.php'; - foreach ($deps['group'] as $group) { - if (isset($group['package'])) { - if (!isset($group['package'][0])) { - $group['package'] = array($group['package']); - } +/** + * PEAR_Common error when an invalid PHP file is passed to PEAR_Common::analyzeSourceCode() + */ +define('PEAR_COMMON_ERROR_INVALIDPHP', 1); +define('_PEAR_COMMON_PACKAGE_NAME_PREG', '[A-Za-z][a-zA-Z0-9_]+'); +define('PEAR_COMMON_PACKAGE_NAME_PREG', '/^' . _PEAR_COMMON_PACKAGE_NAME_PREG . '\\z/'); - foreach ($group['package'] as $dep) { - $this->_registerDep($data, $pkg, $dep, 'optional', - $group['attribs']['name']); - } - } +// this should allow: 1, 1.0, 1.0RC1, 1.0dev, 1.0dev123234234234, 1.0a1, 1.0b1, 1.0pl1 +define('_PEAR_COMMON_PACKAGE_VERSION_PREG', '\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?'); +define('PEAR_COMMON_PACKAGE_VERSION_PREG', '/^' . _PEAR_COMMON_PACKAGE_VERSION_PREG . '\\z/i'); - if (isset($group['subpackage'])) { - if (!isset($group['subpackage'][0])) { - $group['subpackage'] = array($group['subpackage']); - } +// XXX far from perfect :-) +define('_PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '(' . _PEAR_COMMON_PACKAGE_NAME_PREG . + ')(-([.0-9a-zA-Z]+))?'); +define('PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_PACKAGE_DOWNLOAD_PREG . + '\\z/'); - foreach ($group['subpackage'] as $dep) { - $this->_registerDep($data, $pkg, $dep, 'optional', - $group['attribs']['name']); - } - } - } - } +define('_PEAR_CHANNELS_NAME_PREG', '[A-Za-z][a-zA-Z0-9\.]+'); +define('PEAR_CHANNELS_NAME_PREG', '/^' . _PEAR_CHANNELS_NAME_PREG . '\\z/'); - if ($data['dependencies'][$channel][$package] == array()) { - unset($data['dependencies'][$channel][$package]); - if (!count($data['dependencies'][$channel])) { - unset($data['dependencies'][$channel]); - } - } - } +// this should allow any dns or IP address, plus a path - NO UNDERSCORES ALLOWED +define('_PEAR_CHANNELS_SERVER_PREG', '[a-zA-Z0-9\-]+(?:\.[a-zA-Z0-9\-]+)*(\/[a-zA-Z0-9\-]+)*'); +define('PEAR_CHANNELS_SERVER_PREG', '/^' . _PEAR_CHANNELS_SERVER_PREG . '\\z/i'); - /** - * @param array the database - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @param array the specific dependency - * @param required|optional whether this is a required or an optional dep - * @param string|false dependency group this dependency is from, or false for ordinary dep - */ - function _registerDep(&$data, &$pkg, $dep, $type, $group = false) - { - $info = array( - 'dep' => $dep, - 'type' => $type, - 'group' => $group - ); +define('_PEAR_CHANNELS_PACKAGE_PREG', '(' ._PEAR_CHANNELS_SERVER_PREG . ')\/(' + . _PEAR_COMMON_PACKAGE_NAME_PREG . ')'); +define('PEAR_CHANNELS_PACKAGE_PREG', '/^' . _PEAR_CHANNELS_PACKAGE_PREG . '\\z/i'); - $dep = array_map('strtolower', $dep); - $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri'; - if (!isset($data['dependencies'])) { - $data['dependencies'] = array(); - } +define('_PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '(' . _PEAR_CHANNELS_NAME_PREG . ')::(' + . _PEAR_COMMON_PACKAGE_NAME_PREG . ')(-([.0-9a-zA-Z]+))?'); +define('PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_CHANNEL_DOWNLOAD_PREG . '\\z/'); - $channel = strtolower($pkg->getChannel()); - $package = strtolower($pkg->getPackage()); +/** + * List of temporary files and directories registered by + * PEAR_Common::addTempFile(). + * @var array + */ +$GLOBALS['_PEAR_Common_tempfiles'] = array(); - if (!isset($data['dependencies'][$channel])) { - $data['dependencies'][$channel] = array(); - } +/** + * Valid maintainer roles + * @var array + */ +$GLOBALS['_PEAR_Common_maintainer_roles'] = array('lead','developer','contributor','helper'); - if (!isset($data['dependencies'][$channel][$package])) { - $data['dependencies'][$channel][$package] = array(); - } +/** + * Valid release states + * @var array + */ +$GLOBALS['_PEAR_Common_release_states'] = array('alpha','beta','stable','snapshot','devel'); - $data['dependencies'][$channel][$package][] = $info; - if (isset($data['packages'][$depchannel][$dep['name']])) { - $found = false; - foreach ($data['packages'][$depchannel][$dep['name']] as $i => $p) { - if ($p['channel'] == $channel && $p['package'] == $package) { - $found = true; - break; - } - } +/** + * Valid dependency types + * @var array + */ +$GLOBALS['_PEAR_Common_dependency_types'] = array('pkg','ext','php','prog','ldlib','rtlib','os','websrv','sapi'); - if (!$found) { - $data['packages'][$depchannel][$dep['name']][] = array( - 'channel' => $channel, - 'package' => $package - ); - } - } else { - if (!isset($data['packages'])) { - $data['packages'] = array(); - } +/** + * Valid dependency relations + * @var array + */ +$GLOBALS['_PEAR_Common_dependency_relations'] = array('has','eq','lt','le','gt','ge','not', 'ne'); - if (!isset($data['packages'][$depchannel])) { - $data['packages'][$depchannel] = array(); - } +/** + * Valid file roles + * @var array + */ +$GLOBALS['_PEAR_Common_file_roles'] = array('php','ext','test','doc','data','src','script'); - if (!isset($data['packages'][$depchannel][$dep['name']])) { - $data['packages'][$depchannel][$dep['name']] = array(); - } +/** + * Valid replacement types + * @var array + */ +$GLOBALS['_PEAR_Common_replacement_types'] = array('php-const', 'pear-config', 'package-info'); - $data['packages'][$depchannel][$dep['name']][] = array( - 'channel' => $channel, - 'package' => $package - ); - } - } -}PEAR-1.8.0/PEAR/Dependency2.php100664 764 764 142623 100664 10755 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Dependency2.php,v 1.59 2009/02/24 23:38:22 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 + * Valid "provide" types + * @var array */ +$GLOBALS['_PEAR_Common_provide_types'] = array('ext', 'prog', 'class', 'function', 'feature', 'api'); /** - * Required for the PEAR_VALIDATE_* constants + * Valid "provide" types + * @var array */ -require_once 'PEAR/Validate.php'; +$GLOBALS['_PEAR_Common_script_phases'] = array('pre-install', 'post-install', 'pre-uninstall', 'post-uninstall', 'pre-build', 'post-build', 'pre-configure', 'post-configure', 'pre-setup', 'post-setup'); /** - * Dependency check for PEAR packages - * - * This class handles both version 1.0 and 2.0 dependencies - * WARNING: *any* changes to this class must be duplicated in the - * test_PEAR_Dependency2 class found in tests/PEAR_Dependency2/setup.php.inc, - * or unit tests will not actually validate the changes + * Class providing common functionality for PEAR administration classes. * @category pear * @package PEAR + * @author Stig Bakken + * @author Tomas V. V. Cox * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 1.4.0a1 + * @deprecated This class will disappear, and its components will be spread + * into smaller classes, like the AT&T breakup, as of Release 1.4.0a1 */ -class PEAR_Dependency2 +class PEAR_Common extends PEAR { /** - * One of the PEAR_VALIDATE_* states - * @see PEAR_VALIDATE_NORMAL - * @var integer + * User Interface object (PEAR_Frontend_* class). If null, + * the log() method uses print. + * @var object */ - var $_state; + var $ui = null; /** - * Command-line options to install/upgrade/uninstall commands - * @param array + * Configuration object (PEAR_Config). + * @var PEAR_Config */ - var $_options; + var $config = null; - /** - * @var OS_Guess - */ - var $_os; + /** stack of elements, gives some sort of XML context */ + var $element_stack = array(); - /** - * @var PEAR_Registry - */ - var $_registry; + /** name of currently parsed XML element */ + var $current_element; - /** - * @var PEAR_Config - */ - var $_config; + /** array of attributes of the currently parsed XML element */ + var $current_attributes = array(); + + /** assoc with information about a package */ + var $pkginfo = array(); + + var $current_path = null; /** - * @var PEAR_DependencyDB + * Flag variable used to mark a valid package file + * @var boolean + * @access private */ - var $_dependencydb; + var $_validPackageFile; /** - * Output of PEAR_Registry::parsedPackageName() - * @var array + * PEAR_Common constructor + * + * @access public */ - var $_currentPackage; + function PEAR_Common() + { + parent::PEAR(); + $this->config = &PEAR_Config::singleton(); + $this->debug = $this->config->get('verbose'); + } /** - * @param PEAR_Config - * @param array installation options - * @param array format of PEAR_Registry::parsedPackageName() - * @param int installation state (one of PEAR_VALIDATE_*) + * PEAR_Common destructor + * + * @access private */ - function PEAR_Dependency2(&$config, $installoptions, $package, - $state = PEAR_VALIDATE_INSTALLING) + function _PEAR_Common() { - $this->_config = &$config; - if (!class_exists('PEAR_DependencyDB')) { - require_once 'PEAR/DependencyDB.php'; - } + // doesn't work due to bug #14744 + //$tempfiles = $this->_tempfiles; + $tempfiles =& $GLOBALS['_PEAR_Common_tempfiles']; + while ($file = array_shift($tempfiles)) { + if (@is_dir($file)) { + if (!class_exists('System')) { + require_once 'System.php'; + } - if (isset($installoptions['packagingroot'])) { - // make sure depdb is in the right location - $config->setInstallRoot($installoptions['packagingroot']); + System::rm(array('-rf', $file)); + } elseif (file_exists($file)) { + unlink($file); + } } + } - $this->_registry = &$config->getRegistry(); - $this->_dependencydb = &PEAR_DependencyDB::singleton($config); - if (isset($installoptions['packagingroot'])) { - $config->setInstallRoot(false); + /** + * Register a temporary file or directory. When the destructor is + * executed, all registered temporary files and directories are + * removed. + * + * @param string $file name of file or directory + * + * @return void + * + * @access public + */ + function addTempFile($file) + { + if (!class_exists('PEAR_Frontend')) { + require_once 'PEAR/Frontend.php'; } + PEAR_Frontend::addTempFile($file); + } - $this->_options = $installoptions; - $this->_state = $state; - if (!class_exists('OS_Guess')) { - require_once 'OS/Guess.php'; + /** + * Wrapper to System::mkDir(), creates a directory as well as + * any necessary parent directories. + * + * @param string $dir directory name + * + * @return bool TRUE on success, or a PEAR error + * + * @access public + */ + function mkDirHier($dir) + { + // Only used in Installer - move it there ? + $this->log(2, "+ create dir $dir"); + if (!class_exists('System')) { + require_once 'System.php'; } - - $this->_os = new OS_Guess; - $this->_currentPackage = $package; + return System::mkDir(array('-p', $dir)); } - function _getExtraString($dep) + /** + * Logging method. + * + * @param int $level log level (0 is quiet, higher is noisier) + * @param string $msg message to write to the log + * + * @return void + * + * @access public + * @static + */ + function log($level, $msg, $append_crlf = true) { - $extra = ' ('; - if (isset($dep['uri'])) { - return ''; - } - - if (isset($dep['recommended'])) { - $extra .= 'recommended version ' . $dep['recommended']; - } else { - if (isset($dep['min'])) { - $extra .= 'version >= ' . $dep['min']; + if ($this->debug >= $level) { + if (!class_exists('PEAR_Frontend')) { + require_once 'PEAR/Frontend.php'; } - if (isset($dep['max'])) { - if ($extra != ' (') { - $extra .= ', '; - } - $extra .= 'version <= ' . $dep['max']; + $ui = &PEAR_Frontend::singleton(); + if (is_a($ui, 'PEAR_Frontend')) { + $ui->log($msg, $append_crlf); + } else { + print "$msg\n"; } + } + } - if (isset($dep['exclude'])) { - if (!is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); - } - - if ($extra != ' (') { - $extra .= ', '; - } - - $extra .= 'excluded versions: '; - foreach ($dep['exclude'] as $i => $exclude) { - if ($i) { - $extra .= ', '; - } - $extra .= $exclude; - } - } + /** + * Create and register a temporary directory. + * + * @param string $tmpdir (optional) Directory to use as tmpdir. + * Will use system defaults (for example + * /tmp or c:\windows\temp) if not specified + * + * @return string name of created directory + * + * @access public + */ + function mkTempDir($tmpdir = '') + { + $topt = $tmpdir ? array('-t', $tmpdir) : array(); + $topt = array_merge($topt, array('-d', 'pear')); + if (!class_exists('System')) { + require_once 'System.php'; } - $extra .= ')'; - if ($extra == ' ()') { - $extra = ''; + if (!$tmpdir = System::mktemp($topt)) { + return false; } - return $extra; + $this->addTempFile($tmpdir); + return $tmpdir; } /** - * This makes unit-testing a heck of a lot easier + * Set object that represents the frontend to be used. + * + * @param object Reference of the frontend object + * @return void + * @access public */ - function getPHP_OS() + function setFrontendObject(&$ui) { - return PHP_OS; + $this->ui = &$ui; } /** - * This makes unit-testing a heck of a lot easier + * Return an array containing all of the states that are more stable than + * or equal to the passed in state + * + * @param string Release state + * @param boolean Determines whether to include $state in the list + * @return false|array False if $state is not a valid release state */ - function getsysname() + function betterStates($state, $include = false) { - return $this->_os->getSysname(); + static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable'); + $i = array_search($state, $states); + if ($i === false) { + return false; + } + if ($include) { + $i--; + } + return array_slice($states, $i + 1); } /** - * Specify a dependency on an OS. Use arch for detailed os/processor information + * Get the valid roles for a PEAR package maintainer * - * There are two generic OS dependencies that will be the most common, unix and windows. - * Other options are linux, freebsd, darwin (OS X), sunos, irix, hpux, aix + * @return array + * @static */ - function validateOsDependency($dep) + function getUserRoles() { - if ($this->_state != PEAR_VALIDATE_INSTALLING && $this->_state != PEAR_VALIDATE_DOWNLOADING) { - return true; - } - - if ($dep['name'] == '*') { - return true; - } + return $GLOBALS['_PEAR_Common_maintainer_roles']; + } - $not = isset($dep['conflicts']) ? true : false; - switch (strtolower($dep['name'])) { - case 'windows' : - if ($not) { - if (strtolower(substr($this->getPHP_OS(), 0, 3)) == 'win') { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError("Cannot install %s on Windows"); - } + /** + * Get the valid package release states of packages + * + * @return array + * @static + */ + function getReleaseStates() + { + return $GLOBALS['_PEAR_Common_release_states']; + } - return $this->warning("warning: Cannot install %s on Windows"); - } - } else { - if (strtolower(substr($this->getPHP_OS(), 0, 3)) != 'win') { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError("Can only install %s on Windows"); - } + /** + * Get the implemented dependency types (php, ext, pkg etc.) + * + * @return array + * @static + */ + function getDependencyTypes() + { + return $GLOBALS['_PEAR_Common_dependency_types']; + } - return $this->warning("warning: Can only install %s on Windows"); - } - } - break; - case 'unix' : - $unices = array('linux', 'freebsd', 'darwin', 'sunos', 'irix', 'hpux', 'aix'); - if ($not) { - if (in_array($this->getSysname(), $unices)) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError("Cannot install %s on any Unix system"); - } + /** + * Get the implemented dependency relations (has, lt, ge etc.) + * + * @return array + * @static + */ + function getDependencyRelations() + { + return $GLOBALS['_PEAR_Common_dependency_relations']; + } - return $this->warning( "warning: Cannot install %s on any Unix system"); - } - } else { - if (!in_array($this->getSysname(), $unices)) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError("Can only install %s on a Unix system"); - } + /** + * Get the implemented file roles + * + * @return array + * @static + */ + function getFileRoles() + { + return $GLOBALS['_PEAR_Common_file_roles']; + } - return $this->warning("warning: Can only install %s on a Unix system"); - } - } - break; - default : - if ($not) { - if (strtolower($dep['name']) == strtolower($this->getSysname())) { - if (!isset($this->_options['nodeps']) && - !isset($this->_options['force'])) { - return $this->raiseError('Cannot install %s on ' . $dep['name'] . - ' operating system'); - } + /** + * Get the implemented file replacement types in + * + * @return array + * @static + */ + function getReplacementTypes() + { + return $GLOBALS['_PEAR_Common_replacement_types']; + } - return $this->warning('warning: Cannot install %s on ' . - $dep['name'] . ' operating system'); - } - } else { - if (strtolower($dep['name']) != strtolower($this->getSysname())) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('Cannot install %s on ' . - $this->getSysname() . - ' operating system, can only install on ' . $dep['name']); - } + /** + * Get the implemented file replacement types in + * + * @return array + * @static + */ + function getProvideTypes() + { + return $GLOBALS['_PEAR_Common_provide_types']; + } - return $this->warning('warning: Cannot install %s on ' . - $this->getSysname() . - ' operating system, can only install on ' . $dep['name']); - } - } - } - return true; + /** + * Get the implemented file replacement types in + * + * @return array + * @static + */ + function getScriptPhases() + { + return $GLOBALS['_PEAR_Common_script_phases']; } /** - * This makes unit-testing a heck of a lot easier + * Test whether a string contains a valid package name. + * + * @param string $name the package name to test + * + * @return bool + * + * @access public */ - function matchSignature($pattern) + function validPackageName($name) { - return $this->_os->matchSignature($pattern); + return (bool)preg_match(PEAR_COMMON_PACKAGE_NAME_PREG, $name); } /** - * Specify a complex dependency on an OS/processor/kernel version, - * Use OS for simple operating system dependency. + * Test whether a string contains a valid package version. * - * This is the only dependency that accepts an eregable pattern. The pattern - * will be matched against the php_uname() output parsed by OS_Guess + * @param string $ver the package version to test + * + * @return bool + * + * @access public */ - function validateArchDependency($dep) + function validPackageVersion($ver) { - if ($this->_state != PEAR_VALIDATE_INSTALLING) { + return (bool)preg_match(PEAR_COMMON_PACKAGE_VERSION_PREG, $ver); + } + + /** + * @param string $path relative or absolute include path + * @return boolean + * @static + */ + function isIncludeable($path) + { + if (file_exists($path) && is_readable($path)) { return true; } - $not = isset($dep['conflicts']) ? true : false; - if (!$this->matchSignature($dep['pattern'])) { - if (!$not) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s Architecture dependency failed, does not ' . - 'match "' . $dep['pattern'] . '"'); - } - - return $this->warning('warning: %s Architecture dependency failed, does ' . - 'not match "' . $dep['pattern'] . '"'); + $ipath = explode(PATH_SEPARATOR, ini_get('include_path')); + foreach ($ipath as $include) { + $test = realpath($include . DIRECTORY_SEPARATOR . $path); + if (file_exists($test) && is_readable($test)) { + return true; } + } - return true; + return false; + } + + function _postProcessChecks($pf) + { + if (!PEAR::isError($pf)) { + return $this->_postProcessValidPackagexml($pf); } - if ($not) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s Architecture dependency failed, required "' . - $dep['pattern'] . '"'); + $errs = $pf->getUserinfo(); + if (is_array($errs)) { + foreach ($errs as $error) { + $e = $this->raiseError($error['message'], $error['code'], null, null, $error); } - - return $this->warning('warning: %s Architecture dependency failed, ' . - 'required "' . $dep['pattern'] . '"'); } - return true; + return $pf; } /** - * This makes unit-testing a heck of a lot easier + * Returns information about a package file. Expects the name of + * a gzipped tar file as input. + * + * @param string $file name of .tgz file + * + * @return array array with package information + * + * @access public + * @deprecated use PEAR_PackageFile->fromTgzFile() instead + * */ - function extension_loaded($name) + function infoFromTgzFile($file) { - return extension_loaded($name); + $packagefile = &new PEAR_PackageFile($this->config); + $pf = &$packagefile->fromTgzFile($file, PEAR_VALIDATE_NORMAL); + return $this->_postProcessChecks($pf); } /** - * This makes unit-testing a heck of a lot easier + * Returns information about a package file. Expects the name of + * a package xml file as input. + * + * @param string $descfile name of package xml file + * + * @return array array with package information + * + * @access public + * @deprecated use PEAR_PackageFile->fromPackageFile() instead + * */ - function phpversion($name = null) + function infoFromDescriptionFile($descfile) { - if ($name !== null) { - return phpversion($name); - } + $packagefile = &new PEAR_PackageFile($this->config); + $pf = &$packagefile->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL); + return $this->_postProcessChecks($pf); + } - return phpversion(); + /** + * Returns information about a package file. Expects the contents + * of a package xml file as input. + * + * @param string $data contents of package.xml file + * + * @return array array with package information + * + * @access public + * @deprecated use PEAR_PackageFile->fromXmlstring() instead + * + */ + function infoFromString($data) + { + $packagefile = &new PEAR_PackageFile($this->config); + $pf = &$packagefile->fromXmlString($data, PEAR_VALIDATE_NORMAL, false); + return $this->_postProcessChecks($pf); } - function validateExtensionDependency($dep, $required = true) + /** + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @return array + */ + function _postProcessValidPackagexml(&$pf) { - if ($this->_state != PEAR_VALIDATE_INSTALLING && - $this->_state != PEAR_VALIDATE_DOWNLOADING) { - return true; + if (!is_a($pf, 'PEAR_PackageFile_v2')) { + $this->pkginfo = $pf->toArray(); + return $this->pkginfo; } - $loaded = $this->extension_loaded($dep['name']); - $extra = $this->_getExtraString($dep); - if (isset($dep['exclude'])) { - if (!is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); + // sort of make this into a package.xml 1.0-style array + // changelog is not converted to old format. + $arr = $pf->toArray(true); + $arr = array_merge($arr, $arr['old']); + unset($arr['old'], $arr['xsdversion'], $arr['contents'], $arr['compatible'], + $arr['channel'], $arr['uri'], $arr['dependencies'], $arr['phprelease'], + $arr['extsrcrelease'], $arr['zendextsrcrelease'], $arr['extbinrelease'], + $arr['zendextbinrelease'], $arr['bundle'], $arr['lead'], $arr['developer'], + $arr['helper'], $arr['contributor']); + $arr['filelist'] = $pf->getFilelist(); + $this->pkginfo = $arr; + return $arr; + } + + /** + * Returns package information from different sources + * + * This method is able to extract information about a package + * from a .tgz archive or from a XML package definition file. + * + * @access public + * @param string Filename of the source ('package.xml', '.tgz') + * @return string + * @deprecated use PEAR_PackageFile->fromAnyFile() instead + */ + function infoFromAny($info) + { + if (is_string($info) && file_exists($info)) { + $packagefile = &new PEAR_PackageFile($this->config); + $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL); + if (PEAR::isError($pf)) { + $errs = $pf->getUserinfo(); + if (is_array($errs)) { + foreach ($errs as $error) { + $e = $this->raiseError($error['message'], $error['code'], null, null, $error); + } + } + + return $pf; } + + return $this->_postProcessValidPackagexml($pf); } - if (!isset($dep['min']) && !isset($dep['max']) && - !isset($dep['recommended']) && !isset($dep['exclude'])) { - if ($loaded) { - if (isset($dep['conflicts'])) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s conflicts with PHP extension "' . - $dep['name'] . '"' . $extra); - } + return $info; + } - return $this->warning('warning: %s conflicts with PHP extension "' . - $dep['name'] . '"' . $extra); - } + /** + * Return an XML document based on the package info (as returned + * by the PEAR_Common::infoFrom* methods). + * + * @param array $pkginfo package info + * + * @return string XML data + * + * @access public + * @deprecated use a PEAR_PackageFile_v* object's generator instead + */ + function xmlFromInfo($pkginfo) + { + $config = &PEAR_Config::singleton(); + $packagefile = &new PEAR_PackageFile($config); + $pf = &$packagefile->fromArray($pkginfo); + $gen = &$pf->getDefaultGenerator(); + return $gen->toXml(PEAR_VALIDATE_PACKAGING); + } - return true; - } else { - if (isset($dep['conflicts'])) { - return true; - } + /** + * Validate XML package definition file. + * + * @param string $info Filename of the package archive or of the + * package definition file + * @param array $errors Array that will contain the errors + * @param array $warnings Array that will contain the warnings + * @param string $dir_prefix (optional) directory where source files + * may be found, or empty if they are not available + * @access public + * @return boolean + * @deprecated use the validation of PEAR_PackageFile objects + */ + function validatePackageInfo($info, &$errors, &$warnings, $dir_prefix = '') + { + $config = &PEAR_Config::singleton(); + $packagefile = &new PEAR_PackageFile($config); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + if (strpos($info, 'fromXmlString($info, PEAR_VALIDATE_NORMAL, ''); + } else { + $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL); + } - if ($required) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires PHP extension "' . - $dep['name'] . '"' . $extra); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($pf)) { + $errs = $pf->getUserinfo(); + if (is_array($errs)) { + foreach ($errs as $error) { + if ($error['level'] == 'error') { + $errors[] = $error['message']; + } else { + $warnings[] = $error['message']; } - - return $this->warning('warning: %s requires PHP extension "' . - $dep['name'] . '"' . $extra); } - - return $this->warning('%s can optionally use PHP extension "' . - $dep['name'] . '"' . $extra); } + + return false; } - if (!$loaded) { - if (isset($dep['conflicts'])) { - return true; - } + return true; + } - if (!$required) { - return $this->warning('%s can optionally use PHP extension "' . - $dep['name'] . '"' . $extra); - } - - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires PHP extension "' . $dep['name'] . - '"' . $extra); - } - - return $this->warning('warning: %s requires PHP extension "' . $dep['name'] . - '"' . $extra); - } - - $version = (string) $this->phpversion($dep['name']); - if (empty($version)) { - $version = '0'; - } - - $fail = false; - if (isset($dep['min']) && !version_compare($version, $dep['min'], '>=')) { - $fail = true; - } - - if (isset($dep['max']) && !version_compare($version, $dep['max'], '<=')) { - $fail = true; + /** + * Build a "provides" array from data returned by + * analyzeSourceCode(). The format of the built array is like + * this: + * + * array( + * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'), + * ... + * ) + * + * + * @param array $srcinfo array with information about a source file + * as returned by the analyzeSourceCode() method. + * + * @return void + * + * @access public + * + */ + function buildProvidesArray($srcinfo) + { + $file = basename($srcinfo['source_file']); + $pn = ''; + if (isset($this->_packageName)) { + $pn = $this->_packageName; } - if ($fail && !isset($dep['conflicts'])) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires PHP extension "' . $dep['name'] . - '"' . $extra . ', installed version is ' . $version); + $pnl = strlen($pn); + foreach ($srcinfo['declared_classes'] as $class) { + $key = "class;$class"; + if (isset($this->pkginfo['provides'][$key])) { + continue; } - return $this->warning('warning: %s requires PHP extension "' . $dep['name'] . - '"' . $extra . ', installed version is ' . $version); - } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail && isset($dep['conflicts'])) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s conflicts with PHP extension "' . - $dep['name'] . '"' . $extra . ', installed version is ' . $version); + $this->pkginfo['provides'][$key] = + array('file'=> $file, 'type' => 'class', 'name' => $class); + if (isset($srcinfo['inheritance'][$class])) { + $this->pkginfo['provides'][$key]['extends'] = + $srcinfo['inheritance'][$class]; } - - return $this->warning('warning: %s conflicts with PHP extension "' . - $dep['name'] . '"' . $extra . ', installed version is ' . $version); } - if (isset($dep['exclude'])) { - foreach ($dep['exclude'] as $exclude) { - if (version_compare($version, $exclude, '==')) { - if (isset($dep['conflicts'])) { - continue; - } - - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s is not compatible with PHP extension "' . - $dep['name'] . '" version ' . - $exclude); - } - - return $this->warning('warning: %s is not compatible with PHP extension "' . - $dep['name'] . '" version ' . - $exclude); - } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s conflicts with PHP extension "' . - $dep['name'] . '"' . $extra . ', installed version is ' . $version); - } - - return $this->warning('warning: %s conflicts with PHP extension "' . - $dep['name'] . '"' . $extra . ', installed version is ' . $version); + foreach ($srcinfo['declared_methods'] as $class => $methods) { + foreach ($methods as $method) { + $function = "$class::$method"; + $key = "function;$function"; + if ($method{0} == '_' || !strcasecmp($method, $class) || + isset($this->pkginfo['provides'][$key])) { + continue; } + + $this->pkginfo['provides'][$key] = + array('file'=> $file, 'type' => 'function', 'name' => $function); } } - if (isset($dep['recommended'])) { - if (version_compare($version, $dep['recommended'], '==')) { - return true; + foreach ($srcinfo['declared_functions'] as $function) { + $key = "function;$function"; + if ($function{0} == '_' || isset($this->pkginfo['provides'][$key])) { + continue; } - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s dependency: PHP extension ' . $dep['name'] . - ' version "' . $version . '"' . - ' is not the recommended version "' . $dep['recommended'] . - '", but may be compatible, use --force to install'); + if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) { + $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\""; } - return $this->warning('warning: %s dependency: PHP extension ' . - $dep['name'] . ' version "' . $version . '"' . - ' is not the recommended version "' . $dep['recommended'].'"'); + $this->pkginfo['provides'][$key] = + array('file'=> $file, 'type' => 'function', 'name' => $function); } - - return true; } - function validatePhpDependency($dep) + /** + * Analyze the source code of the given PHP file + * + * @param string Filename of the PHP file + * @return mixed + * @access public + */ + function analyzeSourceCode($file) { - if ($this->_state != PEAR_VALIDATE_INSTALLING && - $this->_state != PEAR_VALIDATE_DOWNLOADING) { - return true; - } - - $version = $this->phpversion(); - $extra = $this->_getExtraString($dep); - if (isset($dep['exclude'])) { - if (!is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); - } + if (!class_exists('PEAR_PackageFile_v2_Validator')) { + require_once 'PEAR/PackageFile/v2/Validator.php'; } - if (isset($dep['min'])) { - if (!version_compare($version, $dep['min'], '>=')) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires PHP' . - $extra . ', installed version is ' . $version); - } + $a = new PEAR_PackageFile_v2_Validator; + return $a->analyzeSourceCode($file); + } - return $this->warning('warning: %s requires PHP' . - $extra . ', installed version is ' . $version); - } + function detectDependencies($any, $status_callback = null) + { + if (!function_exists("token_get_all")) { + return false; } - if (isset($dep['max'])) { - if (!version_compare($version, $dep['max'], '<=')) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires PHP' . - $extra . ', installed version is ' . $version); - } - - return $this->warning('warning: %s requires PHP' . - $extra . ', installed version is ' . $version); - } + if (PEAR::isError($info = $this->infoFromAny($any))) { + return $this->raiseError($info); } - if (isset($dep['exclude'])) { - foreach ($dep['exclude'] as $exclude) { - if (version_compare($version, $exclude, '==')) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s is not compatible with PHP version ' . - $exclude); - } + if (!is_array($info)) { + return false; + } - return $this->warning( - 'warning: %s is not compatible with PHP version ' . - $exclude); - } - } + $deps = array(); + $used_c = $decl_c = $decl_f = $decl_m = array(); + foreach ($info['filelist'] as $file => $fa) { + $tmp = $this->analyzeSourceCode($file); + $used_c = @array_merge($used_c, $tmp['used_classes']); + $decl_c = @array_merge($decl_c, $tmp['declared_classes']); + $decl_f = @array_merge($decl_f, $tmp['declared_functions']); + $decl_m = @array_merge($decl_m, $tmp['declared_methods']); + $inheri = @array_merge($inheri, $tmp['inheritance']); } - return true; + $used_c = array_unique($used_c); + $decl_c = array_unique($decl_c); + $undecl_c = array_diff($used_c, $decl_c); + + return array('used_classes' => $used_c, + 'declared_classes' => $decl_c, + 'declared_methods' => $decl_m, + 'declared_functions' => $decl_f, + 'undeclared_classes' => $undecl_c, + 'inheritance' => $inheri, + ); } /** - * This makes unit-testing a heck of a lot easier + * Download a file through HTTP. Considers suggested file name in + * Content-disposition: header and can run a callback function for + * different events. The callback will be called with two + * parameters: the callback type, and parameters. The implemented + * callback types are: + * + * 'setup' called at the very beginning, parameter is a UI object + * that should be used for all output + * 'message' the parameter is a string with an informational message + * 'saveas' may be used to save with a different file name, the + * parameter is the filename that is about to be used. + * If a 'saveas' callback returns a non-empty string, + * that file name will be used as the filename instead. + * Note that $save_dir will not be affected by this, only + * the basename of the file. + * 'start' download is starting, parameter is number of bytes + * that are expected, or -1 if unknown + * 'bytesread' parameter is the number of bytes read so far + * 'done' download is complete, parameter is the total number + * of bytes read + * 'connfailed' if the TCP connection fails, this callback is called + * with array(host,port,errno,errmsg) + * 'writefailed' if writing to disk fails, this callback is called + * with array(destfile,errmsg) + * + * If an HTTP proxy has been configured (http_proxy PEAR_Config + * setting), the proxy will be used. + * + * @param string $url the URL to download + * @param object $ui PEAR_Frontend_* instance + * @param object $config PEAR_Config instance + * @param string $save_dir (optional) directory to save file in + * @param mixed $callback (optional) function/method to call for status + * updates + * + * @return string Returns the full path of the downloaded file or a PEAR + * error on failure. If the error is caused by + * socket-related errors, the error object will + * have the fsockopen error code available through + * getCode(). + * + * @access public + * @deprecated in favor of PEAR_Downloader::downloadHttp() */ - function getPEARVersion() + function downloadHttp($url, &$ui, $save_dir = '.', $callback = null) { - return '1.8.0'; + if (!class_exists('PEAR_Downloader')) { + require_once 'PEAR/Downloader.php'; + } + return PEAR_Downloader::downloadHttp($url, $ui, $save_dir, $callback); } +} - function validatePearinstallerDependency($dep) - { - $pearversion = $this->getPEARVersion(); - $extra = $this->_getExtraString($dep); - if (isset($dep['exclude'])) { - if (!is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); - } - } +require_once 'PEAR/Config.php'; +require_once 'PEAR/PackageFile.php';PEAR-1.9.0/PEAR/Config.php100664 764 764 204452 100664 10022 + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Config.php 286480 2009-07-29 02:50:02Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ - if (version_compare($pearversion, $dep['min'], '<')) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires PEAR Installer' . $extra . - ', installed version is ' . $pearversion); - } +/** + * Required for error handling + */ +require_once 'PEAR.php'; +require_once 'PEAR/Registry.php'; +require_once 'PEAR/Installer/Role.php'; +require_once 'System.php'; - return $this->warning('warning: %s requires PEAR Installer' . $extra . - ', installed version is ' . $pearversion); - } +/** + * Last created PEAR_Config instance. + * @var object + */ +$GLOBALS['_PEAR_Config_instance'] = null; +if (!defined('PEAR_INSTALL_DIR') || !PEAR_INSTALL_DIR) { + $PEAR_INSTALL_DIR = PHP_LIBDIR . DIRECTORY_SEPARATOR . 'pear'; +} else { + $PEAR_INSTALL_DIR = PEAR_INSTALL_DIR; +} - if (isset($dep['max'])) { - if (version_compare($pearversion, $dep['max'], '>')) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires PEAR Installer' . $extra . - ', installed version is ' . $pearversion); - } +// Below we define constants with default values for all configuration +// parameters except username/password. All of them can have their +// defaults set through environment variables. The reason we use the +// PHP_ prefix is for some security, PHP protects environment +// variables starting with PHP_*. - return $this->warning('warning: %s requires PEAR Installer' . $extra . - ', installed version is ' . $pearversion); - } - } +// default channel and preferred mirror is based on whether we are invoked through +// the "pear" or the "pecl" command +if (!defined('PEAR_RUNTYPE')) { + define('PEAR_RUNTYPE', 'pear'); +} - if (isset($dep['exclude'])) { - if (!isset($dep['exclude'][0])) { - $dep['exclude'] = array($dep['exclude']); - } +if (PEAR_RUNTYPE == 'pear') { + define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pear.php.net'); +} else { + define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pecl.php.net'); +} - foreach ($dep['exclude'] as $exclude) { - if (version_compare($exclude, $pearversion, '==')) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s is not compatible with PEAR Installer ' . - 'version ' . $exclude); - } +if (getenv('PHP_PEAR_SYSCONF_DIR')) { + define('PEAR_CONFIG_SYSCONFDIR', getenv('PHP_PEAR_SYSCONF_DIR')); +} elseif (getenv('SystemRoot')) { + define('PEAR_CONFIG_SYSCONFDIR', getenv('SystemRoot')); +} else { + define('PEAR_CONFIG_SYSCONFDIR', PHP_SYSCONFDIR); +} - return $this->warning('warning: %s is not compatible with PEAR ' . - 'Installer version ' . $exclude); - } - } - } +// Default for master_server +if (getenv('PHP_PEAR_MASTER_SERVER')) { + define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', getenv('PHP_PEAR_MASTER_SERVER')); +} else { + define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', 'pear.php.net'); +} - return true; +// Default for http_proxy +if (getenv('PHP_PEAR_HTTP_PROXY')) { + define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('PHP_PEAR_HTTP_PROXY')); +} elseif (getenv('http_proxy')) { + define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('http_proxy')); +} else { + define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', ''); +} + +// Default for php_dir +if (getenv('PHP_PEAR_INSTALL_DIR')) { + define('PEAR_CONFIG_DEFAULT_PHP_DIR', getenv('PHP_PEAR_INSTALL_DIR')); +} else { + if (@file_exists($PEAR_INSTALL_DIR) && is_dir($PEAR_INSTALL_DIR)) { + define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR); + } else { + define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR); } +} - function validateSubpackageDependency($dep, $required, $params) - { - return $this->validatePackageDependency($dep, $required, $params); +// Default for ext_dir +if (getenv('PHP_PEAR_EXTENSION_DIR')) { + define('PEAR_CONFIG_DEFAULT_EXT_DIR', getenv('PHP_PEAR_EXTENSION_DIR')); +} else { + if (ini_get('extension_dir')) { + define('PEAR_CONFIG_DEFAULT_EXT_DIR', ini_get('extension_dir')); + } elseif (defined('PEAR_EXTENSION_DIR') && + file_exists(PEAR_EXTENSION_DIR) && is_dir(PEAR_EXTENSION_DIR)) { + define('PEAR_CONFIG_DEFAULT_EXT_DIR', PEAR_EXTENSION_DIR); + } elseif (defined('PHP_EXTENSION_DIR')) { + define('PEAR_CONFIG_DEFAULT_EXT_DIR', PHP_EXTENSION_DIR); + } else { + define('PEAR_CONFIG_DEFAULT_EXT_DIR', '.'); } +} - /** - * @param array dependency information (2.0 format) - * @param boolean whether this is a required dependency - * @param array a list of downloaded packages to be installed, if any - * @param boolean if true, then deps on pear.php.net that fail will also check - * against pecl.php.net packages to accomodate extensions that have - * moved to pecl.php.net from pear.php.net - */ - function validatePackageDependency($dep, $required, $params, $depv1 = false) - { - if ($this->_state != PEAR_VALIDATE_INSTALLING && - $this->_state != PEAR_VALIDATE_DOWNLOADING) { - return true; - } +// Default for doc_dir +if (getenv('PHP_PEAR_DOC_DIR')) { + define('PEAR_CONFIG_DEFAULT_DOC_DIR', getenv('PHP_PEAR_DOC_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_DOC_DIR', + $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'docs'); +} - if (isset($dep['providesextension'])) { - if ($this->extension_loaded($dep['providesextension'])) { - $save = $dep; - $subdep = $dep; - $subdep['name'] = $subdep['providesextension']; - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $ret = $this->validateExtensionDependency($subdep, $required); - PEAR::popErrorHandling(); - if (!PEAR::isError($ret)) { - return true; - } - } - } +// Default for bin_dir +if (getenv('PHP_PEAR_BIN_DIR')) { + define('PEAR_CONFIG_DEFAULT_BIN_DIR', getenv('PHP_PEAR_BIN_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_BIN_DIR', PHP_BINDIR); +} - if ($this->_state == PEAR_VALIDATE_INSTALLING) { - return $this->_validatePackageInstall($dep, $required, $depv1); - } +// Default for data_dir +if (getenv('PHP_PEAR_DATA_DIR')) { + define('PEAR_CONFIG_DEFAULT_DATA_DIR', getenv('PHP_PEAR_DATA_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_DATA_DIR', + $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'data'); +} - if ($this->_state == PEAR_VALIDATE_DOWNLOADING) { - return $this->_validatePackageDownload($dep, $required, $params, $depv1); - } - } +// Default for cfg_dir +if (getenv('PHP_PEAR_CFG_DIR')) { + define('PEAR_CONFIG_DEFAULT_CFG_DIR', getenv('PHP_PEAR_CFG_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_CFG_DIR', + $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'cfg'); +} - function _validatePackageDownload($dep, $required, $params, $depv1 = false) - { - $dep['package'] = $dep['name']; - if (isset($dep['uri'])) { - $dep['channel'] = '__uri'; - } +// Default for www_dir +if (getenv('PHP_PEAR_WWW_DIR')) { + define('PEAR_CONFIG_DEFAULT_WWW_DIR', getenv('PHP_PEAR_WWW_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_WWW_DIR', + $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'www'); +} - $depname = $this->_registry->parsedPackageNameToString($dep, true); - $found = false; - foreach ($params as $param) { - if ($param->isEqual( - array('package' => $dep['name'], - 'channel' => $dep['channel']))) { - $found = true; - break; - } +// Default for test_dir +if (getenv('PHP_PEAR_TEST_DIR')) { + define('PEAR_CONFIG_DEFAULT_TEST_DIR', getenv('PHP_PEAR_TEST_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_TEST_DIR', + $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'tests'); +} - if ($depv1 && $dep['channel'] == 'pear.php.net') { - if ($param->isEqual( - array('package' => $dep['name'], - 'channel' => 'pecl.php.net'))) { - $found = true; - break; - } - } - } +// Default for temp_dir +if (getenv('PHP_PEAR_TEMP_DIR')) { + define('PEAR_CONFIG_DEFAULT_TEMP_DIR', getenv('PHP_PEAR_TEMP_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_TEMP_DIR', + System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' . + DIRECTORY_SEPARATOR . 'temp'); +} - if (!$found && isset($dep['providesextension'])) { - foreach ($params as $param) { - if ($param->isExtension($dep['providesextension'])) { - $found = true; - break; - } - } - } - - if ($found) { - $version = $param->getVersion(); - $installed = false; - $downloaded = true; - } else { - if ($this->_registry->packageExists($dep['name'], $dep['channel'])) { - $installed = true; - $downloaded = false; - $version = $this->_registry->packageinfo($dep['name'], 'version', - $dep['channel']); - } else { - if ($dep['channel'] == 'pecl.php.net' && $this->_registry->packageExists($dep['name'], - 'pear.php.net')) { - $installed = true; - $downloaded = false; - $version = $this->_registry->packageinfo($dep['name'], 'version', - 'pear.php.net'); - } else { - $version = 'not installed or downloaded'; - $installed = false; - $downloaded = false; - } - } - } - - $extra = $this->_getExtraString($dep); - if (isset($dep['exclude']) && !is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); - } - - if (!isset($dep['min']) && !isset($dep['max']) && - !isset($dep['recommended']) && !isset($dep['exclude']) - ) { - if ($installed || $downloaded) { - $installed = $installed ? 'installed' : 'downloaded'; - if (isset($dep['conflicts'])) { - $rest = ''; - if ($version) { - $rest = ", $installed version is " . $version; - } - - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s conflicts with package "' . $depname . '"' . $extra . $rest); - } - - return $this->warning('warning: %s conflicts with package "' . $depname . '"' . $extra . $rest); - } - - return true; - } - - if (isset($dep['conflicts'])) { - return true; - } - - if ($required) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires package "' . $depname . '"' . $extra); - } - - return $this->warning('warning: %s requires package "' . $depname . '"' . $extra); - } - - return $this->warning('%s can optionally use package "' . $depname . '"' . $extra); - } - - if (!$installed && !$downloaded) { - if (isset($dep['conflicts'])) { - return true; - } - - if ($required) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires package "' . $depname . '"' . $extra); - } - - return $this->warning('warning: %s requires package "' . $depname . '"' . $extra); - } - - return $this->warning('%s can optionally use package "' . $depname . '"' . $extra); - } - - $fail = false; - if (isset($dep['min']) && version_compare($version, $dep['min'], '<')) { - $fail = true; - } - - if (isset($dep['max']) && version_compare($version, $dep['max'], '>')) { - $fail = true; - } - - if ($fail && !isset($dep['conflicts'])) { - $installed = $installed ? 'installed' : 'downloaded'; - $dep['package'] = $dep['name']; - $dep = $this->_registry->parsedPackageNameToString($dep, true); - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires package "' . $depname . '"' . - $extra . ", $installed version is " . $version); - } - - return $this->warning('warning: %s requires package "' . $depname . '"' . - $extra . ", $installed version is " . $version); - } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail && - isset($dep['conflicts']) && !isset($dep['exclude'])) { - $installed = $installed ? 'installed' : 'downloaded'; - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s conflicts with package "' . $depname . '"' . $extra . - ", $installed version is " . $version); - } - - return $this->warning('warning: %s conflicts with package "' . $depname . '"' . - $extra . ", $installed version is " . $version); - } - - if (isset($dep['exclude'])) { - $installed = $installed ? 'installed' : 'downloaded'; - foreach ($dep['exclude'] as $exclude) { - if (version_compare($version, $exclude, '==') && !isset($dep['conflicts'])) { - if (!isset($this->_options['nodeps']) && - !isset($this->_options['force']) - ) { - return $this->raiseError('%s is not compatible with ' . - $installed . ' package "' . - $depname . '" version ' . - $exclude); - } - - return $this->warning('warning: %s is not compatible with ' . - $installed . ' package "' . - $depname . '" version ' . - $exclude); - } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) { - $installed = $installed ? 'installed' : 'downloaded'; - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s conflicts with package "' . $depname . '"' . - $extra . ", $installed version is " . $version); - } +// Default for cache_dir +if (getenv('PHP_PEAR_CACHE_DIR')) { + define('PEAR_CONFIG_DEFAULT_CACHE_DIR', getenv('PHP_PEAR_CACHE_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_CACHE_DIR', + System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' . + DIRECTORY_SEPARATOR . 'cache'); +} - return $this->warning('warning: %s conflicts with package "' . $depname . '"' . - $extra . ", $installed version is " . $version); - } - } - } +// Default for download_dir +if (getenv('PHP_PEAR_DOWNLOAD_DIR')) { + define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR', getenv('PHP_PEAR_DOWNLOAD_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR', + System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' . + DIRECTORY_SEPARATOR . 'download'); +} - if (isset($dep['recommended'])) { - $installed = $installed ? 'installed' : 'downloaded'; - if (version_compare($version, $dep['recommended'], '==')) { - return true; - } +// Default for php_bin +if (getenv('PHP_PEAR_PHP_BIN')) { + define('PEAR_CONFIG_DEFAULT_PHP_BIN', getenv('PHP_PEAR_PHP_BIN')); +} else { + define('PEAR_CONFIG_DEFAULT_PHP_BIN', PEAR_CONFIG_DEFAULT_BIN_DIR. + DIRECTORY_SEPARATOR.'php'.(OS_WINDOWS ? '.exe' : '')); +} - if (!$found && $installed) { - $param = $this->_registry->getPackage($dep['name'], $dep['channel']); - } +// Default for verbose +if (getenv('PHP_PEAR_VERBOSE')) { + define('PEAR_CONFIG_DEFAULT_VERBOSE', getenv('PHP_PEAR_VERBOSE')); +} else { + define('PEAR_CONFIG_DEFAULT_VERBOSE', 1); +} - if ($param) { - $found = false; - foreach ($params as $parent) { - if ($parent->isEqual($this->_currentPackage)) { - $found = true; - break; - } - } +// Default for preferred_state +if (getenv('PHP_PEAR_PREFERRED_STATE')) { + define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', getenv('PHP_PEAR_PREFERRED_STATE')); +} else { + define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', 'stable'); +} - if ($found) { - if ($param->isCompatible($parent)) { - return true; - } - } else { // this is for validPackage() calls - $parent = $this->_registry->getPackage($this->_currentPackage['package'], - $this->_currentPackage['channel']); - if ($parent !== null && $param->isCompatible($parent)) { - return true; - } - } - } +// Default for umask +if (getenv('PHP_PEAR_UMASK')) { + define('PEAR_CONFIG_DEFAULT_UMASK', getenv('PHP_PEAR_UMASK')); +} else { + define('PEAR_CONFIG_DEFAULT_UMASK', decoct(umask())); +} - if (!isset($this->_options['nodeps']) && !isset($this->_options['force']) && - !isset($this->_options['loose']) - ) { - return $this->raiseError('%s dependency package "' . $depname . - '" ' . $installed . ' version ' . $version . - ' is not the recommended version ' . $dep['recommended'] . - ', but may be compatible, use --force to install'); - } +// Default for cache_ttl +if (getenv('PHP_PEAR_CACHE_TTL')) { + define('PEAR_CONFIG_DEFAULT_CACHE_TTL', getenv('PHP_PEAR_CACHE_TTL')); +} else { + define('PEAR_CONFIG_DEFAULT_CACHE_TTL', 3600); +} - return $this->warning('warning: %s dependency package "' . $depname . - '" ' . $installed . ' version ' . $version . - ' is not the recommended version ' . $dep['recommended']); - } +// Default for sig_type +if (getenv('PHP_PEAR_SIG_TYPE')) { + define('PEAR_CONFIG_DEFAULT_SIG_TYPE', getenv('PHP_PEAR_SIG_TYPE')); +} else { + define('PEAR_CONFIG_DEFAULT_SIG_TYPE', 'gpg'); +} - return true; - } +// Default for sig_bin +if (getenv('PHP_PEAR_SIG_BIN')) { + define('PEAR_CONFIG_DEFAULT_SIG_BIN', getenv('PHP_PEAR_SIG_BIN')); +} else { + define('PEAR_CONFIG_DEFAULT_SIG_BIN', + System::which( + 'gpg', OS_WINDOWS ? 'c:\gnupg\gpg.exe' : '/usr/local/bin/gpg')); +} - function _validatePackageInstall($dep, $required, $depv1 = false) - { - return $this->_validatePackageDownload($dep, $required, array(), $depv1); - } +// Default for sig_keydir +if (getenv('PHP_PEAR_SIG_KEYDIR')) { + define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR', getenv('PHP_PEAR_SIG_KEYDIR')); +} else { + define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR', + PEAR_CONFIG_SYSCONFDIR . DIRECTORY_SEPARATOR . 'pearkeys'); +} +/** + * This is a class for storing configuration data, keeping track of + * which are system-defined, user-defined or defaulted. + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Config extends PEAR +{ /** - * Verify that uninstalling packages passed in to command line is OK. + * Array of config files used. * - * @param PEAR_Installer $dl - * @return PEAR_Error|true + * @var array layer => config file */ - function validatePackageUninstall(&$dl) - { - if (PEAR::isError($this->_dependencydb)) { - return $this->_dependencydb; - } - - $params = array(); - // construct an array of "downloaded" packages to fool the package dependency checker - // into using these to validate uninstalls of circular dependencies - $downloaded = &$dl->getUninstallPackages(); - foreach ($downloaded as $i => $pf) { - if (!class_exists('PEAR_Downloader_Package')) { - require_once 'PEAR/Downloader/Package.php'; - } - $dp = &new PEAR_Downloader_Package($dl); - $dp->setPackageFile($downloaded[$i]); - $params[$i] = &$dp; - } - - // check cache - $memyselfandI = strtolower($this->_currentPackage['channel']) . '/' . - strtolower($this->_currentPackage['package']); - if (isset($dl->___uninstall_package_cache)) { - $badpackages = $dl->___uninstall_package_cache; - if (isset($badpackages[$memyselfandI]['warnings'])) { - foreach ($badpackages[$memyselfandI]['warnings'] as $warning) { - $dl->log(0, $warning[0]); - } - } - - if (isset($badpackages[$memyselfandI]['errors'])) { - foreach ($badpackages[$memyselfandI]['errors'] as $error) { - if (is_array($error)) { - $dl->log(0, $error[0]); - } else { - $dl->log(0, $error->getMessage()); - } - } - - if (isset($this->_options['nodeps']) || isset($this->_options['force'])) { - return $this->warning( - 'warning: %s should not be uninstalled, other installed packages depend ' . - 'on this package'); - } + var $files = array( + 'system' => '', + 'user' => '', + ); - return $this->raiseError( - '%s cannot be uninstalled, other installed packages depend on this package'); - } + var $layers = array(); - return true; - } + /** + * Configuration data, two-dimensional array where the first + * dimension is the config layer ('user', 'system' and 'default'), + * and the second dimension is keyname => value. + * + * The order in the first dimension is important! Earlier + * layers will shadow later ones when a config value is + * requested (if a 'user' value exists, it will be returned first, + * then 'system' and finally 'default'). + * + * @var array layer => array(keyname => value, ...) + */ + var $configuration = array( + 'user' => array(), + 'system' => array(), + 'default' => array(), + ); - // first, list the immediate parents of each package to be uninstalled - $perpackagelist = array(); - $allparents = array(); - foreach ($params as $i => $param) { - $a = array( - 'channel' => strtolower($param->getChannel()), - 'package' => strtolower($param->getPackage()) - ); + /** + * Configuration values that can be set for a channel + * + * All other configuration values can only have a global value + * @var array + * @access private + */ + var $_channelConfigInfo = array( + 'php_dir', 'ext_dir', 'doc_dir', 'bin_dir', 'data_dir', 'cfg_dir', + 'test_dir', 'www_dir', 'php_bin', 'php_prefix', 'php_suffix', 'username', + 'password', 'verbose', 'preferred_state', 'umask', 'preferred_mirror', 'php_ini' + ); - $deps = $this->_dependencydb->getDependentPackages($a); - if ($deps) { - foreach ($deps as $d) { - $pardeps = $this->_dependencydb->getDependencies($d); - foreach ($pardeps as $dep) { - if (strtolower($dep['dep']['channel']) == $a['channel'] && - strtolower($dep['dep']['name']) == $a['package']) { - if (!isset($perpackagelist[$a['channel'] . '/' . $a['package']])) { - $perpackagelist[$a['channel'] . '/' . $a['package']] = array(); - } - $perpackagelist[$a['channel'] . '/' . $a['package']][] - = array($d['channel'] . '/' . $d['package'], $dep); - if (!isset($allparents[$d['channel'] . '/' . $d['package']])) { - $allparents[$d['channel'] . '/' . $d['package']] = array(); - } - if (!isset($allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']])) { - $allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']] = array(); - } - $allparents[$d['channel'] . '/' . $d['package']] - [$a['channel'] . '/' . $a['package']][] - = array($d, $dep); - } - } - } - } - } + /** + * Channels that can be accessed + * @see setChannels() + * @var array + * @access private + */ + var $_channels = array('pear.php.net', 'pecl.php.net', '__uri'); - // next, remove any packages from the parents list that are not installed - $remove = array(); - foreach ($allparents as $parent => $d1) { - foreach ($d1 as $d) { - if ($this->_registry->packageExists($d[0][0]['package'], $d[0][0]['channel'])) { - continue; - } - $remove[$parent] = true; - } - } + /** + * This variable is used to control the directory values returned + * @see setInstallRoot(); + * @var string|false + * @access private + */ + var $_installRoot = false; - // next remove any packages from the parents list that are not passed in for - // uninstallation - foreach ($allparents as $parent => $d1) { - foreach ($d1 as $d) { - foreach ($params as $param) { - if (strtolower($param->getChannel()) == $d[0][0]['channel'] && - strtolower($param->getPackage()) == $d[0][0]['package']) { - // found it - continue 3; - } - } - $remove[$parent] = true; - } - } + /** + * If requested, this will always refer to the registry + * contained in php_dir + * @var PEAR_Registry + */ + var $_registry = array(); - // remove all packages whose dependencies fail - // save which ones failed for error reporting - $badchildren = array(); - do { - $fail = false; - foreach ($remove as $package => $unused) { - if (!isset($allparents[$package])) { - continue; - } + /** + * @var array + * @access private + */ + var $_regInitialized = array(); - foreach ($allparents[$package] as $kid => $d1) { - foreach ($d1 as $depinfo) { - if ($depinfo[1]['type'] != 'optional') { - if (isset($badchildren[$kid])) { - continue; - } - $badchildren[$kid] = true; - $remove[$kid] = true; - $fail = true; - continue 2; - } - } - } - if ($fail) { - // start over, we removed some children - continue 2; - } - } - } while ($fail); + /** + * @var bool + * @access private + */ + var $_noRegistry = false; - // next, construct the list of packages that can't be uninstalled - $badpackages = array(); - $save = $this->_currentPackage; - foreach ($perpackagelist as $package => $packagedeps) { - foreach ($packagedeps as $parent) { - if (!isset($remove[$parent[0]])) { - continue; - } + /** + * amount of errors found while parsing config + * @var integer + * @access private + */ + var $_errorsFound = 0; + var $_lastError = null; - $packagename = $this->_registry->parsePackageName($parent[0]); - $packagename['channel'] = $this->_registry->channelAlias($packagename['channel']); - $pa = $this->_registry->getPackage($packagename['package'], $packagename['channel']); - $packagename['package'] = $pa->getPackage(); - $this->_currentPackage = $packagename; - // parent is not present in uninstall list, make sure we can actually - // uninstall it (parent dep is optional) - $parentname['channel'] = $this->_registry->channelAlias($parent[1]['dep']['channel']); - $pa = $this->_registry->getPackage($parent[1]['dep']['name'], $parent[1]['dep']['channel']); - $parentname['package'] = $pa->getPackage(); - $parent[1]['dep']['package'] = $parentname['package']; - $parent[1]['dep']['channel'] = $parentname['channel']; - if ($parent[1]['type'] == 'optional') { - $test = $this->_validatePackageUninstall($parent[1]['dep'], false, $dl); - if ($test !== true) { - $badpackages[$package]['warnings'][] = $test; - } - } else { - $test = $this->_validatePackageUninstall($parent[1]['dep'], true, $dl); - if ($test !== true) { - $badpackages[$package]['errors'][] = $test; - } - } - } - } - - $this->_currentPackage = $save; - $dl->___uninstall_package_cache = $badpackages; - if (isset($badpackages[$memyselfandI])) { - if (isset($badpackages[$memyselfandI]['warnings'])) { - foreach ($badpackages[$memyselfandI]['warnings'] as $warning) { - $dl->log(0, $warning[0]); - } - } - - if (isset($badpackages[$memyselfandI]['errors'])) { - foreach ($badpackages[$memyselfandI]['errors'] as $error) { - if (is_array($error)) { - $dl->log(0, $error[0]); - } else { - $dl->log(0, $error->getMessage()); - } - } - - if (isset($this->_options['nodeps']) || isset($this->_options['force'])) { - return $this->warning( - 'warning: %s should not be uninstalled, other installed packages depend ' . - 'on this package'); - } - - return $this->raiseError( - '%s cannot be uninstalled, other installed packages depend on this package'); - } - } - - return true; - } + /** + * Information about the configuration data. Stores the type, + * default value and a documentation string for each configuration + * value. + * + * @var array layer => array(infotype => value, ...) + */ + var $configuration_info = array( + // Channels/Internet Access + 'default_channel' => array( + 'type' => 'string', + 'default' => PEAR_CONFIG_DEFAULT_CHANNEL, + 'doc' => 'the default channel to use for all non explicit commands', + 'prompt' => 'Default Channel', + 'group' => 'Internet Access', + ), + 'preferred_mirror' => array( + 'type' => 'string', + 'default' => PEAR_CONFIG_DEFAULT_CHANNEL, + 'doc' => 'the default server or mirror to use for channel actions', + 'prompt' => 'Default Channel Mirror', + 'group' => 'Internet Access', + ), + 'remote_config' => array( + 'type' => 'password', + 'default' => '', + 'doc' => 'ftp url of remote configuration file to use for synchronized install', + 'prompt' => 'Remote Configuration File', + 'group' => 'Internet Access', + ), + 'auto_discover' => array( + 'type' => 'integer', + 'default' => 0, + 'doc' => 'whether to automatically discover new channels', + 'prompt' => 'Auto-discover new Channels', + 'group' => 'Internet Access', + ), + // Internet Access + 'master_server' => array( + 'type' => 'string', + 'default' => 'pear.php.net', + 'doc' => 'name of the main PEAR server [NOT USED IN THIS VERSION]', + 'prompt' => 'PEAR server [DEPRECATED]', + 'group' => 'Internet Access', + ), + 'http_proxy' => array( + 'type' => 'string', + 'default' => PEAR_CONFIG_DEFAULT_HTTP_PROXY, + 'doc' => 'HTTP proxy (host:port) to use when downloading packages', + 'prompt' => 'HTTP Proxy Server Address', + 'group' => 'Internet Access', + ), + // File Locations + 'php_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_PHP_DIR, + 'doc' => 'directory where .php files are installed', + 'prompt' => 'PEAR directory', + 'group' => 'File Locations', + ), + 'ext_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_EXT_DIR, + 'doc' => 'directory where loadable extensions are installed', + 'prompt' => 'PHP extension directory', + 'group' => 'File Locations', + ), + 'doc_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_DOC_DIR, + 'doc' => 'directory where documentation is installed', + 'prompt' => 'PEAR documentation directory', + 'group' => 'File Locations', + ), + 'bin_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_BIN_DIR, + 'doc' => 'directory where executables are installed', + 'prompt' => 'PEAR executables directory', + 'group' => 'File Locations', + ), + 'data_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_DATA_DIR, + 'doc' => 'directory where data files are installed', + 'prompt' => 'PEAR data directory', + 'group' => 'File Locations (Advanced)', + ), + 'cfg_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_CFG_DIR, + 'doc' => 'directory where modifiable configuration files are installed', + 'prompt' => 'PEAR configuration file directory', + 'group' => 'File Locations (Advanced)', + ), + 'www_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_WWW_DIR, + 'doc' => 'directory where www frontend files (html/js) are installed', + 'prompt' => 'PEAR www files directory', + 'group' => 'File Locations (Advanced)', + ), + 'test_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_TEST_DIR, + 'doc' => 'directory where regression tests are installed', + 'prompt' => 'PEAR test directory', + 'group' => 'File Locations (Advanced)', + ), + 'cache_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_CACHE_DIR, + 'doc' => 'directory which is used for web service cache', + 'prompt' => 'PEAR Installer cache directory', + 'group' => 'File Locations (Advanced)', + ), + 'temp_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_TEMP_DIR, + 'doc' => 'directory which is used for all temp files', + 'prompt' => 'PEAR Installer temp directory', + 'group' => 'File Locations (Advanced)', + ), + 'download_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR, + 'doc' => 'directory which is used for all downloaded files', + 'prompt' => 'PEAR Installer download directory', + 'group' => 'File Locations (Advanced)', + ), + 'php_bin' => array( + 'type' => 'file', + 'default' => PEAR_CONFIG_DEFAULT_PHP_BIN, + 'doc' => 'PHP CLI/CGI binary for executing scripts', + 'prompt' => 'PHP CLI/CGI binary', + 'group' => 'File Locations (Advanced)', + ), + 'php_prefix' => array( + 'type' => 'string', + 'default' => '', + 'doc' => '--program-prefix for php_bin\'s ./configure, used for pecl installs', + 'prompt' => '--program-prefix passed to PHP\'s ./configure', + 'group' => 'File Locations (Advanced)', + ), + 'php_suffix' => array( + 'type' => 'string', + 'default' => '', + 'doc' => '--program-suffix for php_bin\'s ./configure, used for pecl installs', + 'prompt' => '--program-suffix passed to PHP\'s ./configure', + 'group' => 'File Locations (Advanced)', + ), + 'php_ini' => array( + 'type' => 'file', + 'default' => '', + 'doc' => 'location of php.ini in which to enable PECL extensions on install', + 'prompt' => 'php.ini location', + 'group' => 'File Locations (Advanced)', + ), + // Maintainers + 'username' => array( + 'type' => 'string', + 'default' => '', + 'doc' => '(maintainers) your PEAR account name', + 'prompt' => 'PEAR username (for maintainers)', + 'group' => 'Maintainers', + ), + 'password' => array( + 'type' => 'password', + 'default' => '', + 'doc' => '(maintainers) your PEAR account password', + 'prompt' => 'PEAR password (for maintainers)', + 'group' => 'Maintainers', + ), + // Advanced + 'verbose' => array( + 'type' => 'integer', + 'default' => PEAR_CONFIG_DEFAULT_VERBOSE, + 'doc' => 'verbosity level +0: really quiet +1: somewhat quiet +2: verbose +3: debug', + 'prompt' => 'Debug Log Level', + 'group' => 'Advanced', + ), + 'preferred_state' => array( + 'type' => 'set', + 'default' => PEAR_CONFIG_DEFAULT_PREFERRED_STATE, + 'doc' => 'the installer will prefer releases with this state when installing packages without a version or state specified', + 'valid_set' => array( + 'stable', 'beta', 'alpha', 'devel', 'snapshot'), + 'prompt' => 'Preferred Package State', + 'group' => 'Advanced', + ), + 'umask' => array( + 'type' => 'mask', + 'default' => PEAR_CONFIG_DEFAULT_UMASK, + 'doc' => 'umask used when creating files (Unix-like systems only)', + 'prompt' => 'Unix file mask', + 'group' => 'Advanced', + ), + 'cache_ttl' => array( + 'type' => 'integer', + 'default' => PEAR_CONFIG_DEFAULT_CACHE_TTL, + 'doc' => 'amount of secs where the local cache is used and not updated', + 'prompt' => 'Cache TimeToLive', + 'group' => 'Advanced', + ), + 'sig_type' => array( + 'type' => 'set', + 'default' => PEAR_CONFIG_DEFAULT_SIG_TYPE, + 'doc' => 'which package signature mechanism to use', + 'valid_set' => array('gpg'), + 'prompt' => 'Package Signature Type', + 'group' => 'Maintainers', + ), + 'sig_bin' => array( + 'type' => 'string', + 'default' => PEAR_CONFIG_DEFAULT_SIG_BIN, + 'doc' => 'which package signature mechanism to use', + 'prompt' => 'Signature Handling Program', + 'group' => 'Maintainers', + ), + 'sig_keyid' => array( + 'type' => 'string', + 'default' => '', + 'doc' => 'which key to use for signing with', + 'prompt' => 'Signature Key Id', + 'group' => 'Maintainers', + ), + 'sig_keydir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_SIG_KEYDIR, + 'doc' => 'directory where signature keys are located', + 'prompt' => 'Signature Key Directory', + 'group' => 'Maintainers', + ), + // __channels is reserved - used for channel-specific configuration + ); - function _validatePackageUninstall($dep, $required, $dl) + /** + * Constructor. + * + * @param string file to read user-defined options from + * @param string file to read system-wide defaults from + * @param bool determines whether a registry object "follows" + * the value of php_dir (is automatically created + * and moved when php_dir is changed) + * @param bool if true, fails if configuration files cannot be loaded + * + * @access public + * + * @see PEAR_Config::singleton + */ + function PEAR_Config($user_file = '', $system_file = '', $ftp_file = false, + $strict = true) { - $depname = $this->_registry->parsedPackageNameToString($dep, true); - $version = $this->_registry->packageinfo($dep['package'], 'version', $dep['channel']); - if (!$version) { - return true; - } - - $extra = $this->_getExtraString($dep); - if (isset($dep['exclude']) && !is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); + $this->PEAR(); + PEAR_Installer_Role::initializeConfig($this); + $sl = DIRECTORY_SEPARATOR; + if (empty($user_file)) { + if (OS_WINDOWS) { + $user_file = PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini'; + } else { + $user_file = getenv('HOME') . $sl . '.pearrc'; + } } - if (isset($dep['conflicts'])) { - return true; // uninstall OK - these packages conflict (probably installed with --force) + if (empty($system_file)) { + $system_file = PEAR_CONFIG_SYSCONFDIR . $sl; + if (OS_WINDOWS) { + $system_file .= 'pearsys.ini'; + } else { + $system_file .= 'pear.conf'; + } } - if (!isset($dep['min']) && !isset($dep['max'])) { - if (!$required) { - return $this->warning('"' . $depname . '" can be optionally used by ' . - 'installed package %s' . $extra); + $this->layers = array_keys($this->configuration); + $this->files['user'] = $user_file; + $this->files['system'] = $system_file; + if ($user_file && file_exists($user_file)) { + $this->pushErrorHandling(PEAR_ERROR_RETURN); + $this->readConfigFile($user_file, 'user', $strict); + $this->popErrorHandling(); + if ($this->_errorsFound > 0) { + return; } + } - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('"' . $depname . '" is required by ' . - 'installed package %s' . $extra); + if ($system_file && @file_exists($system_file)) { + $this->mergeConfigFile($system_file, false, 'system', $strict); + if ($this->_errorsFound > 0) { + return; } - return $this->warning('warning: "' . $depname . '" is required by ' . - 'installed package %s' . $extra); } - $fail = false; - if (isset($dep['min']) && version_compare($version, $dep['min'], '>=')) { - $fail = true; + if (!$ftp_file) { + $ftp_file = $this->get('remote_config'); } - if (isset($dep['max']) && version_compare($version, $dep['max'], '<=')) { - $fail = true; + if ($ftp_file && defined('PEAR_REMOTEINSTALL_OK')) { + $this->readFTPConfigFile($ftp_file); } - // we re-use this variable, preserve the original value - $saverequired = $required; - if (!$required) { - return $this->warning($depname . $extra . ' can be optionally used by installed package' . - ' "%s"'); + foreach ($this->configuration_info as $key => $info) { + $this->configuration['default'][$key] = $info['default']; } - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError($depname . $extra . ' is required by installed package' . - ' "%s"'); + $this->_registry['default'] = &new PEAR_Registry($this->configuration['default']['php_dir']); + $this->_registry['default']->setConfig($this, false); + $this->_regInitialized['default'] = false; + //$GLOBALS['_PEAR_Config_instance'] = &$this; + } + + /** + * Return the default locations of user and system configuration files + * @static + */ + function getDefaultConfigFiles() + { + $sl = DIRECTORY_SEPARATOR; + if (OS_WINDOWS) { + return array( + 'user' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini', + 'system' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pearsys.ini' + ); } - return $this->raiseError('warning: ' . $depname . $extra . - ' is required by installed package "%s"'); + return array( + 'user' => getenv('HOME') . $sl . '.pearrc', + 'system' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.conf' + ); } /** - * validate a downloaded package against installed packages + * Static singleton method. If you want to keep only one instance + * of this class in use, this method will give you a reference to + * the last created PEAR_Config object if one exists, or create a + * new object. * - * As of PEAR 1.4.3, this will only validate + * @param string (optional) file to read user-defined options from + * @param string (optional) file to read system-wide defaults from * - * @param array|PEAR_Downloader_Package|PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * $pkg package identifier (either - * array('package' => blah, 'channel' => blah) or an array with - * index 'info' referencing an object) - * @param PEAR_Downloader $dl - * @param array $params full list of packages to install - * @return true|PEAR_Error + * @return object an existing or new PEAR_Config instance + * + * @access public + * + * @see PEAR_Config::PEAR_Config */ - function validatePackage($pkg, &$dl, $params = array()) + function &singleton($user_file = '', $system_file = '', $strict = true) { - if (is_array($pkg) && isset($pkg['info'])) { - $deps = $this->_dependencydb->getDependentPackageDependencies($pkg['info']); - } else { - $deps = $this->_dependencydb->getDependentPackageDependencies($pkg); - } - - $fail = false; - if ($deps) { - if (!class_exists('PEAR_Downloader_Package')) { - require_once 'PEAR/Downloader/Package.php'; - } - - $dp = &new PEAR_Downloader_Package($dl); - if (is_object($pkg)) { - $dp->setPackageFile($pkg); - } else { - $dp->setDownloadURL($pkg); - } - - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - foreach ($deps as $channel => $info) { - foreach ($info as $package => $ds) { - foreach ($params as $packd) { - if (strtolower($packd->getPackage()) == strtolower($package) && - $packd->getChannel() == $channel) { - $dl->log(3, 'skipping installed package check of "' . - $this->_registry->parsedPackageNameToString( - array('channel' => $channel, 'package' => $package), - true) . - '", version "' . $packd->getVersion() . '" will be ' . - 'downloaded and installed'); - continue 2; // jump to next package - } - } - - foreach ($ds as $d) { - $checker = &new PEAR_Dependency2($this->_config, $this->_options, - array('channel' => $channel, 'package' => $package), $this->_state); - $dep = $d['dep']; - $required = $d['type'] == 'required'; - $ret = $checker->_validatePackageDownload($dep, $required, array(&$dp)); - if (is_array($ret)) { - $dl->log(0, $ret[0]); - } elseif (PEAR::isError($ret)) { - $dl->log(0, $ret->getMessage()); - $fail = true; - } - } - } - } - PEAR::popErrorHandling(); + if (is_object($GLOBALS['_PEAR_Config_instance'])) { + return $GLOBALS['_PEAR_Config_instance']; } - if ($fail) { - return $this->raiseError( - '%s cannot be installed, conflicts with installed packages'); + $t_conf = &new PEAR_Config($user_file, $system_file, false, $strict); + if ($t_conf->_errorsFound > 0) { + return $t_conf->lastError; } - return true; + $GLOBALS['_PEAR_Config_instance'] = &$t_conf; + return $GLOBALS['_PEAR_Config_instance']; } /** - * validate a package.xml 1.0 dependency + * Determine whether any configuration files have been detected, and whether a + * registry object can be retrieved from this configuration. + * @return bool + * @since PEAR 1.4.0a1 */ - function validateDependency1($dep, $params = array()) + function validConfiguration() { - if (!isset($dep['optional'])) { - $dep['optional'] = 'no'; - } - - list($newdep, $type) = $this->normalizeDep($dep); - if (!$newdep) { - return $this->raiseError("Invalid Dependency"); + if ($this->isDefinedLayer('user') || $this->isDefinedLayer('system')) { + return true; } - if (method_exists($this, "validate{$type}Dependency")) { - return $this->{"validate{$type}Dependency"}($newdep, $dep['optional'] == 'no', - $params, true); - } + return false; } /** - * Convert a 1.0 dep into a 2.0 dep + * Reads configuration data from a file. All existing values in + * the config layer are discarded and replaced with data from the + * file. + * @param string file to read from, if NULL or not specified, the + * last-used file for the same layer (second param) is used + * @param string config layer to insert data into ('user' or 'system') + * @return bool TRUE on success or a PEAR error on failure */ - function normalizeDep($dep) + function readConfigFile($file = null, $layer = 'user', $strict = true) { - $types = array( - 'pkg' => 'Package', - 'ext' => 'Extension', - 'os' => 'Os', - 'php' => 'Php' - ); + if (empty($this->files[$layer])) { + return $this->raiseError("unknown config layer `$layer'"); + } - if (!isset($types[$dep['type']])) { - return array(false, false); + if ($file === null) { + $file = $this->files[$layer]; } - $type = $types[$dep['type']]; + $data = $this->_readConfigDataFrom($file); + if (PEAR::isError($data)) { + if (!$strict) { + return true; + } - $newdep = array(); - switch ($type) { - case 'Package' : - $newdep['channel'] = 'pear.php.net'; - case 'Extension' : - case 'Os' : - $newdep['name'] = $dep['name']; - break; - } + $this->_errorsFound++; + $this->lastError = $data; - $dep['rel'] = PEAR_Dependency2::signOperator($dep['rel']); - switch ($dep['rel']) { - case 'has' : - return array($newdep, $type); - break; - case 'not' : - $newdep['conflicts'] = true; - break; - case '>=' : - case '>' : - $newdep['min'] = $dep['version']; - if ($dep['rel'] == '>') { - $newdep['exclude'] = $dep['version']; - } - break; - case '<=' : - case '<' : - $newdep['max'] = $dep['version']; - if ($dep['rel'] == '<') { - $newdep['exclude'] = $dep['version']; - } - break; - case 'ne' : - case '!=' : - $newdep['min'] = '0'; - $newdep['max'] = '100000'; - $newdep['exclude'] = $dep['version']; - break; - case '==' : - $newdep['min'] = $dep['version']; - $newdep['max'] = $dep['version']; - break; + return $data; } - if ($type == 'Php') { - if (!isset($newdep['min'])) { - $newdep['min'] = '4.4.0'; - } - if (!isset($newdep['max'])) { - $newdep['max'] = '6.0.0'; - } + $this->files[$layer] = $file; + $this->_decodeInput($data); + $this->configuration[$layer] = $data; + $this->_setupChannels(); + if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) { + $this->_registry[$layer] = &new PEAR_Registry($phpdir); + $this->_registry[$layer]->setConfig($this, false); + $this->_regInitialized[$layer] = false; + } else { + unset($this->_registry[$layer]); } - return array($newdep, $type); + return true; } /** - * Converts text comparing operators to them sign equivalents - * - * Example: 'ge' to '>=' - * - * @access public - * @param string Operator - * @return string Sign equivalent + * @param string url to the remote config file, like ftp://www.example.com/pear/config.ini + * @return true|PEAR_Error */ - function signOperator($operator) + function readFTPConfigFile($path) { - switch($operator) { - case 'lt': return '<'; - case 'le': return '<='; - case 'gt': return '>'; - case 'ge': return '>='; - case 'eq': return '=='; - case 'ne': return '!='; - default: - return $operator; - } - } + do { // poor man's try + if (!class_exists('PEAR_FTP')) { + if (!class_exists('PEAR_Common')) { + require_once 'PEAR/Common.php'; + } + if (PEAR_Common::isIncludeable('PEAR/FTP.php')) { + require_once 'PEAR/FTP.php'; + } + } - function raiseError($msg) - { - if (isset($this->_options['ignore-errors'])) { - return $this->warning($msg); - } + if (!class_exists('PEAR_FTP')) { + return PEAR::raiseError('PEAR_RemoteInstaller must be installed to use remote config'); + } - return PEAR::raiseError(sprintf($msg, $this->_registry->parsedPackageNameToString( - $this->_currentPackage, true))); - } + $this->_ftp = &new PEAR_FTP; + $this->_ftp->pushErrorHandling(PEAR_ERROR_RETURN); + $e = $this->_ftp->init($path); + if (PEAR::isError($e)) { + $this->_ftp->popErrorHandling(); + return $e; + } - function warning($msg) - { - return array(sprintf($msg, $this->_registry->parsedPackageNameToString( - $this->_currentPackage, true))); - } -}PEAR-1.8.0/PEAR/Downloader.php100664 764 764 202344 100664 10710 - * @author Stig Bakken - * @author Tomas V. V. Cox - * @author Martin Jansen - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Downloader.php,v 1.159 2009/03/08 04:01:08 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.3.0 - */ + $tmp = System::mktemp('-d'); + PEAR_Common::addTempFile($tmp); + $e = $this->_ftp->get(basename($path), $tmp . DIRECTORY_SEPARATOR . + 'pear.ini', false, FTP_BINARY); + if (PEAR::isError($e)) { + $this->_ftp->popErrorHandling(); + return $e; + } -/** - * Needed for constants, extending - */ -require_once 'PEAR/Common.php'; + PEAR_Common::addTempFile($tmp . DIRECTORY_SEPARATOR . 'pear.ini'); + $this->_ftp->disconnect(); + $this->_ftp->popErrorHandling(); + $this->files['ftp'] = $tmp . DIRECTORY_SEPARATOR . 'pear.ini'; + $e = $this->readConfigFile(null, 'ftp'); + if (PEAR::isError($e)) { + return $e; + } -define('PEAR_INSTALLER_OK', 1); -define('PEAR_INSTALLER_FAILED', 0); -define('PEAR_INSTALLER_SKIPPED', -1); -define('PEAR_INSTALLER_ERROR_NO_PREF_STATE', 2); + $fail = array(); + foreach ($this->configuration_info as $key => $val) { + if (in_array($this->getGroup($key), + array('File Locations', 'File Locations (Advanced)')) && + $this->getType($key) == 'directory') { + // any directory configs must be set for this to work + if (!isset($this->configuration['ftp'][$key])) { + $fail[] = $key; + } + } + } -/** - * Administration class used to download anything from the internet (PEAR Packages, - * static URLs, xml files) - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @author Stig Bakken - * @author Tomas V. V. Cox - * @author Martin Jansen - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.3.0 - */ -class PEAR_Downloader extends PEAR_Common -{ - /** - * @var PEAR_Registry - * @access private - */ - var $_registry; + if (!count($fail)) { + return true; + } - /** - * Preferred Installation State (snapshot, devel, alpha, beta, stable) - * @var string|null - * @access private - */ - var $_preferredState; + $fail = '"' . implode('", "', $fail) . '"'; + unset($this->files['ftp']); + unset($this->configuration['ftp']); + return PEAR::raiseError('ERROR: Ftp configuration file must set all ' . + 'directory configuration variables. These variables were not set: ' . + $fail); + } while (false); // poor man's catch + unset($this->files['ftp']); + return PEAR::raiseError('no remote host specified'); + } /** - * Options from command-line passed to Install. - * - * Recognized options:
- * - onlyreqdeps : install all required dependencies as well - * - alldeps : install all dependencies, including optional - * - installroot : base relative path to install files in - * - force : force a download even if warnings would prevent it - * - nocompress : download uncompressed tarballs - * @see PEAR_Command_Install - * @access private - * @var array + * Reads the existing configurations and creates the _channels array from it */ - var $_options; + function _setupChannels() + { + $set = array_flip(array_values($this->_channels)); + foreach ($this->configuration as $layer => $data) { + $i = 1000; + if (isset($data['__channels']) && is_array($data['__channels'])) { + foreach ($data['__channels'] as $channel => $info) { + $set[$channel] = $i++; + } + } + } + $this->_channels = array_values(array_flip($set)); + $this->setChannels($this->_channels); + } - /** - * Downloaded Packages after a call to download(). - * - * Format of each entry: - * - * - * array('pkg' => 'package_name', 'file' => '/path/to/local/file', - * 'info' => array() // parsed package.xml - * ); - * - * @access private - * @var array - */ - var $_downloadedPackages = array(); + function deleteChannel($channel) + { + $ch = strtolower($channel); + foreach ($this->configuration as $layer => $data) { + if (isset($data['__channels']) && isset($data['__channels'][$ch])) { + unset($this->configuration[$layer]['__channels'][$ch]); + } + } - /** - * Packages slated for download. - * - * This is used to prevent downloading a package more than once should it be a dependency - * for two packages to be installed. - * Format of each entry: - * - *
-     * array('package_name1' => parsed package.xml, 'package_name2' => parsed package.xml,
-     * );
-     * 
- * @access private - * @var array - */ - var $_toDownload = array(); + $this->_channels = array_flip($this->_channels); + unset($this->_channels[$ch]); + $this->_channels = array_flip($this->_channels); + } /** - * Array of every package installed, with names lower-cased. - * - * Format: - * - * array('package1' => 0, 'package2' => 1, ); - * - * @var array + * Merges data into a config layer from a file. Does the same + * thing as readConfigFile, except it does not replace all + * existing values in the config layer. + * @param string file to read from + * @param bool whether to overwrite existing data (default TRUE) + * @param string config layer to insert data into ('user' or 'system') + * @param string if true, errors are returned if file opening fails + * @return bool TRUE on success or a PEAR error on failure */ - var $_installed = array(); + function mergeConfigFile($file, $override = true, $layer = 'user', $strict = true) + { + if (empty($this->files[$layer])) { + return $this->raiseError("unknown config layer `$layer'"); + } - /** - * @var array - * @access private - */ - var $_errorStack = array(); + if ($file === null) { + $file = $this->files[$layer]; + } - /** - * @var boolean - * @access private - */ - var $_internalDownload = false; + $data = $this->_readConfigDataFrom($file); + if (PEAR::isError($data)) { + if (!$strict) { + return true; + } - /** - * Temporary variable used in sorting packages by dependency in {@link sortPkgDeps()} - * @var array - * @access private - */ - var $_packageSortTree; + $this->_errorsFound++; + $this->lastError = $data; - /** - * Temporary directory, or configuration value where downloads will occur - * @var string - */ - var $_downloadDir; - // {{{ PEAR_Downloader() + return $data; + } - /** - * @param PEAR_Frontend_* - * @param array - * @param PEAR_Config - */ - function PEAR_Downloader(&$ui, $options, &$config) - { - parent::PEAR_Common(); - $this->_options = $options; - $this->config = &$config; - $this->_preferredState = $this->config->get('preferred_state'); - $this->ui = &$ui; - if (!$this->_preferredState) { - // don't inadvertantly use a non-set preferred_state - $this->_preferredState = null; + $this->_decodeInput($data); + if ($override) { + $this->configuration[$layer] = + PEAR_Config::arrayMergeRecursive($this->configuration[$layer], $data); + } else { + $this->configuration[$layer] = + PEAR_Config::arrayMergeRecursive($data, $this->configuration[$layer]); } - if (isset($this->_options['installroot'])) { - $this->config->setInstallRoot($this->_options['installroot']); + $this->_setupChannels(); + if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) { + $this->_registry[$layer] = &new PEAR_Registry($phpdir); + $this->_registry[$layer]->setConfig($this, false); + $this->_regInitialized[$layer] = false; + } else { + unset($this->_registry[$layer]); } - $this->_registry = &$config->getRegistry(); + return true; + } - if (isset($this->_options['alldeps']) || isset($this->_options['onlyreqdeps'])) { - $this->_installed = $this->_registry->listAllPackages(); - foreach ($this->_installed as $key => $unused) { - if (!count($unused)) { + /** + * @param array + * @param array + * @return array + * @static + */ + function arrayMergeRecursive($arr2, $arr1) + { + $ret = array(); + foreach ($arr2 as $key => $data) { + if (!isset($arr1[$key])) { + $ret[$key] = $data; + unset($arr1[$key]); + continue; + } + if (is_array($data)) { + if (!is_array($arr1[$key])) { + $ret[$key] = $arr1[$key]; + unset($arr1[$key]); continue; } - $strtolower = create_function('$a','return strtolower($a);'); - array_walk($this->_installed[$key], $strtolower); + $ret[$key] = PEAR_Config::arrayMergeRecursive($arr1[$key], $arr2[$key]); + unset($arr1[$key]); } } + + return array_merge($ret, $arr1); } /** - * Attempt to discover a channel's remote capabilities from - * its server name - * @param string - * @return boolean + * Writes data into a config layer from a file. + * + * @param string|null file to read from, or null for default + * @param string config layer to insert data into ('user' or + * 'system') + * @param string|null data to write to config file or null for internal data [DEPRECATED] + * @return bool TRUE on success or a PEAR error on failure */ - function discover($channel) + function writeConfigFile($file = null, $layer = 'user', $data = null) { - $this->log(1, 'Attempting to discover channel "' . $channel . '"...'); - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $callback = $this->ui ? array(&$this, '_downloadCallback') : null; - if (!class_exists('System')) { - require_once 'System.php'; + $this->_lazyChannelSetup($layer); + if ($layer == 'both' || $layer == 'all') { + foreach ($this->files as $type => $file) { + $err = $this->writeConfigFile($file, $type, $data); + if (PEAR::isError($err)) { + return $err; + } + } + return true; } - $tmp = System::mktemp(array('-d')); - $a = $this->downloadHttp('http://' . $channel . '/channel.xml', $this->ui, $tmp, $callback, false); - PEAR::popErrorHandling(); - if (PEAR::isError($a)) { - // Attempt to fallback to https automatically. - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $this->log(1, 'Attempting fallback to https instead of http on channel "' . $channel . '"...'); - $a = $this->downloadHttp('https://' . $channel . '/channel.xml', $this->ui, $tmp, $callback, false); - PEAR::popErrorHandling(); - if (PEAR::isError($a)) { - return false; - } + if (empty($this->files[$layer])) { + return $this->raiseError("unknown config file type `$layer'"); } - list($a, $lastmodified) = $a; - if (!class_exists('PEAR_ChannelFile')) { - require_once 'PEAR/ChannelFile.php'; + if ($file === null) { + $file = $this->files[$layer]; } - $b = new PEAR_ChannelFile; - if ($b->fromXmlFile($a)) { - unlink($a); - if ($this->config->get('auto_discover')) { - $this->_registry->addChannel($b, $lastmodified); - $alias = $b->getName(); - if ($b->getName() == $this->_registry->channelName($b->getAlias())) { - $alias = $b->getAlias(); - } + $data = ($data === null) ? $this->configuration[$layer] : $data; + $this->_encodeOutput($data); + $opt = array('-p', dirname($file)); + if (!@System::mkDir($opt)) { + return $this->raiseError("could not create directory: " . dirname($file)); + } - $this->log(1, 'Auto-discovered channel "' . $channel . - '", alias "' . $alias . '", adding to registry'); - } + if (file_exists($file) && is_file($file) && !is_writeable($file)) { + return $this->raiseError("no write access to $file!"); + } - return true; + $fp = @fopen($file, "w"); + if (!$fp) { + return $this->raiseError("PEAR_Config::writeConfigFile fopen('$file','w') failed ($php_errormsg)"); } - unlink($a); - return false; + $contents = "#PEAR_Config 0.9\n" . serialize($data); + if (!@fwrite($fp, $contents)) { + return $this->raiseError("PEAR_Config::writeConfigFile: fwrite failed ($php_errormsg)"); + } + return true; } /** - * For simpler unit-testing - * @param PEAR_Downloader - * @return PEAR_Downloader_Package + * Reads configuration data from a file and returns the parsed data + * in an array. + * + * @param string file to read from + * @return array configuration data or a PEAR error on failure + * @access private */ - function &newDownloaderPackage(&$t) + function _readConfigDataFrom($file) { - if (!class_exists('PEAR_Downloader_Package')) { - require_once 'PEAR/Downloader/Package.php'; + $fp = false; + if (file_exists($file)) { + $fp = @fopen($file, "r"); } - $a = &new PEAR_Downloader_Package($t); - return $a; - } - /** - * For simpler unit-testing - * @param PEAR_Config - * @param array - * @param array - * @param int - */ - function &getDependency2Object(&$c, $i, $p, $s) - { - if (!class_exists('PEAR_Dependency2')) { - require_once 'PEAR/Dependency2.php'; + if (!$fp) { + return $this->raiseError("PEAR_Config::readConfigFile fopen('$file','r') failed"); } - $z = &new PEAR_Dependency2($c, $i, $p, $s); - return $z; - } - function &download($params) - { - if (!count($params)) { - $a = array(); - return $a; + $size = filesize($file); + $rt = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + fclose($fp); + $contents = file_get_contents($file); + if (empty($contents)) { + return $this->raiseError('Configuration file "' . $file . '" is empty'); } - if (!isset($this->_registry)) { - $this->_registry = &$this->config->getRegistry(); - } + set_magic_quotes_runtime($rt); - $channelschecked = array(); - // convert all parameters into PEAR_Downloader_Package objects - foreach ($params as $i => $param) { - $params[$i] = &$this->newDownloaderPackage($this); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $err = $params[$i]->initialize($param); - PEAR::staticPopErrorHandling(); - if (!$err) { - // skip parameters that were missed by preferred_state - continue; + $version = false; + if (preg_match('/^#PEAR_Config\s+(\S+)\s+/si', $contents, $matches)) { + $version = $matches[1]; + $contents = substr($contents, strlen($matches[0])); + } else { + // Museum config file + if (substr($contents,0,2) == 'a:') { + $version = '0.1'; } + } - if (PEAR::isError($err)) { - if (!isset($this->_options['soft']) && $err->getMessage() !== '') { - $this->log(0, $err->getMessage()); - } + if ($version && version_compare("$version", '1', '<')) { + // no '@', it is possible that unserialize + // raises a notice but it seems to block IO to + // STDOUT if a '@' is used and a notice is raise + $data = unserialize($contents); - $params[$i] = false; - if (is_object($param)) { - $param = $param->getChannel() . '/' . $param->getPackage(); + if (!is_array($data) && !$data) { + if ($contents == serialize(false)) { + $data = array(); + } else { + $err = $this->raiseError("PEAR_Config: bad data in $file"); + return $err; } - - if (!isset($this->_options['soft'])) { - $this->log(2, 'Package "' . $param . '" is not valid'); + } + if (!is_array($data)) { + if (strlen(trim($contents)) > 0) { + $error = "PEAR_Config: bad data in $file"; + $err = $this->raiseError($error); + return $err; } - // Message logged above in a specific verbose mode, passing null to not show up on CLI - $this->pushError(null, PEAR_INSTALLER_SKIPPED); - } else { - do { - if ($params[$i] && $params[$i]->getType() == 'local') { - // bug #7090 skip channel.xml check for local packages - break; - } + $data = array(); + } + // add parsing of newer formats here... + } else { + $err = $this->raiseError("$file: unknown version `$version'"); + return $err; + } - if ($params[$i] && !isset($channelschecked[$params[$i]->getChannel()]) && - !isset($this->_options['offline'])) { - $channelschecked[$params[$i]->getChannel()] = true; - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - if (!class_exists('System')) { - require_once 'System.php'; - } + return $data; + } - $curchannel = &$this->_registry->getChannel($params[$i]->getChannel()); - if (PEAR::isError($curchannel)) { - PEAR::staticPopErrorHandling(); - return $this->raiseError($curchannel); - } + /** + * Gets the file used for storing the config for a layer + * + * @param string $layer 'user' or 'system' + */ + function getConfFile($layer) + { + return $this->files[$layer]; + } - if (PEAR::isError($dir = $this->getDownloadDir())) { - PEAR::staticPopErrorHandling(); - break; - } + /** + * @param string Configuration class name, used for detecting duplicate calls + * @param array information on a role as parsed from its xml file + * @return true|PEAR_Error + * @access private + */ + function _addConfigVars($class, $vars) + { + static $called = array(); + if (isset($called[$class])) { + return; + } - $mirror = $this->config->get('preferred_mirror', null, - $params[$i]->getChannel()); - $a = $this->downloadHttp('http://' . $mirror . - '/channel.xml', $this->ui, $dir, null, $curchannel->lastModified()); + $called[$class] = 1; + if (count($vars) > 3) { + return $this->raiseError('Roles can only define 3 new config variables or less'); + } - PEAR::staticPopErrorHandling(); - if (PEAR::isError($a) || !$a) { - // Attempt fallback to https automatically - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $a = $this->downloadHttp('https://' . $mirror . - '/channel.xml', $this->ui, $dir, null, $curchannel->lastModified()); + foreach ($vars as $name => $var) { + if (!is_array($var)) { + return $this->raiseError('Configuration information must be an array'); + } - PEAR::staticPopErrorHandling(); - if (PEAR::isError($a) || !$a) { - break; - } + if (!isset($var['type'])) { + return $this->raiseError('Configuration information must contain a type'); + } elseif (!in_array($var['type'], + array('string', 'mask', 'password', 'directory', 'file', 'set'))) { + return $this->raiseError( + 'Configuration type must be one of directory, file, string, ' . + 'mask, set, or password'); + } + if (!isset($var['default'])) { + return $this->raiseError( + 'Configuration information must contain a default value ("default" index)'); + } + + if (is_array($var['default'])) { + $real_default = ''; + foreach ($var['default'] as $config_var => $val) { + if (strpos($config_var, 'text') === 0) { + $real_default .= $val; + } elseif (strpos($config_var, 'constant') === 0) { + if (!defined($val)) { + return $this->raiseError( + 'Unknown constant "' . $val . '" requested in ' . + 'default value for configuration variable "' . + $name . '"'); } - $this->log(0, 'WARNING: channel "' . $params[$i]->getChannel() . '" has ' . - 'updated its protocols, use "' . PEAR_RUNTYPE . ' channel-update ' . $params[$i]->getChannel() . - '" to update'); - } - } while (false); - if ($params[$i] && !isset($this->_options['downloadonly'])) { - if (isset($this->_options['packagingroot'])) { - $checkdir = $this->_prependPath( - $this->config->get('php_dir', null, $params[$i]->getChannel()), - $this->_options['packagingroot']); + $real_default .= constant($val); + } elseif (isset($this->configuration_info[$config_var])) { + $real_default .= + $this->configuration_info[$config_var]['default']; } else { - $checkdir = $this->config->get('php_dir', - null, $params[$i]->getChannel()); + return $this->raiseError( + 'Unknown request for "' . $config_var . '" value in ' . + 'default value for configuration variable "' . + $name . '"'); } + } + $var['default'] = $real_default; + } - while ($checkdir && $checkdir != '/' && !file_exists($checkdir)) { - $checkdir = dirname($checkdir); - } + if ($var['type'] == 'integer') { + $var['default'] = (integer) $var['default']; + } - if ($checkdir == '.') { - $checkdir = '/'; - } + if (!isset($var['doc'])) { + return $this->raiseError( + 'Configuration information must contain a summary ("doc" index)'); + } - if (!is_writeable($checkdir)) { - return PEAR::raiseError('Cannot install, php_dir for channel "' . - $params[$i]->getChannel() . '" is not writeable by the current user'); - } - } + if (!isset($var['prompt'])) { + return $this->raiseError( + 'Configuration information must contain a simple prompt ("prompt" index)'); } - } - unset($channelschecked); - PEAR_Downloader_Package::removeDuplicates($params); - if (!count($params)) { - $a = array(); - return $a; + if (!isset($var['group'])) { + return $this->raiseError( + 'Configuration information must contain a simple group ("group" index)'); + } + + if (isset($this->configuration_info[$name])) { + return $this->raiseError('Configuration variable "' . $name . + '" already exists'); + } + + $this->configuration_info[$name] = $var; + // fix bug #7351: setting custom config variable in a channel fails + $this->_channelConfigInfo[] = $name; } - if (!isset($this->_options['nodeps']) && !isset($this->_options['offline'])) { - $reverify = true; - while ($reverify) { - $reverify = false; - foreach ($params as $i => $param) { - //PHP Bug 40768 / PEAR Bug #10944 - //Nested foreaches fail in PHP 5.2.1 - key($params); - $ret = $params[$i]->detectDependencies($params); - if (PEAR::isError($ret)) { - $reverify = true; - $params[$i] = false; - PEAR_Downloader_Package::removeDuplicates($params); - if (!isset($this->_options['soft'])) { - $this->log(0, $ret->getMessage()); - } - continue 2; - } + return true; + } + + /** + * Encodes/scrambles configuration data before writing to files. + * Currently, 'password' values will be base64-encoded as to avoid + * that people spot cleartext passwords by accident. + * + * @param array (reference) array to encode values in + * @return bool TRUE on success + * @access private + */ + function _encodeOutput(&$data) + { + foreach ($data as $key => $value) { + if ($key == '__channels') { + foreach ($data['__channels'] as $channel => $blah) { + $this->_encodeOutput($data['__channels'][$channel]); } } - } - if (isset($this->_options['offline'])) { - $this->log(3, 'Skipping dependency download check, --offline specified'); + if (!isset($this->configuration_info[$key])) { + continue; + } + + $type = $this->configuration_info[$key]['type']; + switch ($type) { + // we base64-encode passwords so they are at least + // not shown in plain by accident + case 'password': { + $data[$key] = base64_encode($data[$key]); + break; + } + case 'mask': { + $data[$key] = octdec($data[$key]); + break; + } + } } - if (!count($params)) { - $a = array(); - return $a; + return true; + } + + /** + * Decodes/unscrambles configuration data after reading from files. + * + * @param array (reference) array to encode values in + * @return bool TRUE on success + * @access private + * + * @see PEAR_Config::_encodeOutput + */ + function _decodeInput(&$data) + { + if (!is_array($data)) { + return true; } - while (PEAR_Downloader_Package::mergeDependencies($params)); - PEAR_Downloader_Package::removeDuplicates($params, true); - $errorparams = array(); - if (PEAR_Downloader_Package::detectStupidDuplicates($params, $errorparams)) { - if (count($errorparams)) { - foreach ($errorparams as $param) { - $name = $this->_registry->parsedPackageNameToString($param->getParsedPackage()); - $this->pushError('Duplicate package ' . $name . ' found', PEAR_INSTALLER_FAILED); + foreach ($data as $key => $value) { + if ($key == '__channels') { + foreach ($data['__channels'] as $channel => $blah) { + $this->_decodeInput($data['__channels'][$channel]); } - $a = array(); - return $a; } - } - PEAR_Downloader_Package::removeInstalled($params); - if (!count($params)) { - $this->pushError('No valid packages found', PEAR_INSTALLER_FAILED); - $a = array(); - return $a; - } + if (!isset($this->configuration_info[$key])) { + continue; + } - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $err = $this->analyzeDependencies($params); - PEAR::popErrorHandling(); - if (!count($params)) { - $this->pushError('No valid packages found', PEAR_INSTALLER_FAILED); - $a = array(); - return $a; + $type = $this->configuration_info[$key]['type']; + switch ($type) { + case 'password': { + $data[$key] = base64_decode($data[$key]); + break; + } + case 'mask': { + $data[$key] = decoct($data[$key]); + break; + } + } } - $ret = array(); - $newparams = array(); - if (isset($this->_options['pretend'])) { - return $params; - } + return true; + } - $somefailed = false; - foreach ($params as $i => $package) { - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $pf = &$params[$i]->download(); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($pf)) { - if (!isset($this->_options['soft'])) { - $this->log(1, $pf->getMessage()); - $this->log(0, 'Error: cannot download "' . - $this->_registry->parsedPackageNameToString($package->getParsedPackage(), - true) . - '"'); + /** + * Retrieve the default channel. + * + * On startup, channels are not initialized, so if the default channel is not + * pear.php.net, then initialize the config. + * @param string registry layer + * @return string|false + */ + function getDefaultChannel($layer = null) + { + $ret = false; + if ($layer === null) { + foreach ($this->layers as $layer) { + if (isset($this->configuration[$layer]['default_channel'])) { + $ret = $this->configuration[$layer]['default_channel']; + break; } - $somefailed = true; - continue; } + } elseif (isset($this->configuration[$layer]['default_channel'])) { + $ret = $this->configuration[$layer]['default_channel']; + } - $newparams[] = &$params[$i]; - $ret[] = array( - 'file' => $pf->getArchiveFile(), - 'info' => &$pf, - 'pkg' => $pf->getPackage() - ); + if ($ret == 'pear.php.net' && defined('PEAR_RUNTYPE') && PEAR_RUNTYPE == 'pecl') { + $ret = 'pecl.php.net'; } - if ($somefailed) { - // remove params that did not download successfully - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $err = $this->analyzeDependencies($newparams, true); - PEAR::popErrorHandling(); - if (!count($newparams)) { - $this->pushError('Download failed', PEAR_INSTALLER_FAILED); - $a = array(); - return $a; + if ($ret) { + if ($ret != 'pear.php.net') { + $this->_lazyChannelSetup(); } + + return $ret; } - $this->_downloadedPackages = $ret; - return $newparams; + return PEAR_CONFIG_DEFAULT_CHANNEL; } /** - * @param array all packages to be installed + * Returns a configuration value, prioritizing layers as per the + * layers property. + * + * @param string config key + * @return mixed the config value, or NULL if not found + * @access public */ - function analyzeDependencies(&$params, $force = false) + function get($key, $layer = null, $channel = false) { - $hasfailed = $failed = false; - if (isset($this->_options['downloadonly'])) { - return; + if (!isset($this->configuration_info[$key])) { + return null; } - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $redo = true; - $reset = false; - while ($redo) { - $redo = false; - foreach ($params as $i => $param) { - $deps = $param->getDeps(); - if (!$deps) { - $depchecker = &$this->getDependency2Object($this->config, $this->getOptions(), - $param->getParsedPackage(), PEAR_VALIDATE_DOWNLOADING); - $send = $param->getPackageFile(); + if ($key == '__channels') { + return null; + } - $installcheck = $depchecker->validatePackage($send, $this, $params); - if (PEAR::isError($installcheck)) { - if (!isset($this->_options['soft'])) { - $this->log(0, $installcheck->getMessage()); - } - $hasfailed = true; - $params[$i] = false; - $reset = true; - $redo = true; - $failed = false; - PEAR_Downloader_Package::removeDuplicates($params); - continue 2; - } - continue; - } + if ($key == 'default_channel') { + return $this->getDefaultChannel($layer); + } - if (!$reset && $param->alreadyValidated() && !$force) { - continue; - } + if (!$channel) { + $channel = $this->getDefaultChannel(); + } elseif ($channel != 'pear.php.net') { + $this->_lazyChannelSetup(); + } + $channel = strtolower($channel); - if (count($deps)) { - $depchecker = &$this->getDependency2Object($this->config, $this->getOptions(), - $param->getParsedPackage(), PEAR_VALIDATE_DOWNLOADING); - $send = $param->getPackageFile(); - if ($send === null) { - $send = $param->getDownloadURL(); - } + $test = (in_array($key, $this->_channelConfigInfo)) ? + $this->_getChannelValue($key, $layer, $channel) : + null; + if ($test !== null) { + if ($this->_installRoot) { + if (in_array($this->getGroup($key), + array('File Locations', 'File Locations (Advanced)')) && + $this->getType($key) == 'directory') { + return $this->_prependPath($test, $this->_installRoot); + } + } + return $test; + } - $installcheck = $depchecker->validatePackage($send, $this, $params); - if (PEAR::isError($installcheck)) { - if (!isset($this->_options['soft'])) { - $this->log(0, $installcheck->getMessage()); + if ($layer === null) { + foreach ($this->layers as $layer) { + if (isset($this->configuration[$layer][$key])) { + $test = $this->configuration[$layer][$key]; + if ($this->_installRoot) { + if (in_array($this->getGroup($key), + array('File Locations', 'File Locations (Advanced)')) && + $this->getType($key) == 'directory') { + return $this->_prependPath($test, $this->_installRoot); } - $hasfailed = true; - $params[$i] = false; - $reset = true; - $redo = true; - $failed = false; - PEAR_Downloader_Package::removeDuplicates($params); - continue 2; } - $failed = false; - if (isset($deps['required'])) { - foreach ($deps['required'] as $type => $dep) { - // note: Dependency2 will never return a PEAR_Error if ignore-errors - // is specified, so soft is needed to turn off logging - if (!isset($dep[0])) { - if (PEAR::isError($e = $depchecker->{"validate{$type}Dependency"}($dep, - true, $params))) { - $failed = true; - if (!isset($this->_options['soft'])) { - $this->log(0, $e->getMessage()); - } - } elseif (is_array($e) && !$param->alreadyValidated()) { - if (!isset($this->_options['soft'])) { - $this->log(0, $e[0]); - } - } - } else { - foreach ($dep as $d) { - if (PEAR::isError($e = - $depchecker->{"validate{$type}Dependency"}($d, - true, $params))) { - $failed = true; - if (!isset($this->_options['soft'])) { - $this->log(0, $e->getMessage()); - } - } elseif (is_array($e) && !$param->alreadyValidated()) { - if (!isset($this->_options['soft'])) { - $this->log(0, $e[0]); - } - } - } - } - } - - if (isset($deps['optional'])) { - foreach ($deps['optional'] as $type => $dep) { - if (!isset($dep[0])) { - if (PEAR::isError($e = - $depchecker->{"validate{$type}Dependency"}($dep, - false, $params))) { - $failed = true; - if (!isset($this->_options['soft'])) { - $this->log(0, $e->getMessage()); - } - } elseif (is_array($e) && !$param->alreadyValidated()) { - if (!isset($this->_options['soft'])) { - $this->log(0, $e[0]); - } - } - } else { - foreach ($dep as $d) { - if (PEAR::isError($e = - $depchecker->{"validate{$type}Dependency"}($d, - false, $params))) { - $failed = true; - if (!isset($this->_options['soft'])) { - $this->log(0, $e->getMessage()); - } - } elseif (is_array($e) && !$param->alreadyValidated()) { - if (!isset($this->_options['soft'])) { - $this->log(0, $e[0]); - } - } - } - } - } - } - - $groupname = $param->getGroup(); - if (isset($deps['group']) && $groupname) { - if (!isset($deps['group'][0])) { - $deps['group'] = array($deps['group']); - } - - $found = false; - foreach ($deps['group'] as $group) { - if ($group['attribs']['name'] == $groupname) { - $found = true; - break; - } + if ($key == 'preferred_mirror') { + $reg = &$this->getRegistry(); + if (is_object($reg)) { + $chan = &$reg->getChannel($channel); + if (PEAR::isError($chan)) { + return $channel; } - if ($found) { - unset($group['attribs']); - foreach ($group as $type => $dep) { - if (!isset($dep[0])) { - if (PEAR::isError($e = - $depchecker->{"validate{$type}Dependency"}($dep, - false, $params))) { - $failed = true; - if (!isset($this->_options['soft'])) { - $this->log(0, $e->getMessage()); - } - } elseif (is_array($e) && !$param->alreadyValidated()) { - if (!isset($this->_options['soft'])) { - $this->log(0, $e[0]); - } - } - } else { - foreach ($dep as $d) { - if (PEAR::isError($e = - $depchecker->{"validate{$type}Dependency"}($d, - false, $params))) { - $failed = true; - if (!isset($this->_options['soft'])) { - $this->log(0, $e->getMessage()); - } - } elseif (is_array($e) && !$param->alreadyValidated()) { - if (!isset($this->_options['soft'])) { - $this->log(0, $e[0]); - } - } - } - } - } - } - } - } else { - foreach ($deps as $dep) { - if (PEAR::isError($e = $depchecker->validateDependency1($dep, $params))) { - $failed = true; - if (!isset($this->_options['soft'])) { - $this->log(0, $e->getMessage()); - } - } elseif (is_array($e) && !$param->alreadyValidated()) { - if (!isset($this->_options['soft'])) { - $this->log(0, $e[0]); - } + if (!$chan->getMirror($test) && $chan->getName() != $test) { + return $channel; // mirror does not exist } } } - $params[$i]->setValidated(); + return $test; } - - if ($failed) { - $hasfailed = true; - $params[$i] = false; - $reset = true; - $redo = true; - $failed = false; - PEAR_Downloader_Package::removeDuplicates($params); - continue 2; + } + } elseif (isset($this->configuration[$layer][$key])) { + $test = $this->configuration[$layer][$key]; + if ($this->_installRoot) { + if (in_array($this->getGroup($key), + array('File Locations', 'File Locations (Advanced)')) && + $this->getType($key) == 'directory') { + return $this->_prependPath($test, $this->_installRoot); } } - } - PEAR::staticPopErrorHandling(); - if ($hasfailed && (isset($this->_options['ignore-errors']) || - isset($this->_options['nodeps']))) { - // this is probably not needed, but just in case - if (!isset($this->_options['soft'])) { - $this->log(0, 'WARNING: dependencies failed'); + + if ($key == 'preferred_mirror') { + $reg = &$this->getRegistry(); + if (is_object($reg)) { + $chan = &$reg->getChannel($channel); + if (PEAR::isError($chan)) { + return $channel; + } + + if (!$chan->getMirror($test) && $chan->getName() != $test) { + return $channel; // mirror does not exist + } + } } + + return $test; } + + return null; } /** - * Retrieve the directory that downloads will happen in + * Returns a channel-specific configuration value, prioritizing layers as per the + * layers property. + * + * @param string config key + * @return mixed the config value, or NULL if not found * @access private - * @return string */ - function getDownloadDir() + function _getChannelValue($key, $layer, $channel) { - if (isset($this->_downloadDir)) { - return $this->_downloadDir; - } - $downloaddir = $this->config->get('download_dir'); - if (empty($downloaddir) || (is_dir($downloaddir) && !is_writable($downloaddir))) { - if (is_dir($downloaddir) && !is_writable($downloaddir)) { - $this->log(0, 'WARNING: configuration download directory "' . $downloaddir . - '" is not writeable. Change download_dir config variable to ' . - 'a writeable dir to avoid this warning'); - } - if (!class_exists('System')) { - require_once 'System.php'; - } - if (PEAR::isError($downloaddir = System::mktemp('-d'))) { - return $downloaddir; - } - $this->log(3, '+ tmp dir created at ' . $downloaddir); - } - if (!is_writable($downloaddir)) { - if (PEAR::isError(System::mkdir(array('-p', $downloaddir))) || - !is_writable($downloaddir)) { - return PEAR::raiseError('download directory "' . $downloaddir . - '" is not writeable. Change download_dir config variable to ' . - 'a writeable dir'); - } + if ($key == '__channels' || $channel == 'pear.php.net') { + return null; } - return $this->_downloadDir = $downloaddir; - } - function setDownloadDir($dir) - { - if (!@is_writable($dir)) { - if (PEAR::isError(System::mkdir(array('-p', $dir)))) { - return PEAR::raiseError('download directory "' . $dir . - '" is not writeable. Change download_dir config variable to ' . - 'a writeable dir'); + $ret = null; + if ($layer === null) { + foreach ($this->layers as $ilayer) { + if (isset($this->configuration[$ilayer]['__channels'][$channel][$key])) { + $ret = $this->configuration[$ilayer]['__channels'][$channel][$key]; + break; + } } + } elseif (isset($this->configuration[$layer]['__channels'][$channel][$key])) { + $ret = $this->configuration[$layer]['__channels'][$channel][$key]; } - $this->_downloadDir = $dir; - } - // }}} - // {{{ configSet() - function configSet($key, $value, $layer = 'user', $channel = false) - { - $this->config->set($key, $value, $layer, $channel); - $this->_preferredState = $this->config->get('preferred_state', null, $channel); - if (!$this->_preferredState) { - // don't inadvertantly use a non-set preferred_state - $this->_preferredState = null; + if ($key != 'preferred_mirror') { + return $ret; } - } - // }}} - // {{{ setOptions() - function setOptions($options) - { - $this->_options = $options; - } - // }}} - // {{{ setOptions() - function getOptions() - { - return $this->_options; - } + if ($ret !== null) { + $reg = &$this->getRegistry($layer); + if (is_object($reg)) { + $chan = &$reg->getChannel($channel); + if (PEAR::isError($chan)) { + return $channel; + } - // }}} + if (!$chan->getMirror($ret) && $chan->getName() != $ret) { + return $channel; // mirror does not exist + } + } - /** - * For simpler unit-testing - * @param PEAR_Config - * @param int - * @param string - */ - function &getPackagefileObject(&$c, $d, $t = false) - { - if (!class_exists('PEAR_PackageFile')) { - require_once 'PEAR/PackageFile.php'; + return $ret; + } + + if ($channel != $this->getDefaultChannel($layer)) { + return $channel; // we must use the channel name as the preferred mirror + // if the user has not chosen an alternate } - $a = &new PEAR_PackageFile($c, $d, $t); - return $a; - } - // {{{ _getPackageDownloadUrl() + return $this->getDefaultChannel($layer); + } /** - * @param array output of {@link parsePackageName()} - * @access private + * Set a config value in a specific layer (defaults to 'user'). + * Enforces the types defined in the configuration_info array. An + * integer config variable will be cast to int, and a set config + * variable will be validated against its legal values. + * + * @param string config key + * @param string config value + * @param string (optional) config layer + * @param string channel to set this value for, or null for global value + * @return bool TRUE on success, FALSE on failure */ - function _getPackageDownloadUrl($parr) + function set($key, $value, $layer = 'user', $channel = false) { - $curchannel = $this->config->get('default_channel'); - $this->configSet('default_channel', $parr['channel']); - // getDownloadURL returns an array. On error, it only contains information - // on the latest release as array(version, info). On success it contains - // array(version, info, download url string) - $state = isset($parr['state']) ? $parr['state'] : $this->config->get('preferred_state'); - if (!$this->_registry->channelExists($parr['channel'])) { - do { - if ($this->config->get('auto_discover') && $this->discover($parr['channel'])) { - break; - } - - $this->configSet('default_channel', $curchannel); - return PEAR::raiseError('Unknown remote channel: ' . $parr['channel']); - } while (false); - } - - $chan = &$this->_registry->getChannel($parr['channel']); - if (PEAR::isError($chan)) { - return $chan; + if ($key == '__channels') { + return false; } - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $version = $this->_registry->packageInfo($parr['package'], 'version', $parr['channel']); - $stability = $this->_registry->packageInfo($parr['package'], 'stability', $parr['channel']); - // package is installed - use the installed release stability level - if (!isset($parr['state']) && $stability !== null) { - $state = $stability['release']; + if (!isset($this->configuration[$layer])) { + return false; } - PEAR::staticPopErrorHandling(); - $base2 = false; - $preferred_mirror = $this->config->get('preferred_mirror'); - if (!$chan->supportsREST($preferred_mirror) || - ( - !($base2 = $chan->getBaseURL('REST1.3', $preferred_mirror)) - && - !($base = $chan->getBaseURL('REST1.0', $preferred_mirror)) - ) - ) { - return $this->raiseError($parr['channel'] . ' is using a unsupported protocal - This should never happen.'); + if ($key == 'default_channel') { + // can only set this value globally + $channel = 'pear.php.net'; + if ($value != 'pear.php.net') { + $this->_lazyChannelSetup($layer); + } } - if ($base2) { - $rest = &$this->config->getREST('1.3', $this->_options); - $base = $base2; - } else { - $rest = &$this->config->getREST('1.0', $this->_options); - } + if ($key == 'preferred_mirror') { + if ($channel == '__uri') { + return false; // can't set the __uri pseudo-channel's mirror + } - if (!isset($parr['version']) && !isset($parr['state']) && $version - && !PEAR::isError($version) - && !isset($this->_options['downloadonly'])) { - $url = $rest->getDownloadURL($base, $parr, $state, $version, $chan->getName()); - } else { - $url = $rest->getDownloadURL($base, $parr, $state, false, $chan->getName()); - } + $reg = &$this->getRegistry($layer); + if (is_object($reg)) { + $chan = &$reg->getChannel($channel ? $channel : 'pear.php.net'); + if (PEAR::isError($chan)) { + return false; + } - if (PEAR::isError($url)) { - $this->configSet('default_channel', $curchannel); - return $url; + if (!$chan->getMirror($value) && $chan->getName() != $value) { + return false; // mirror does not exist + } + } } - if ($parr['channel'] != $curchannel) { - $this->configSet('default_channel', $curchannel); + if (!isset($this->configuration_info[$key])) { + return false; } - if (!is_array($url)) { - return $url; + extract($this->configuration_info[$key]); + switch ($type) { + case 'integer': + $value = (int)$value; + break; + case 'set': { + // If a valid_set is specified, require the value to + // be in the set. If there is no valid_set, accept + // any value. + if ($valid_set) { + reset($valid_set); + if ((key($valid_set) === 0 && !in_array($value, $valid_set)) || + (key($valid_set) !== 0 && empty($valid_set[$value]))) + { + return false; + } + } + break; + } } - $url['raw'] = false; // no checking is necessary for REST - if (!is_array($url['info'])) { - return PEAR::raiseError('Invalid remote dependencies retrieved from REST - ' . - 'this should never happen'); + if (!$channel) { + $channel = $this->get('default_channel', null, 'pear.php.net'); } - if (!isset($this->_options['force']) && - !isset($this->_options['downloadonly']) && - $version && - !PEAR::isError($version) && - !isset($parr['group']) - ) { - if (version_compare($version, $url['version'], '=')) { - return PEAR::raiseError($this->_registry->parsedPackageNameToString( - $parr, true) . ' is already installed and is the same as the ' . - 'released version ' . $url['version'], -976); + if (!in_array($channel, $this->_channels)) { + $this->_lazyChannelSetup($layer); + $reg = &$this->getRegistry($layer); + if ($reg) { + $channel = $reg->channelName($channel); } - if (version_compare($version, $url['version'], '>')) { - return PEAR::raiseError($this->_registry->parsedPackageNameToString( - $parr, true) . ' is already installed and is newer than detected ' . - 'released version ' . $url['version'], -976); + if (!in_array($channel, $this->_channels)) { + return false; } } - if (isset($url['info']['required']) || $url['compatible']) { - require_once 'PEAR/PackageFile/v2.php'; - $pf = new PEAR_PackageFile_v2; - $pf->setRawChannel($parr['channel']); - if ($url['compatible']) { - $pf->setRawCompatible($url['compatible']); + if ($channel != 'pear.php.net') { + if (in_array($key, $this->_channelConfigInfo)) { + $this->configuration[$layer]['__channels'][$channel][$key] = $value; + return true; } - } else { - require_once 'PEAR/PackageFile/v1.php'; - $pf = new PEAR_PackageFile_v1; - } - $pf->setRawPackage($url['package']); - $pf->setDeps($url['info']); - if ($url['compatible']) { - $pf->setCompatible($url['compatible']); + return false; } - $pf->setRawState($url['stability']); - $url['info'] = &$pf; - if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) { - $ext = '.tar'; - } else { - $ext = '.tgz'; + if ($key == 'default_channel') { + if (!isset($reg)) { + $reg = &$this->getRegistry($layer); + if (!$reg) { + $reg = &$this->getRegistry(); + } + } + + if ($reg) { + $value = $reg->channelName($value); + } + + if (!$value) { + return false; + } } - if (is_array($url) && isset($url['url'])) { - $url['url'] .= $ext; + $this->configuration[$layer][$key] = $value; + if ($key == 'php_dir' && !$this->_noRegistry) { + if (!isset($this->_registry[$layer]) || + $value != $this->_registry[$layer]->install_dir) { + $this->_registry[$layer] = &new PEAR_Registry($value); + $this->_regInitialized[$layer] = false; + $this->_registry[$layer]->setConfig($this, false); + } } - return $url; + return true; } - // }}} - // {{{ getDepPackageDownloadUrl() - /** - * @param array dependency array - * @access private - */ - function _getDepPackageDownloadUrl($dep, $parr) + function _lazyChannelSetup($uselayer = false) { - $xsdversion = isset($dep['rel']) ? '1.0' : '2.0'; - $curchannel = $this->config->get('default_channel'); - if (isset($dep['uri'])) { - $xsdversion = '2.0'; - $chan = &$this->_registry->getChannel('__uri'); - if (PEAR::isError($chan)) { - return $chan; - } + if ($this->_noRegistry) { + return; + } - $version = $this->_registry->packageInfo($dep['name'], 'version', '__uri'); - $this->configSet('default_channel', '__uri'); - } else { - if (isset($dep['channel'])) { - $remotechannel = $dep['channel']; - } else { - $remotechannel = 'pear.php.net'; + $merge = false; + foreach ($this->_registry as $layer => $p) { + if ($uselayer && $uselayer != $layer) { + continue; } - if (!$this->_registry->channelExists($remotechannel)) { - do { - if ($this->config->get('auto_discover')) { - if ($this->discover($remotechannel)) { - break; - } - } - return PEAR::raiseError('Unknown remote channel: ' . $remotechannel); - } while (false); - } - - $chan = &$this->_registry->getChannel($remotechannel); - if (PEAR::isError($chan)) { - return $chan; - } - - $version = $this->_registry->packageInfo($dep['name'], 'version', $remotechannel); - $this->configSet('default_channel', $remotechannel); - } - - $state = isset($parr['state']) ? $parr['state'] : $this->config->get('preferred_state'); - if (isset($parr['state']) && isset($parr['version'])) { - unset($parr['state']); - } - - if (isset($dep['uri'])) { - $info = &$this->newDownloaderPackage($this); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $err = $info->initialize($dep); - PEAR::staticPopErrorHandling(); - if (!$err) { - // skip parameters that were missed by preferred_state - return PEAR::raiseError('Cannot initialize dependency'); - } - - if (PEAR::isError($err)) { - if (!isset($this->_options['soft'])) { - $this->log(0, $err->getMessage()); + if (!$this->_regInitialized[$layer]) { + if ($layer == 'default' && isset($this->_registry['user']) || + isset($this->_registry['system'])) { + // only use the default registry if there are no alternatives + continue; } - if (is_object($info)) { - $param = $info->getChannel() . '/' . $info->getPackage(); + if (!is_object($this->_registry[$layer])) { + if ($phpdir = $this->get('php_dir', $layer, 'pear.php.net')) { + $this->_registry[$layer] = &new PEAR_Registry($phpdir); + $this->_registry[$layer]->setConfig($this, false); + $this->_regInitialized[$layer] = false; + } else { + unset($this->_registry[$layer]); + return; + } } - return PEAR::raiseError('Package "' . $param . '" is not valid'); - } - return $info; - } elseif ($chan->supportsREST($this->config->get('preferred_mirror')) - && $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror')) - ) { - $rest = &$this->config->getREST('1.0', $this->_options); - $url = $rest->getDepDownloadURL($base, $xsdversion, $dep, $parr, - $state, $version, $chan->getName()); - if (PEAR::isError($url)) { - return $url; - } - if ($parr['channel'] != $curchannel) { - $this->configSet('default_channel', $curchannel); + $this->setChannels($this->_registry[$layer]->listChannels(), $merge); + $this->_regInitialized[$layer] = true; + $merge = true; } + } + } - if (!is_array($url)) { - return $url; - } + /** + * Set the list of channels. + * + * This should be set via a call to {@link PEAR_Registry::listChannels()} + * @param array + * @param bool + * @return bool success of operation + */ + function setChannels($channels, $merge = false) + { + if (!is_array($channels)) { + return false; + } - $url['raw'] = false; // no checking is necessary for REST - if (!is_array($url['info'])) { - return PEAR::raiseError('Invalid remote dependencies retrieved from REST - ' . - 'this should never happen'); + if ($merge) { + $this->_channels = array_merge($this->_channels, $channels); + } else { + $this->_channels = $channels; + } + + foreach ($channels as $channel) { + $channel = strtolower($channel); + if ($channel == 'pear.php.net') { + continue; } - if (isset($url['info']['required'])) { - if (!class_exists('PEAR_PackageFile_v2')) { - require_once 'PEAR/PackageFile/v2.php'; + foreach ($this->layers as $layer) { + if (!isset($this->configuration[$layer]['__channels'])) { + $this->configuration[$layer]['__channels'] = array(); } - $pf = new PEAR_PackageFile_v2; - $pf->setRawChannel($remotechannel); - } else { - if (!class_exists('PEAR_PackageFile_v1')) { - require_once 'PEAR/PackageFile/v1.php'; + if (!isset($this->configuration[$layer]['__channels'][$channel]) + || !is_array($this->configuration[$layer]['__channels'][$channel])) { + $this->configuration[$layer]['__channels'][$channel] = array(); } - $pf = new PEAR_PackageFile_v1; - - } - $pf->setRawPackage($url['package']); - $pf->setDeps($url['info']); - if ($url['compatible']) { - $pf->setCompatible($url['compatible']); } + } - $pf->setRawState($url['stability']); - $url['info'] = &$pf; - if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) { - $ext = '.tar'; - } else { - $ext = '.tgz'; - } + return true; + } - if (is_array($url) && isset($url['url'])) { - $url['url'] .= $ext; - } + /** + * Get the type of a config value. + * + * @param string config key + * + * @return string type, one of "string", "integer", "file", + * "directory", "set" or "password". + * + * @access public + * + */ + function getType($key) + { + if (isset($this->configuration_info[$key])) { + return $this->configuration_info[$key]['type']; + } + return false; + } - return $url; + /** + * Get the documentation for a config value. + * + * @param string config key + * @return string documentation string + * + * @access public + * + */ + function getDocs($key) + { + if (isset($this->configuration_info[$key])) { + return $this->configuration_info[$key]['doc']; } - return $this->raiseError($parr['channel'] . ' is using a unsupported protocal - This should never happen.'); + return false; } - // }}} - // {{{ getPackageDownloadUrl() /** - * @deprecated in favor of _getPackageDownloadUrl + * Get the short documentation for a config value. + * + * @param string config key + * @return string short documentation string + * + * @access public + * */ - function getPackageDownloadUrl($package, $version = null, $channel = false) + function getPrompt($key) { - if ($version) { - $package .= "-$version"; - } - if ($this === null || $this->_registry === null) { - $package = "http://pear.php.net/get/$package"; - } else { - $chan = $this->_registry->getChannel($channel); - if (PEAR::isError($chan)) { - return ''; - } - $package = "http://" . $chan->getServer() . "/get/$package"; - } - if (!extension_loaded("zlib")) { - $package .= '?uncompress=yes'; + if (isset($this->configuration_info[$key])) { + return $this->configuration_info[$key]['prompt']; } - return $package; - } - // }}} - // {{{ getDownloadedPackages() + return false; + } /** - * Retrieve a list of downloaded packages after a call to {@link download()}. + * Get the parameter group for a config key. + * + * @param string config key + * @return string parameter group + * + * @access public * - * Also resets the list of downloaded packages. - * @return array */ - function getDownloadedPackages() + function getGroup($key) { - $ret = $this->_downloadedPackages; - $this->_downloadedPackages = array(); - $this->_toDownload = array(); - return $ret; - } + if (isset($this->configuration_info[$key])) { + return $this->configuration_info[$key]['group']; + } - // }}} - // {{{ _downloadCallback() + return false; + } - function _downloadCallback($msg, $params = null) + /** + * Get the list of parameter groups. + * + * @return array list of parameter groups + * + * @access public + * + */ + function getGroups() { - switch ($msg) { - case 'saveas': - $this->log(1, "downloading $params ..."); - break; - case 'done': - $this->log(1, '...done: ' . number_format($params, 0, '', ',') . ' bytes'); - break; - case 'bytesread': - static $bytes; - if (empty($bytes)) { - $bytes = 0; - } - if (!($bytes % 10240)) { - $this->log(1, '.', false); - } - $bytes += $params; - break; - case 'start': - if($params[1] == -1) { - $length = "Unknown size"; - } else { - $length = number_format($params[1], 0, '', ',')." bytes"; - } - $this->log(1, "Starting to download {$params[0]} ($length)"); - break; + $tmp = array(); + foreach ($this->configuration_info as $key => $info) { + $tmp[$info['group']] = 1; } - if (method_exists($this->ui, '_downloadCallback')) - $this->ui->_downloadCallback($msg, $params); - } - // }}} - // {{{ _prependPath($path, $prepend) + return array_keys($tmp); + } - function _prependPath($path, $prepend) + /** + * Get the list of the parameters in a group. + * + * @param string $group parameter group + * @return array list of parameters in $group + * + * @access public + * + */ + function getGroupKeys($group) { - if (strlen($prepend) > 0) { - if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) { - if (preg_match('/^[a-z]:/i', $prepend)) { - $prepend = substr($prepend, 2); - } elseif ($prepend{0} != '\\') { - $prepend = "\\$prepend"; - } - $path = substr($path, 0, 2) . $prepend . substr($path, 2); - } else { - $path = $prepend . $path; + $keys = array(); + foreach ($this->configuration_info as $key => $info) { + if ($info['group'] == $group) { + $keys[] = $key; } } - return $path; + + return $keys; } - // }}} - // {{{ pushError($errmsg, $code) /** - * @param string - * @param integer + * Get the list of allowed set values for a config value. Returns + * NULL for config values that are not sets. + * + * @param string config key + * @return array enumerated array of set values, or NULL if the + * config key is unknown or not a set + * + * @access public + * */ - function pushError($errmsg, $code = -1) + function getSetValues($key) { - array_push($this->_errorStack, array($errmsg, $code)); - } - - // }}} - // {{{ getErrorMsgs() + if (isset($this->configuration_info[$key]) && + isset($this->configuration_info[$key]['type']) && + $this->configuration_info[$key]['type'] == 'set') + { + $valid_set = $this->configuration_info[$key]['valid_set']; + reset($valid_set); + if (key($valid_set) === 0) { + return $valid_set; + } - function getErrorMsgs() - { - $msgs = array(); - $errs = $this->_errorStack; - foreach ($errs as $err) { - $msgs[] = $err[0]; + return array_keys($valid_set); } - $this->_errorStack = array(); - return $msgs; - } - // }}} + return null; + } /** - * for BC + * Get all the current config keys. + * + * @return array simple array of config keys + * + * @access public */ - function sortPkgDeps(&$packages, $uninstall = false) + function getKeys() { - $uninstall ? - $this->sortPackagesForUninstall($packages) : - $this->sortPackagesForInstall($packages); + $keys = array(); + foreach ($this->layers as $layer) { + $test = $this->configuration[$layer]; + if (isset($test['__channels'])) { + foreach ($test['__channels'] as $channel => $configs) { + $keys = array_merge($keys, $configs); + } + } + + unset($test['__channels']); + $keys = array_merge($keys, $test); + + } + return array_keys($keys); } /** - * Sort a list of arrays of array(downloaded packagefilename) by dependency. + * Remove the a config key from a specific config layer. * - * This uses the topological sort method from graph theory, and the - * Structures_Graph package to properly sort dependencies for installation. - * @param array an array of downloaded PEAR_Downloader_Packages - * @return array array of array(packagefilename, package.xml contents) + * @param string config key + * @param string (optional) config layer + * @param string (optional) channel (defaults to default channel) + * @return bool TRUE on success, FALSE on failure + * + * @access public */ - function sortPackagesForInstall(&$packages) + function remove($key, $layer = 'user', $channel = null) { - require_once 'Structures/Graph.php'; - require_once 'Structures/Graph/Node.php'; - require_once 'Structures/Graph/Manipulator/TopologicalSorter.php'; - $depgraph = new Structures_Graph(true); - $nodes = array(); - $reg = &$this->config->getRegistry(); - foreach ($packages as $i => $package) { - $pname = $reg->parsedPackageNameToString( - array( - 'channel' => $package->getChannel(), - 'package' => strtolower($package->getPackage()), - )); - $nodes[$pname] = new Structures_Graph_Node; - $nodes[$pname]->setData($packages[$i]); - $depgraph->addNode($nodes[$pname]); + if ($channel === null) { + $channel = $this->getDefaultChannel(); } - $deplinks = array(); - foreach ($nodes as $package => $node) { - $pf = &$node->getData(); - $pdeps = $pf->getDeps(true); - if (!$pdeps) { - continue; + if ($channel !== 'pear.php.net') { + if (isset($this->configuration[$layer]['__channels'][$channel][$key])) { + unset($this->configuration[$layer]['__channels'][$channel][$key]); + return true; } + } - if ($pf->getPackagexmlVersion() == '1.0') { - foreach ($pdeps as $dep) { - if ($dep['type'] != 'pkg' || - (isset($dep['optional']) && $dep['optional'] == 'yes')) { - continue; - } - - $dname = $reg->parsedPackageNameToString( - array( - 'channel' => 'pear.php.net', - 'package' => strtolower($dep['name']), - )); + if (isset($this->configuration[$layer][$key])) { + unset($this->configuration[$layer][$key]); + return true; + } - if (isset($nodes[$dname])) { - if (!isset($deplinks[$dname])) { - $deplinks[$dname] = array(); - } + return false; + } - $deplinks[$dname][$package] = 1; - // dependency is in installed packages - continue; - } + /** + * Temporarily remove an entire config layer. USE WITH CARE! + * + * @param string config key + * @param string (optional) config layer + * @return bool TRUE on success, FALSE on failure + * + * @access public + */ + function removeLayer($layer) + { + if (isset($this->configuration[$layer])) { + $this->configuration[$layer] = array(); + return true; + } - $dname = $reg->parsedPackageNameToString( - array( - 'channel' => 'pecl.php.net', - 'package' => strtolower($dep['name']), - )); + return false; + } - if (isset($nodes[$dname])) { - if (!isset($deplinks[$dname])) { - $deplinks[$dname] = array(); - } + /** + * Stores configuration data in a layer. + * + * @param string config layer to store + * @return bool TRUE on success, or PEAR error on failure + * + * @access public + */ + function store($layer = 'user', $data = null) + { + return $this->writeConfigFile(null, $layer, $data); + } - $deplinks[$dname][$package] = 1; - // dependency is in installed packages - continue; + /** + * Tells what config layer that gets to define a key. + * + * @param string config key + * @param boolean return the defining channel + * + * @return string|array the config layer, or an empty string if not found. + * + * if $returnchannel, the return is an array array('layer' => layername, + * 'channel' => channelname), or an empty string if not found + * + * @access public + */ + function definedBy($key, $returnchannel = false) + { + foreach ($this->layers as $layer) { + $channel = $this->getDefaultChannel(); + if ($channel !== 'pear.php.net') { + if (isset($this->configuration[$layer]['__channels'][$channel][$key])) { + if ($returnchannel) { + return array('layer' => $layer, 'channel' => $channel); } + return $layer; } - } else { - // the only ordering we care about is: - // 1) subpackages must be installed before packages that depend on them - // 2) required deps must be installed before packages that depend on them - if (isset($pdeps['required']['subpackage'])) { - $t = $pdeps['required']['subpackage']; - if (!isset($t[0])) { - $t = array($t); - } + } - $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); + if (isset($this->configuration[$layer][$key])) { + if ($returnchannel) { + return array('layer' => $layer, 'channel' => 'pear.php.net'); } + return $layer; + } + } - if (isset($pdeps['group'])) { - if (!isset($pdeps['group'][0])) { - $pdeps['group'] = array($pdeps['group']); - } - - foreach ($pdeps['group'] as $group) { - if (isset($group['subpackage'])) { - $t = $group['subpackage']; - if (!isset($t[0])) { - $t = array($t); - } + return ''; + } - $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); - } - } - } + /** + * Tells whether a given key exists as a config value. + * + * @param string config key + * @return bool whether exists in this object + * + * @access public + */ + function isDefined($key) + { + foreach ($this->layers as $layer) { + if (isset($this->configuration[$layer][$key])) { + return true; + } + } - if (isset($pdeps['optional']['subpackage'])) { - $t = $pdeps['optional']['subpackage']; - if (!isset($t[0])) { - $t = array($t); - } + return false; + } - $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); - } + /** + * Tells whether a given config layer exists. + * + * @param string config layer + * @return bool whether exists in this object + * + * @access public + */ + function isDefinedLayer($layer) + { + return isset($this->configuration[$layer]); + } - if (isset($pdeps['required']['package'])) { - $t = $pdeps['required']['package']; - if (!isset($t[0])) { - $t = array($t); - } + /** + * Returns the layers defined (except the 'default' one) + * + * @return array of the defined layers + */ + function getLayers() + { + $cf = $this->configuration; + unset($cf['default']); + return array_keys($cf); + } - $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); - } + function apiVersion() + { + return '1.1'; + } - if (isset($pdeps['group'])) { - if (!isset($pdeps['group'][0])) { - $pdeps['group'] = array($pdeps['group']); - } + /** + * @return PEAR_Registry + */ + function &getRegistry($use = null) + { + $layer = $use === null ? 'user' : $use; + if (isset($this->_registry[$layer])) { + return $this->_registry[$layer]; + } elseif ($use === null && isset($this->_registry['system'])) { + return $this->_registry['system']; + } elseif ($use === null && isset($this->_registry['default'])) { + return $this->_registry['default']; + } elseif ($use) { + $a = false; + return $a; + } - foreach ($pdeps['group'] as $group) { - if (isset($group['package'])) { - $t = $group['package']; - if (!isset($t[0])) { - $t = array($t); - } + // only go here if null was passed in + echo "CRITICAL ERROR: Registry could not be initialized from any value"; + exit(1); + } - $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); - } - } - } - } + /** + * This is to allow customization like the use of installroot + * @param PEAR_Registry + * @return bool + */ + function setRegistry(&$reg, $layer = 'user') + { + if ($this->_noRegistry) { + return false; } - $this->_detectDepCycle($deplinks); - foreach ($deplinks as $dependent => $parents) { - foreach ($parents as $parent => $unused) { - $nodes[$dependent]->connectTo($nodes[$parent]); - } + if (!in_array($layer, array('user', 'system'))) { + return false; } - $installOrder = Structures_Graph_Manipulator_TopologicalSorter::sort($depgraph); - $ret = array(); - for ($i = 0; $i < count($installOrder); $i++) { - foreach ($installOrder[$i] as $index => $sortedpackage) { - $data = &$installOrder[$i][$index]->getData(); - $ret[] = &$nodes[$reg->parsedPackageNameToString( - array( - 'channel' => $data->getChannel(), - 'package' => strtolower($data->getPackage()), - ))]->getData(); - } + $this->_registry[$layer] = &$reg; + if (is_object($reg)) { + $this->_registry[$layer]->setConfig($this, false); } - $packages = $ret; - return; + return true; + } + + function noRegistry() + { + $this->_noRegistry = true; } /** - * Detect recursive links between dependencies and break the cycles - * - * @param array - * @access private + * @return PEAR_REST */ - function _detectDepCycle(&$deplinks) + function &getREST($version, $options = array()) { - do { - $keepgoing = false; - foreach ($deplinks as $dep => $parents) { - foreach ($parents as $parent => $unused) { - // reset the parent cycle detector - $this->_testCycle(null, null, null); - if ($this->_testCycle($dep, $deplinks, $parent)) { - $keepgoing = true; - unset($deplinks[$dep][$parent]); - if (count($deplinks[$dep]) == 0) { - unset($deplinks[$dep]); - } - continue 3; - } - } - } - } while ($keepgoing); + $version = str_replace('.', '', $version); + if (!class_exists($class = 'PEAR_REST_' . $version)) { + require_once 'PEAR/REST/' . $version . '.php'; + } + + $remote = &new $class($this, $options); + return $remote; } - function _testCycle($test, $deplinks, $dep) + /** + * The ftp server is set in {@link readFTPConfigFile()}. It exists only if a + * remote configuration file has been specified + * @return PEAR_FTP|false + */ + function &getFTP() { - static $visited = array(); - if ($test === null) { - $visited = array(); - return; - } - // this happens when a parent has a dep cycle on another dependency - // but the child is not part of the cycle - if (isset($visited[$dep])) { - return false; - } - $visited[$dep] = 1; - if ($test == $dep) { - return true; + if (isset($this->_ftp)) { + return $this->_ftp; } - if (isset($deplinks[$dep])) { - if (in_array($test, array_keys($deplinks[$dep]), true)) { - return true; - } - foreach ($deplinks[$dep] as $parent => $unused) { - if ($this->_testCycle($test, $deplinks, $parent)) { - return true; + + $a = false; + return $a; + } + + function _prependPath($path, $prepend) + { + if (strlen($prepend) > 0) { + if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) { + if (preg_match('/^[a-z]:/i', $prepend)) { + $prepend = substr($prepend, 2); + } elseif ($prepend{0} != '\\') { + $prepend = "\\$prepend"; } + $path = substr($path, 0, 2) . $prepend . substr($path, 2); + } else { + $path = $prepend . $path; } } - return false; + return $path; } /** - * Set up the dependency for installation parsing - * - * @param array $t dependency information - * @param PEAR_Registry $reg - * @param array $deplinks list of dependency links already established - * @param array $nodes all existing package nodes - * @param string $package parent package name - * @access private + * @param string|false installation directory to prepend to all _dir variables, or false to + * disable */ - function _setupGraph($t, $reg, &$deplinks, &$nodes, $package) + function setInstallRoot($root) { - foreach ($t as $dep) { - $depchannel = !isset($dep['channel']) ? '__uri': $dep['channel']; - $dname = $reg->parsedPackageNameToString( - array( - 'channel' => $depchannel, - 'package' => strtolower($dep['name']), - )); - - if (isset($nodes[$dname])) { - if (!isset($deplinks[$dname])) { - $deplinks[$dname] = array(); + if (substr($root, -1) == DIRECTORY_SEPARATOR) { + $root = substr($root, 0, -1); + } + $old = $this->_installRoot; + $this->_installRoot = $root; + if (($old != $root) && !$this->_noRegistry) { + foreach (array_keys($this->_registry) as $layer) { + if ($layer == 'ftp' || !isset($this->_registry[$layer])) { + continue; } - $deplinks[$dname][$package] = 1; + $this->_registry[$layer] = + &new PEAR_Registry($this->get('php_dir', $layer, 'pear.php.net')); + $this->_registry[$layer]->setConfig($this, false); + $this->_regInitialized[$layer] = false; } } } +} +PEAR-1.9.0/PEAR/DependencyDB.php100664 764 764 57256 100664 11071 + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: DependencyDB.php 286686 2009-08-02 17:38:57Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ - function _dependsOn($a, $b) +/** + * Needed for error handling + */ +require_once 'PEAR.php'; +require_once 'PEAR/Config.php'; + +$GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'] = array(); +/** + * Track dependency relationships between installed packages + * @category pear + * @package PEAR + * @author Greg Beaver + * @author Tomas V.V.Cox + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_DependencyDB +{ + // {{{ properties + + /** + * This is initialized by {@link setConfig()} + * @var PEAR_Config + * @access private + */ + var $_config; + /** + * This is initialized by {@link setConfig()} + * @var PEAR_Registry + * @access private + */ + var $_registry; + /** + * Filename of the dependency DB (usually .depdb) + * @var string + * @access private + */ + var $_depdb = false; + /** + * File name of the lockfile (usually .depdblock) + * @var string + * @access private + */ + var $_lockfile = false; + /** + * Open file resource for locking the lockfile + * @var resource|false + * @access private + */ + var $_lockFp = false; + /** + * API version of this class, used to validate a file on-disk + * @var string + * @access private + */ + var $_version = '1.0'; + /** + * Cached dependency database file + * @var array|null + * @access private + */ + var $_cache; + + // }}} + // {{{ & singleton() + + /** + * Get a raw dependency database. Calls setConfig() and assertDepsDB() + * @param PEAR_Config + * @param string|false full path to the dependency database, or false to use default + * @return PEAR_DependencyDB|PEAR_Error + * @static + */ + function &singleton(&$config, $depdb = false) { - return $this->_checkDepTree(strtolower($a->getChannel()), strtolower($a->getPackage()), $b); + $phpdir = $config->get('php_dir', null, 'pear.php.net'); + if (!isset($GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir])) { + $a = new PEAR_DependencyDB; + $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir] = &$a; + $a->setConfig($config, $depdb); + $e = $a->assertDepsDB(); + if (PEAR::isError($e)) { + return $e; + } + } + + return $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir]; } - function _checkDepTree($channel, $package, $b, $checked = array()) + /** + * Set up the registry/location of dependency DB + * @param PEAR_Config|false + * @param string|false full path to the dependency database, or false to use default + */ + function setConfig(&$config, $depdb = false) { - $checked[$channel][$package] = true; - if (!isset($this->_depTree[$channel][$package])) { - return false; + if (!$config) { + $this->_config = &PEAR_Config::singleton(); + } else { + $this->_config = &$config; } - if (isset($this->_depTree[$channel][$package][strtolower($b->getChannel())] - [strtolower($b->getPackage())])) { - return true; + $this->_registry = &$this->_config->getRegistry(); + if (!$depdb) { + $this->_depdb = $this->_config->get('php_dir', null, 'pear.php.net') . + DIRECTORY_SEPARATOR . '.depdb'; + } else { + $this->_depdb = $depdb; } - foreach ($this->_depTree[$channel][$package] as $ch => $packages) { - foreach ($packages as $pa => $true) { - if ($this->_checkDepTree($ch, $pa, $b, $checked)) { - return true; + $this->_lockfile = dirname($this->_depdb) . DIRECTORY_SEPARATOR . '.depdblock'; + } + // }}} + + function hasWriteAccess() + { + if (!file_exists($this->_depdb)) { + $dir = $this->_depdb; + while ($dir && $dir != '.') { + $dir = dirname($dir); // cd .. + if ($dir != '.' && file_exists($dir)) { + if (is_writeable($dir)) { + return true; + } + + return false; } } + + return false; } - return false; + return is_writeable($this->_depdb); } - function _sortInstall($a, $b) + // {{{ assertDepsDB() + + /** + * Create the dependency database, if it doesn't exist. Error if the database is + * newer than the code reading it. + * @return void|PEAR_Error + */ + function assertDepsDB() { - if (!$a->getDeps() && !$b->getDeps()) { - return 0; // neither package has dependencies, order is insignificant - } - if ($a->getDeps() && !$b->getDeps()) { - return 1; // $a must be installed after $b because $a has dependencies - } - if (!$a->getDeps() && $b->getDeps()) { - return -1; // $b must be installed after $a because $b has dependencies + if (!is_file($this->_depdb)) { + $this->rebuildDB(); + return; } - // both packages have dependencies - if ($this->_dependsOn($a, $b)) { - return 1; + + $depdb = $this->_getDepDB(); + // Datatype format has been changed, rebuild the Deps DB + if ($depdb['_version'] < $this->_version) { + $this->rebuildDB(); } - if ($this->_dependsOn($b, $a)) { - return -1; + + if ($depdb['_version']{0} > $this->_version{0}) { + return PEAR::raiseError('Dependency database is version ' . + $depdb['_version'] . ', and we are version ' . + $this->_version . ', cannot continue'); } - return 0; } /** - * Download a file through HTTP. Considers suggested file name in - * Content-disposition: header and can run a callback function for - * different events. The callback will be called with two - * parameters: the callback type, and parameters. The implemented - * callback types are: - * - * 'setup' called at the very beginning, parameter is a UI object - * that should be used for all output - * 'message' the parameter is a string with an informational message - * 'saveas' may be used to save with a different file name, the - * parameter is the filename that is about to be used. - * If a 'saveas' callback returns a non-empty string, - * that file name will be used as the filename instead. - * Note that $save_dir will not be affected by this, only - * the basename of the file. - * 'start' download is starting, parameter is number of bytes - * that are expected, or -1 if unknown - * 'bytesread' parameter is the number of bytes read so far - * 'done' download is complete, parameter is the total number - * of bytes read - * 'connfailed' if the TCP/SSL connection fails, this callback is called - * with array(host,port,errno,errmsg) - * 'writefailed' if writing to disk fails, this callback is called - * with array(destfile,errmsg) - * - * If an HTTP proxy has been configured (http_proxy PEAR_Config - * setting), the proxy will be used. - * - * @param string $url the URL to download - * @param object $ui PEAR_Frontend_* instance - * @param object $config PEAR_Config instance - * @param string $save_dir directory to save file in - * @param mixed $callback function/method to call for status - * updates - * @param false|string|array $lastmodified header values to check against for caching - * use false to return the header values from this download - * @param false|array $accept Accept headers to send - * @param false|string $channel Channel to use for retrieving authentication - * @return string|array Returns the full path of the downloaded file or a PEAR - * error on failure. If the error is caused by - * socket-related errors, the error object will - * have the fsockopen error code available through - * getCode(). If caching is requested, then return the header - * values. - * - * @access public + * Get a list of installed packages that depend on this package + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array + * @return array|false */ - function downloadHttp($url, &$ui, $save_dir = '.', $callback = null, $lastmodified = null, - $accept = false, $channel = false) + function getDependentPackages(&$pkg) { - static $redirect = 0; - // always reset , so we are clean case of error - $wasredirect = $redirect; - $redirect = 0; - if ($callback) { - call_user_func($callback, 'setup', array(&$ui)); - } - - $info = parse_url($url); - if (!isset($info['scheme']) || !in_array($info['scheme'], array('http', 'https'))) { - return PEAR::raiseError('Cannot download non-http URL "' . $url . '"'); + $data = $this->_getDepDB(); + if (is_object($pkg)) { + $channel = strtolower($pkg->getChannel()); + $package = strtolower($pkg->getPackage()); + } else { + $channel = strtolower($pkg['channel']); + $package = strtolower($pkg['package']); } - if (!isset($info['host'])) { - return PEAR::raiseError('Cannot download from non-URL "' . $url . '"'); + if (isset($data['packages'][$channel][$package])) { + return $data['packages'][$channel][$package]; } - $host = isset($info['host']) ? $info['host'] : null; - $port = isset($info['port']) ? $info['port'] : null; - $path = isset($info['path']) ? $info['path'] : null; + return false; + } - if (isset($this)) { - $config = &$this->config; - } else { - $config = &PEAR_Config::singleton(); - } - - $proxy_host = $proxy_port = $proxy_user = $proxy_pass = ''; - if ($config->get('http_proxy') && - $proxy = parse_url($config->get('http_proxy'))) { - $proxy_host = isset($proxy['host']) ? $proxy['host'] : null; - if (isset($proxy['scheme']) && $proxy['scheme'] == 'https') { - $proxy_host = 'ssl://' . $proxy_host; - } - $proxy_port = isset($proxy['port']) ? $proxy['port'] : 8080; - $proxy_user = isset($proxy['user']) ? urldecode($proxy['user']) : null; - $proxy_pass = isset($proxy['pass']) ? urldecode($proxy['pass']) : null; - - if ($callback) { - call_user_func($callback, 'message', "Using HTTP proxy $host:$port"); - } + /** + * Get a list of the actual dependencies of installed packages that depend on + * a package. + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array + * @return array|false + */ + function getDependentPackageDependencies(&$pkg) + { + $data = $this->_getDepDB(); + if (is_object($pkg)) { + $channel = strtolower($pkg->getChannel()); + $package = strtolower($pkg->getPackage()); + } else { + $channel = strtolower($pkg['channel']); + $package = strtolower($pkg['package']); } - if (empty($port)) { - $port = (isset($info['scheme']) && $info['scheme'] == 'https') ? 443 : 80; + $depend = $this->getDependentPackages($pkg); + if (!$depend) { + return false; } - $scheme = (isset($info['scheme']) && $info['scheme'] == 'https') ? 'https' : 'http'; + $dependencies = array(); + foreach ($depend as $info) { + $temp = $this->getDependencies($info); + foreach ($temp as $dep) { + if ( + isset($dep['dep'], $dep['dep']['channel'], $dep['dep']['name']) && + strtolower($dep['dep']['channel']) == $channel && + strtolower($dep['dep']['name']) == $package + ) { + if (!isset($dependencies[$info['channel']])) { + $dependencies[$info['channel']] = array(); + } - if ($proxy_host != '') { - $fp = @fsockopen($proxy_host, $proxy_port, $errno, $errstr); - if (!$fp) { - if ($callback) { - call_user_func($callback, 'connfailed', array($proxy_host, $proxy_port, - $errno, $errstr)); + if (!isset($dependencies[$info['channel']][$info['package']])) { + $dependencies[$info['channel']][$info['package']] = array(); + } + $dependencies[$info['channel']][$info['package']][] = $dep; } - return PEAR::raiseError("Connection to `$proxy_host:$proxy_port' failed: $errstr", $errno); } + } - if ($lastmodified === false || $lastmodified) { - $request = "GET $url HTTP/1.1\r\n"; - $request .= "Host: $host:$port\r\n"; - } else { - $request = "GET $url HTTP/1.0\r\n"; - $request .= "Host: $host\r\n"; - } - } else { - $network_host = $host; - if (isset($info['scheme']) && $info['scheme'] == 'https') { - $network_host = 'ssl://' . $host; - } + return $dependencies; + } - $fp = @fsockopen($network_host, $port, $errno, $errstr); - if (!$fp) { - if ($callback) { - call_user_func($callback, 'connfailed', array($host, $port, - $errno, $errstr)); - } - return PEAR::raiseError("Connection to `$host:$port' failed: $errstr", $errno); - } + /** + * Get a list of dependencies of this installed package + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array + * @return array|false + */ + function getDependencies(&$pkg) + { + if (is_object($pkg)) { + $channel = strtolower($pkg->getChannel()); + $package = strtolower($pkg->getPackage()); + } else { + $channel = strtolower($pkg['channel']); + $package = strtolower($pkg['package']); + } - if ($lastmodified === false || $lastmodified) { - $request = "GET $path HTTP/1.1\r\n"; - $request .= "Host: $host:$port\r\n"; - } else { - $request = "GET $path HTTP/1.0\r\n"; - $request .= "Host: $host\r\n"; - } + $data = $this->_getDepDB(); + if (isset($data['dependencies'][$channel][$package])) { + return $data['dependencies'][$channel][$package]; } - $ifmodifiedsince = ''; - if (is_array($lastmodified)) { - if (isset($lastmodified['Last-Modified'])) { - $ifmodifiedsince = 'If-Modified-Since: ' . $lastmodified['Last-Modified'] . "\r\n"; - } + return false; + } - if (isset($lastmodified['ETag'])) { - $ifmodifiedsince .= "If-None-Match: $lastmodified[ETag]\r\n"; - } + /** + * Determine whether $parent depends on $child, near or deep + * @param array|PEAR_PackageFile_v2|PEAR_PackageFile_v2 + * @param array|PEAR_PackageFile_v2|PEAR_PackageFile_v2 + */ + function dependsOn($parent, $child) + { + $c = array(); + $this->_getDepDB(); + return $this->_dependsOn($parent, $child, $c); + } + + function _dependsOn($parent, $child, &$checked) + { + if (is_object($parent)) { + $channel = strtolower($parent->getChannel()); + $package = strtolower($parent->getPackage()); } else { - $ifmodifiedsince = ($lastmodified ? "If-Modified-Since: $lastmodified\r\n" : ''); + $channel = strtolower($parent['channel']); + $package = strtolower($parent['package']); } - $request .= $ifmodifiedsince . - "User-Agent: PEAR/1.8.0/PHP/" . PHP_VERSION . "\r\n"; - - if (isset($this)) { // only pass in authentication for non-static calls - $username = $config->get('username', null, $channel); - $password = $config->get('password', null, $channel); - if ($username && $password) { - $tmp = base64_encode("$username:$password"); - $request .= "Authorization: Basic $tmp\r\n"; - } + if (is_object($child)) { + $depchannel = strtolower($child->getChannel()); + $deppackage = strtolower($child->getPackage()); + } else { + $depchannel = strtolower($child['channel']); + $deppackage = strtolower($child['package']); } - if ($proxy_host != '' && $proxy_user != '') { - $request .= 'Proxy-Authorization: Basic ' . - base64_encode($proxy_user . ':' . $proxy_pass) . "\r\n"; + if (isset($checked[$channel][$package][$depchannel][$deppackage])) { + return false; // avoid endless recursion } - if ($accept) { - $request .= 'Accept: ' . implode(', ', $accept) . "\r\n"; + $checked[$channel][$package][$depchannel][$deppackage] = true; + if (!isset($this->_cache['dependencies'][$channel][$package])) { + return false; } - $request .= "Connection: close\r\n"; - $request .= "\r\n"; - fwrite($fp, $request); - $headers = array(); - $reply = 0; - while (trim($line = fgets($fp, 1024))) { - if (preg_match('/^([^:]+):\s+(.*)\s*\\z/', $line, $matches)) { - $headers[strtolower($matches[1])] = trim($matches[2]); - } elseif (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) { - $reply = (int)$matches[1]; - if ($reply == 304 && ($lastmodified || ($lastmodified === false))) { - return false; - } - - if (!in_array($reply, array(200, 301, 302, 303, 305, 307))) { - return PEAR::raiseError("File $scheme://$host:$port$path not valid (received: $line)"); + foreach ($this->_cache['dependencies'][$channel][$package] as $info) { + if (isset($info['dep']['uri'])) { + if (is_object($child)) { + if ($info['dep']['uri'] == $child->getURI()) { + return true; + } + } elseif (isset($child['uri'])) { + if ($info['dep']['uri'] == $child['uri']) { + return true; + } } + return false; } - } - if ($reply != 200) { - if (!isset($headers['location'])) { - return PEAR::raiseError("File $scheme://$host:$port$path not valid (redirected but no location)"); + if (strtolower($info['dep']['channel']) == $depchannel && + strtolower($info['dep']['name']) == $deppackage) { + return true; } + } - if ($wasredirect > 4) { - return PEAR::raiseError("File $scheme://$host:$port$path not valid (redirection looped more than 5 times)"); + foreach ($this->_cache['dependencies'][$channel][$package] as $info) { + if (isset($info['dep']['uri'])) { + if ($this->_dependsOn(array( + 'uri' => $info['dep']['uri'], + 'package' => $info['dep']['name']), $child, $checked)) { + return true; + } + } else { + if ($this->_dependsOn(array( + 'channel' => $info['dep']['channel'], + 'package' => $info['dep']['name']), $child, $checked)) { + return true; + } } - - $redirect = $wasredirect + 1; - return $this->downloadHttp($headers['location'], - $ui, $save_dir, $callback, $lastmodified, $accept); } - if (isset($headers['content-disposition']) && - preg_match('/\sfilename=\"([^;]*\S)\"\s*(;|\\z)/', $headers['content-disposition'], $matches)) { - $save_as = basename($matches[1]); - } else { - $save_as = basename($url); - } + return false; + } - if ($callback) { - $tmp = call_user_func($callback, 'saveas', $save_as); - if ($tmp) { - $save_as = $tmp; - } - } + /** + * Register dependencies of a package that is being installed or upgraded + * @param PEAR_PackageFile_v2|PEAR_PackageFile_v2 + */ + function installPackage(&$package) + { + $data = $this->_getDepDB(); + unset($this->_cache); + $this->_setPackageDeps($data, $package); + $this->_writeDepDB($data); + } - $dest_file = $save_dir . DIRECTORY_SEPARATOR . $save_as; - if (!$wp = @fopen($dest_file, 'wb')) { - fclose($fp); - if ($callback) { - call_user_func($callback, 'writefailed', array($dest_file, $php_errormsg)); - } - return PEAR::raiseError("could not open $dest_file for writing"); + /** + * Remove dependencies of a package that is being uninstalled, or upgraded. + * + * Upgraded packages first uninstall, then install + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array If an array, then it must have + * indices 'channel' and 'package' + */ + function uninstallPackage(&$pkg) + { + $data = $this->_getDepDB(); + unset($this->_cache); + if (is_object($pkg)) { + $channel = strtolower($pkg->getChannel()); + $package = strtolower($pkg->getPackage()); + } else { + $channel = strtolower($pkg['channel']); + $package = strtolower($pkg['package']); } - $length = isset($headers['content-length']) ? $headers['content-length'] : -1; - - $bytes = 0; - if ($callback) { - call_user_func($callback, 'start', array(basename($dest_file), $length)); + if (!isset($data['dependencies'][$channel][$package])) { + return true; } - while ($data = fread($fp, 1024)) { - $bytes += strlen($data); - if ($callback) { - call_user_func($callback, 'bytesread', $bytes); - } - if (!@fwrite($wp, $data)) { - fclose($fp); - if ($callback) { - call_user_func($callback, 'writefailed', array($dest_file, $php_errormsg)); + foreach ($data['dependencies'][$channel][$package] as $dep) { + $found = false; + $depchannel = isset($dep['dep']['uri']) ? '__uri' : strtolower($dep['dep']['channel']); + $depname = strtolower($dep['dep']['name']); + if (isset($data['packages'][$depchannel][$depname])) { + foreach ($data['packages'][$depchannel][$depname] as $i => $info) { + if ($info['channel'] == $channel && $info['package'] == $package) { + $found = true; + break; + } } - return PEAR::raiseError("$dest_file: write failed ($php_errormsg)"); } - } - fclose($fp); - fclose($wp); - if ($callback) { - call_user_func($callback, 'done', $bytes); - } - if ($lastmodified === false || $lastmodified) { - if (isset($headers['etag'])) { - $lastmodified = array('ETag' => $headers['etag']); - } - if (isset($headers['last-modified'])) { - if (is_array($lastmodified)) { - $lastmodified['Last-Modified'] = $headers['last-modified']; + if ($found) { + unset($data['packages'][$depchannel][$depname][$i]); + if (!count($data['packages'][$depchannel][$depname])) { + unset($data['packages'][$depchannel][$depname]); + if (!count($data['packages'][$depchannel])) { + unset($data['packages'][$depchannel]); + } } else { - $lastmodified = $headers['last-modified']; + $data['packages'][$depchannel][$depname] = + array_values($data['packages'][$depchannel][$depname]); } } - return array($dest_file, $lastmodified, $headers); } - return $dest_file; - } -} -// }}}PEAR-1.8.0/PEAR/ErrorStack.php100664 764 764 104210 100664 10662 - * @copyright 2004-2008 Greg Beaver - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: ErrorStack.php,v 1.29 2009/02/24 23:38:22 dufuz Exp $ - * @link http://pear.php.net/package/PEAR_ErrorStack - */ - -/** - * Singleton storage - * - * Format: - *
- * array(
- *  'package1' => PEAR_ErrorStack object,
- *  'package2' => PEAR_ErrorStack object,
- *  ...
- * )
- * 
- * @access private - * @global array $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] - */ -$GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] = array(); - -/** - * Global error callback (default) - * - * This is only used if set to non-false. * is the default callback for - * all packages, whereas specific packages may set a default callback - * for all instances, regardless of whether they are a singleton or not. - * - * To exclude non-singletons, only set the local callback for the singleton - * @see PEAR_ErrorStack::setDefaultCallback() - * @access private - * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] - */ -$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] = array( - '*' => false, -); - -/** - * Global Log object (default) - * - * This is only used if set to non-false. Use to set a default log object for - * all stacks, regardless of instantiation order or location - * @see PEAR_ErrorStack::setDefaultLogger() - * @access private - * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] - */ -$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = false; - -/** - * Global Overriding Callback - * - * This callback will override any error callbacks that specific loggers have set. - * Use with EXTREME caution - * @see PEAR_ErrorStack::staticPushCallback() - * @access private - * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] - */ -$GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array(); - -/**#@+ - * One of four possible return values from the error Callback - * @see PEAR_ErrorStack::_errorCallback() - */ -/** - * If this is returned, then the error will be both pushed onto the stack - * and logged. - */ -define('PEAR_ERRORSTACK_PUSHANDLOG', 1); -/** - * If this is returned, then the error will only be pushed onto the stack, - * and not logged. - */ -define('PEAR_ERRORSTACK_PUSH', 2); -/** - * If this is returned, then the error will only be logged, but not pushed - * onto the error stack. - */ -define('PEAR_ERRORSTACK_LOG', 3); -/** - * If this is returned, then the error is completely ignored. - */ -define('PEAR_ERRORSTACK_IGNORE', 4); -/** - * If this is returned, then the error is logged and die() is called. - */ -define('PEAR_ERRORSTACK_DIE', 5); -/**#@-*/ - -/** - * Error code for an attempt to instantiate a non-class as a PEAR_ErrorStack in - * the singleton method. - */ -define('PEAR_ERRORSTACK_ERR_NONCLASS', 1); - -/** - * Error code for an attempt to pass an object into {@link PEAR_ErrorStack::getMessage()} - * that has no __toString() method - */ -define('PEAR_ERRORSTACK_ERR_OBJTOSTRING', 2); -/** - * Error Stack Implementation - * - * Usage: - * - * // global error stack - * $global_stack = &PEAR_ErrorStack::singleton('MyPackage'); - * // local error stack - * $local_stack = new PEAR_ErrorStack('MyPackage'); - * - * @author Greg Beaver - * @version 1.8.0 - * @package PEAR_ErrorStack - * @category Debugging - * @copyright 2004-2008 Greg Beaver - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: ErrorStack.php,v 1.29 2009/02/24 23:38:22 dufuz Exp $ - * @link http://pear.php.net/package/PEAR_ErrorStack - */ -class PEAR_ErrorStack { - /** - * Errors are stored in the order that they are pushed on the stack. - * @since 0.4alpha Errors are no longer organized by error level. - * This renders pop() nearly unusable, and levels could be more easily - * handled in a callback anyway - * @var array - * @access private - */ - var $_errors = array(); - - /** - * Storage of errors by level. - * - * Allows easy retrieval and deletion of only errors from a particular level - * @since PEAR 1.4.0dev - * @var array - * @access private - */ - var $_errorsByLevel = array(); - - /** - * Package name this error stack represents - * @var string - * @access protected - */ - var $_package; - - /** - * Determines whether a PEAR_Error is thrown upon every error addition - * @var boolean - * @access private - */ - var $_compat = false; - - /** - * If set to a valid callback, this will be used to generate the error - * message from the error code, otherwise the message passed in will be - * used - * @var false|string|array - * @access private - */ - var $_msgCallback = false; - - /** - * If set to a valid callback, this will be used to generate the error - * context for an error. For PHP-related errors, this will be a file - * and line number as retrieved from debug_backtrace(), but can be - * customized for other purposes. The error might actually be in a separate - * configuration file, or in a database query. - * @var false|string|array - * @access protected - */ - var $_contextCallback = false; - - /** - * If set to a valid callback, this will be called every time an error - * is pushed onto the stack. The return value will be used to determine - * whether to allow an error to be pushed or logged. - * - * The return value must be one an PEAR_ERRORSTACK_* constant - * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG - * @var false|string|array - * @access protected - */ - var $_errorCallback = array(); - - /** - * PEAR::Log object for logging errors - * @var false|Log - * @access protected - */ - var $_logger = false; - - /** - * Error messages - designed to be overridden - * @var array - * @abstract - */ - var $_errorMsgs = array(); - - /** - * Set up a new error stack - * - * @param string $package name of the package this error stack represents - * @param callback $msgCallback callback used for error message generation - * @param callback $contextCallback callback used for context generation, - * defaults to {@link getFileLine()} - * @param boolean $throwPEAR_Error - */ - function PEAR_ErrorStack($package, $msgCallback = false, $contextCallback = false, - $throwPEAR_Error = false) - { - $this->_package = $package; - $this->setMessageCallback($msgCallback); - $this->setContextCallback($contextCallback); - $this->_compat = $throwPEAR_Error; - } - - /** - * Return a single error stack for this package. - * - * Note that all parameters are ignored if the stack for package $package - * has already been instantiated - * @param string $package name of the package this error stack represents - * @param callback $msgCallback callback used for error message generation - * @param callback $contextCallback callback used for context generation, - * defaults to {@link getFileLine()} - * @param boolean $throwPEAR_Error - * @param string $stackClass class to instantiate - * @static - * @return PEAR_ErrorStack - */ - function &singleton($package, $msgCallback = false, $contextCallback = false, - $throwPEAR_Error = false, $stackClass = 'PEAR_ErrorStack') - { - if (isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { - return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]; - } - if (!class_exists($stackClass)) { - if (function_exists('debug_backtrace')) { - $trace = debug_backtrace(); - } - PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_NONCLASS, - 'exception', array('stackclass' => $stackClass), - 'stack class "%stackclass%" is not a valid class name (should be like PEAR_ErrorStack)', - false, $trace); - } - $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package] = - new $stackClass($package, $msgCallback, $contextCallback, $throwPEAR_Error); - - return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]; - } - - /** - * Internal error handler for PEAR_ErrorStack class - * - * Dies if the error is an exception (and would have died anyway) - * @access private - */ - function _handleError($err) - { - if ($err['level'] == 'exception') { - $message = $err['message']; - if (isset($_SERVER['REQUEST_URI'])) { - echo '
'; - } else { - echo "\n"; - } - var_dump($err['context']); - die($message); - } - } - - /** - * Set up a PEAR::Log object for all error stacks that don't have one - * @param Log $log - * @static - */ - function setDefaultLogger(&$log) - { - if (is_object($log) && method_exists($log, 'log') ) { - $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log; - } elseif (is_callable($log)) { - $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log; - } - } - - /** - * Set up a PEAR::Log object for this error stack - * @param Log $log - */ - function setLogger(&$log) - { - if (is_object($log) && method_exists($log, 'log') ) { - $this->_logger = &$log; - } elseif (is_callable($log)) { - $this->_logger = &$log; - } - } - - /** - * Set an error code => error message mapping callback - * - * This method sets the callback that can be used to generate error - * messages for any instance - * @param array|string Callback function/method - */ - function setMessageCallback($msgCallback) - { - if (!$msgCallback) { - $this->_msgCallback = array(&$this, 'getErrorMessage'); - } else { - if (is_callable($msgCallback)) { - $this->_msgCallback = $msgCallback; - } - } - } - - /** - * Get an error code => error message mapping callback - * - * This method returns the current callback that can be used to generate error - * messages - * @return array|string|false Callback function/method or false if none - */ - function getMessageCallback() - { - return $this->_msgCallback; - } - - /** - * Sets a default callback to be used by all error stacks - * - * This method sets the callback that can be used to generate error - * messages for a singleton - * @param array|string Callback function/method - * @param string Package name, or false for all packages - * @static - */ - function setDefaultCallback($callback = false, $package = false) - { - if (!is_callable($callback)) { - $callback = false; - } - $package = $package ? $package : '*'; - $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$package] = $callback; - } - - /** - * Set a callback that generates context information (location of error) for an error stack - * - * This method sets the callback that can be used to generate context - * information for an error. Passing in NULL will disable context generation - * and remove the expensive call to debug_backtrace() - * @param array|string|null Callback function/method - */ - function setContextCallback($contextCallback) - { - if ($contextCallback === null) { - return $this->_contextCallback = false; - } - if (!$contextCallback) { - $this->_contextCallback = array(&$this, 'getFileLine'); - } else { - if (is_callable($contextCallback)) { - $this->_contextCallback = $contextCallback; - } - } - } - - /** - * Set an error Callback - * If set to a valid callback, this will be called every time an error - * is pushed onto the stack. The return value will be used to determine - * whether to allow an error to be pushed or logged. - * - * The return value must be one of the ERRORSTACK_* constants. - * - * This functionality can be used to emulate PEAR's pushErrorHandling, and - * the PEAR_ERROR_CALLBACK mode, without affecting the integrity of - * the error stack or logging - * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG - * @see popCallback() - * @param string|array $cb - */ - function pushCallback($cb) - { - array_push($this->_errorCallback, $cb); - } - - /** - * Remove a callback from the error callback stack - * @see pushCallback() - * @return array|string|false - */ - function popCallback() - { - if (!count($this->_errorCallback)) { - return false; - } - return array_pop($this->_errorCallback); - } - - /** - * Set a temporary overriding error callback for every package error stack - * - * Use this to temporarily disable all existing callbacks (can be used - * to emulate the @ operator, for instance) - * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG - * @see staticPopCallback(), pushCallback() - * @param string|array $cb - * @static - */ - function staticPushCallback($cb) - { - array_push($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'], $cb); - } - - /** - * Remove a temporary overriding error callback - * @see staticPushCallback() - * @return array|string|false - * @static - */ - function staticPopCallback() - { - $ret = array_pop($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK']); - if (!is_array($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'])) { - $GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array(); - } - return $ret; - } - - /** - * Add an error to the stack - * - * If the message generator exists, it is called with 2 parameters. - * - the current Error Stack object - * - an array that is in the same format as an error. Available indices - * are 'code', 'package', 'time', 'params', 'level', and 'context' - * - * Next, if the error should contain context information, this is - * handled by the context grabbing method. - * Finally, the error is pushed onto the proper error stack - * @param int $code Package-specific error code - * @param string $level Error level. This is NOT spell-checked - * @param array $params associative array of error parameters - * @param string $msg Error message, or a portion of it if the message - * is to be generated - * @param array $repackage If this error re-packages an error pushed by - * another package, place the array returned from - * {@link pop()} in this parameter - * @param array $backtrace Protected parameter: use this to pass in the - * {@link debug_backtrace()} that should be used - * to find error context - * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also - * thrown. If a PEAR_Error is returned, the userinfo - * property is set to the following array: - * - * - * array( - * 'code' => $code, - * 'params' => $params, - * 'package' => $this->_package, - * 'level' => $level, - * 'time' => time(), - * 'context' => $context, - * 'message' => $msg, - * //['repackage' => $err] repackaged error array/Exception class - * ); - * - * - * Normally, the previous array is returned. - */ - function push($code, $level = 'error', $params = array(), $msg = false, - $repackage = false, $backtrace = false) - { - $context = false; - // grab error context - if ($this->_contextCallback) { - if (!$backtrace) { - $backtrace = debug_backtrace(); - } - $context = call_user_func($this->_contextCallback, $code, $params, $backtrace); - } - - // save error - $time = explode(' ', microtime()); - $time = $time[1] + $time[0]; - $err = array( - 'code' => $code, - 'params' => $params, - 'package' => $this->_package, - 'level' => $level, - 'time' => $time, - 'context' => $context, - 'message' => $msg, - ); - - if ($repackage) { - $err['repackage'] = $repackage; - } - - // set up the error message, if necessary - if ($this->_msgCallback) { - $msg = call_user_func_array($this->_msgCallback, - array(&$this, $err)); - $err['message'] = $msg; - } - $push = $log = true; - $die = false; - // try the overriding callback first - $callback = $this->staticPopCallback(); - if ($callback) { - $this->staticPushCallback($callback); - } - if (!is_callable($callback)) { - // try the local callback next - $callback = $this->popCallback(); - if (is_callable($callback)) { - $this->pushCallback($callback); - } else { - // try the default callback - $callback = isset($GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package]) ? - $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package] : - $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']['*']; - } - } - if (is_callable($callback)) { - switch(call_user_func($callback, $err)){ - case PEAR_ERRORSTACK_IGNORE: - return $err; - break; - case PEAR_ERRORSTACK_PUSH: - $log = false; - break; - case PEAR_ERRORSTACK_LOG: - $push = false; - break; - case PEAR_ERRORSTACK_DIE: - $die = true; - break; - // anything else returned has the same effect as pushandlog - } - } - if ($push) { - array_unshift($this->_errors, $err); - if (!isset($this->_errorsByLevel[$err['level']])) { - $this->_errorsByLevel[$err['level']] = array(); - } - $this->_errorsByLevel[$err['level']][] = &$this->_errors[0]; - } - if ($log) { - if ($this->_logger || $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']) { - $this->_log($err); - } - } - if ($die) { - die(); - } - if ($this->_compat && $push) { - return $this->raiseError($msg, $code, null, null, $err); - } - return $err; - } - - /** - * Static version of {@link push()} - * - * @param string $package Package name this error belongs to - * @param int $code Package-specific error code - * @param string $level Error level. This is NOT spell-checked - * @param array $params associative array of error parameters - * @param string $msg Error message, or a portion of it if the message - * is to be generated - * @param array $repackage If this error re-packages an error pushed by - * another package, place the array returned from - * {@link pop()} in this parameter - * @param array $backtrace Protected parameter: use this to pass in the - * {@link debug_backtrace()} that should be used - * to find error context - * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also - * thrown. see docs for {@link push()} - * @static - */ - function staticPush($package, $code, $level = 'error', $params = array(), - $msg = false, $repackage = false, $backtrace = false) - { - $s = &PEAR_ErrorStack::singleton($package); - if ($s->_contextCallback) { - if (!$backtrace) { - if (function_exists('debug_backtrace')) { - $backtrace = debug_backtrace(); - } - } - } - return $s->push($code, $level, $params, $msg, $repackage, $backtrace); - } - - /** - * Log an error using PEAR::Log - * @param array $err Error array - * @param array $levels Error level => Log constant map - * @access protected - */ - function _log($err) - { - if ($this->_logger) { - $logger = &$this->_logger; - } else { - $logger = &$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']; - } - if (is_a($logger, 'Log')) { - $levels = array( - 'exception' => PEAR_LOG_CRIT, - 'alert' => PEAR_LOG_ALERT, - 'critical' => PEAR_LOG_CRIT, - 'error' => PEAR_LOG_ERR, - 'warning' => PEAR_LOG_WARNING, - 'notice' => PEAR_LOG_NOTICE, - 'info' => PEAR_LOG_INFO, - 'debug' => PEAR_LOG_DEBUG); - if (isset($levels[$err['level']])) { - $level = $levels[$err['level']]; - } else { - $level = PEAR_LOG_INFO; - } - $logger->log($err['message'], $level, $err); - } else { // support non-standard logs - call_user_func($logger, $err); - } - } - - - /** - * Pop an error off of the error stack - * - * @return false|array - * @since 0.4alpha it is no longer possible to specify a specific error - * level to return - the last error pushed will be returned, instead - */ - function pop() - { - $err = @array_shift($this->_errors); - if (!is_null($err)) { - @array_pop($this->_errorsByLevel[$err['level']]); - if (!count($this->_errorsByLevel[$err['level']])) { - unset($this->_errorsByLevel[$err['level']]); - } - } - return $err; - } - - /** - * Pop an error off of the error stack, static method - * - * @param string package name - * @return boolean - * @since PEAR1.5.0a1 - */ - function staticPop($package) - { - if ($package) { - if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { - return false; - } - return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->pop(); - } - } - - /** - * Determine whether there are any errors on the stack - * @param string|array Level name. Use to determine if any errors - * of level (string), or levels (array) have been pushed - * @return boolean - */ - function hasErrors($level = false) - { - if ($level) { - return isset($this->_errorsByLevel[$level]); - } - return count($this->_errors); - } - - /** - * Retrieve all errors since last purge - * - * @param boolean set in order to empty the error stack - * @param string level name, to return only errors of a particular severity - * @return array - */ - function getErrors($purge = false, $level = false) - { - if (!$purge) { - if ($level) { - if (!isset($this->_errorsByLevel[$level])) { - return array(); - } else { - return $this->_errorsByLevel[$level]; - } - } else { - return $this->_errors; - } - } - if ($level) { - $ret = $this->_errorsByLevel[$level]; - foreach ($this->_errorsByLevel[$level] as $i => $unused) { - // entries are references to the $_errors array - $this->_errorsByLevel[$level][$i] = false; - } - // array_filter removes all entries === false - $this->_errors = array_filter($this->_errors); - unset($this->_errorsByLevel[$level]); - return $ret; - } - $ret = $this->_errors; - $this->_errors = array(); - $this->_errorsByLevel = array(); - return $ret; - } - - /** - * Determine whether there are any errors on a single error stack, or on any error stack - * - * The optional parameter can be used to test the existence of any errors without the need of - * singleton instantiation - * @param string|false Package name to check for errors - * @param string Level name to check for a particular severity - * @return boolean - * @static - */ - function staticHasErrors($package = false, $level = false) - { - if ($package) { - if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { - return false; - } - return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->hasErrors($level); - } - foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) { - if ($obj->hasErrors($level)) { - return true; - } - } - return false; - } - - /** - * Get a list of all errors since last purge, organized by package - * @since PEAR 1.4.0dev BC break! $level is now in the place $merge used to be - * @param boolean $purge Set to purge the error stack of existing errors - * @param string $level Set to a level name in order to retrieve only errors of a particular level - * @param boolean $merge Set to return a flat array, not organized by package - * @param array $sortfunc Function used to sort a merged array - default - * sorts by time, and should be good for most cases - * @static - * @return array - */ - function staticGetErrors($purge = false, $level = false, $merge = false, - $sortfunc = array('PEAR_ErrorStack', '_sortErrors')) - { - $ret = array(); - if (!is_callable($sortfunc)) { - $sortfunc = array('PEAR_ErrorStack', '_sortErrors'); - } - foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) { - $test = $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->getErrors($purge, $level); - if ($test) { - if ($merge) { - $ret = array_merge($ret, $test); - } else { - $ret[$package] = $test; - } - } - } - if ($merge) { - usort($ret, $sortfunc); - } - return $ret; - } - - /** - * Error sorting function, sorts by time - * @access private - */ - function _sortErrors($a, $b) - { - if ($a['time'] == $b['time']) { - return 0; - } - if ($a['time'] < $b['time']) { - return 1; - } - return -1; - } - - /** - * Standard file/line number/function/class context callback - * - * This function uses a backtrace generated from {@link debug_backtrace()} - * and so will not work at all in PHP < 4.3.0. The frame should - * reference the frame that contains the source of the error. - * @return array|false either array('file' => file, 'line' => line, - * 'function' => function name, 'class' => class name) or - * if this doesn't work, then false - * @param unused - * @param integer backtrace frame. - * @param array Results of debug_backtrace() - * @static - */ - function getFileLine($code, $params, $backtrace = null) - { - if ($backtrace === null) { - return false; - } - $frame = 0; - $functionframe = 1; - if (!isset($backtrace[1])) { - $functionframe = 0; - } else { - while (isset($backtrace[$functionframe]['function']) && - $backtrace[$functionframe]['function'] == 'eval' && - isset($backtrace[$functionframe + 1])) { - $functionframe++; - } - } - if (isset($backtrace[$frame])) { - if (!isset($backtrace[$frame]['file'])) { - $frame++; - } - $funcbacktrace = $backtrace[$functionframe]; - $filebacktrace = $backtrace[$frame]; - $ret = array('file' => $filebacktrace['file'], - 'line' => $filebacktrace['line']); - // rearrange for eval'd code or create function errors - if (strpos($filebacktrace['file'], '(') && - preg_match(';^(.*?)\((\d+)\) : (.*?)\\z;', $filebacktrace['file'], - $matches)) { - $ret['file'] = $matches[1]; - $ret['line'] = $matches[2] + 0; - } - if (isset($funcbacktrace['function']) && isset($backtrace[1])) { - if ($funcbacktrace['function'] != 'eval') { - if ($funcbacktrace['function'] == '__lambda_func') { - $ret['function'] = 'create_function() code'; - } else { - $ret['function'] = $funcbacktrace['function']; - } - } - } - if (isset($funcbacktrace['class']) && isset($backtrace[1])) { - $ret['class'] = $funcbacktrace['class']; - } - return $ret; - } - return false; - } - - /** - * Standard error message generation callback - * - * This method may also be called by a custom error message generator - * to fill in template values from the params array, simply - * set the third parameter to the error message template string to use - * - * The special variable %__msg% is reserved: use it only to specify - * where a message passed in by the user should be placed in the template, - * like so: - * - * Error message: %msg% - internal error - * - * If the message passed like so: - * - * - * $stack->push(ERROR_CODE, 'error', array(), 'server error 500'); - * - * - * The returned error message will be "Error message: server error 500 - - * internal error" - * @param PEAR_ErrorStack - * @param array - * @param string|false Pre-generated error message template - * @static - * @return string - */ - function getErrorMessage(&$stack, $err, $template = false) - { - if ($template) { - $mainmsg = $template; - } else { - $mainmsg = $stack->getErrorMessageTemplate($err['code']); - } - $mainmsg = str_replace('%__msg%', $err['message'], $mainmsg); - if (is_array($err['params']) && count($err['params'])) { - foreach ($err['params'] as $name => $val) { - if (is_array($val)) { - // @ is needed in case $val is a multi-dimensional array - $val = @implode(', ', $val); - } - if (is_object($val)) { - if (method_exists($val, '__toString')) { - $val = $val->__toString(); - } else { - PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_OBJTOSTRING, - 'warning', array('obj' => get_class($val)), - 'object %obj% passed into getErrorMessage, but has no __toString() method'); - $val = 'Object'; - } - } - $mainmsg = str_replace('%' . $name . '%', $val, $mainmsg); - } - } - return $mainmsg; - } - - /** - * Standard Error Message Template generator from code - * @return string - */ - function getErrorMessageTemplate($code) - { - if (!isset($this->_errorMsgs[$code])) { - return '%__msg%'; - } - return $this->_errorMsgs[$code]; - } - - /** - * Set the Error Message Template array - * - * The array format must be: - *
-     * array(error code => 'message template',...)
-     * 
- * - * Error message parameters passed into {@link push()} will be used as input - * for the error message. If the template is 'message %foo% was %bar%', and the - * parameters are array('foo' => 'one', 'bar' => 'six'), the error message returned will - * be 'message one was six' - * @return string - */ - function setErrorMessageTemplate($template) - { - $this->_errorMsgs = $template; - } - - - /** - * emulate PEAR::raiseError() - * - * @return PEAR_Error - */ - function raiseError() - { - require_once 'PEAR.php'; - $args = func_get_args(); - return call_user_func_array(array('PEAR', 'raiseError'), $args); - } -} -$stack = &PEAR_ErrorStack::singleton('PEAR_ErrorStack'); -$stack->pushCallback(array('PEAR_ErrorStack', '_handleError')); -?> -PEAR-1.8.0/PEAR/Exception.php100664 764 764 33642 100664 10533 - * @author Hans Lellelid - * @author Bertrand Mansion - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Exception.php,v 1.30 2009/02/24 23:38:22 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.3.3 - */ - - -/** - * Base PEAR_Exception Class - * - * 1) Features: - * - * - Nestable exceptions (throw new PEAR_Exception($msg, $prev_exception)) - * - Definable triggers, shot when exceptions occur - * - Pretty and informative error messages - * - Added more context info available (like class, method or cause) - * - cause can be a PEAR_Exception or an array of mixed - * PEAR_Exceptions/PEAR_ErrorStack warnings - * - callbacks for specific exception classes and their children - * - * 2) Ideas: - * - * - Maybe a way to define a 'template' for the output - * - * 3) Inherited properties from PHP Exception Class: - * - * protected $message - * protected $code - * protected $line - * protected $file - * private $trace - * - * 4) Inherited methods from PHP Exception Class: - * - * __clone - * __construct - * getMessage - * getCode - * getFile - * getLine - * getTraceSafe - * getTraceSafeAsString - * __toString - * - * 5) Usage example - * - * - * require_once 'PEAR/Exception.php'; - * - * class Test { - * function foo() { - * throw new PEAR_Exception('Error Message', ERROR_CODE); - * } - * } - * - * function myLogger($pear_exception) { - * echo $pear_exception->getMessage(); - * } - * // each time a exception is thrown the 'myLogger' will be called - * // (its use is completely optional) - * PEAR_Exception::addObserver('myLogger'); - * $test = new Test; - * try { - * $test->foo(); - * } catch (PEAR_Exception $e) { - * print $e; - * } - * - * - * @category pear - * @package PEAR - * @author Tomas V.V.Cox - * @author Hans Lellelid - * @author Bertrand Mansion - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.3.3 - * - */ -class PEAR_Exception extends Exception -{ - const OBSERVER_PRINT = -2; - const OBSERVER_TRIGGER = -4; - const OBSERVER_DIE = -8; - protected $cause; - private static $_observers = array(); - private static $_uniqueid = 0; - private $_trace; - - /** - * Supported signatures: - * - PEAR_Exception(string $message); - * - PEAR_Exception(string $message, int $code); - * - PEAR_Exception(string $message, Exception $cause); - * - PEAR_Exception(string $message, Exception $cause, int $code); - * - PEAR_Exception(string $message, PEAR_Error $cause); - * - PEAR_Exception(string $message, PEAR_Error $cause, int $code); - * - PEAR_Exception(string $message, array $causes); - * - PEAR_Exception(string $message, array $causes, int $code); - * @param string exception message - * @param int|Exception|PEAR_Error|array|null exception cause - * @param int|null exception code or null - */ - public function __construct($message, $p2 = null, $p3 = null) - { - if (is_int($p2)) { - $code = $p2; - $this->cause = null; - } elseif (is_object($p2) || is_array($p2)) { - // using is_object allows both Exception and PEAR_Error - if (is_object($p2) && !($p2 instanceof Exception)) { - if (!class_exists('PEAR_Error') || !($p2 instanceof PEAR_Error)) { - throw new PEAR_Exception('exception cause must be Exception, ' . - 'array, or PEAR_Error'); - } - } - $code = $p3; - if (is_array($p2) && isset($p2['message'])) { - // fix potential problem of passing in a single warning - $p2 = array($p2); - } - $this->cause = $p2; - } else { - $code = null; - $this->cause = null; - } - parent::__construct($message, $code); - $this->signal(); - } - - /** - * @param mixed $callback - A valid php callback, see php func is_callable() - * - A PEAR_Exception::OBSERVER_* constant - * - An array(const PEAR_Exception::OBSERVER_*, - * mixed $options) - * @param string $label The name of the observer. Use this if you want - * to remove it later with removeObserver() - */ - public static function addObserver($callback, $label = 'default') - { - self::$_observers[$label] = $callback; - } - - public static function removeObserver($label = 'default') - { - unset(self::$_observers[$label]); - } - - /** - * @return int unique identifier for an observer - */ - public static function getUniqueId() - { - return self::$_uniqueid++; - } - - private function signal() - { - foreach (self::$_observers as $func) { - if (is_callable($func)) { - call_user_func($func, $this); - continue; - } - settype($func, 'array'); - switch ($func[0]) { - case self::OBSERVER_PRINT : - $f = (isset($func[1])) ? $func[1] : '%s'; - printf($f, $this->getMessage()); - break; - case self::OBSERVER_TRIGGER : - $f = (isset($func[1])) ? $func[1] : E_USER_NOTICE; - trigger_error($this->getMessage(), $f); - break; - case self::OBSERVER_DIE : - $f = (isset($func[1])) ? $func[1] : '%s'; - die(printf($f, $this->getMessage())); - break; - default: - trigger_error('invalid observer type', E_USER_WARNING); - } - } - } - - /** - * Return specific error information that can be used for more detailed - * error messages or translation. - * - * This method may be overridden in child exception classes in order - * to add functionality not present in PEAR_Exception and is a placeholder - * to define API - * - * The returned array must be an associative array of parameter => value like so: - *
-     * array('name' => $name, 'context' => array(...))
-     * 
- * @return array - */ - public function getErrorData() - { - return array(); - } - - /** - * Returns the exception that caused this exception to be thrown - * @access public - * @return Exception|array The context of the exception - */ - public function getCause() - { - return $this->cause; - } - - /** - * Function must be public to call on caused exceptions - * @param array - */ - public function getCauseMessage(&$causes) - { - $trace = $this->getTraceSafe(); - $cause = array('class' => get_class($this), - 'message' => $this->message, - 'file' => 'unknown', - 'line' => 'unknown'); - if (isset($trace[0])) { - if (isset($trace[0]['file'])) { - $cause['file'] = $trace[0]['file']; - $cause['line'] = $trace[0]['line']; - } - } - $causes[] = $cause; - if ($this->cause instanceof PEAR_Exception) { - $this->cause->getCauseMessage($causes); - } elseif ($this->cause instanceof Exception) { - $causes[] = array('class' => get_class($this->cause), - 'message' => $this->cause->getMessage(), - 'file' => $this->cause->getFile(), - 'line' => $this->cause->getLine()); - } elseif (class_exists('PEAR_Error') && $this->cause instanceof PEAR_Error) { - $causes[] = array('class' => get_class($this->cause), - 'message' => $this->cause->getMessage(), - 'file' => 'unknown', - 'line' => 'unknown'); - } elseif (is_array($this->cause)) { - foreach ($this->cause as $cause) { - if ($cause instanceof PEAR_Exception) { - $cause->getCauseMessage($causes); - } elseif ($cause instanceof Exception) { - $causes[] = array('class' => get_class($cause), - 'message' => $cause->getMessage(), - 'file' => $cause->getFile(), - 'line' => $cause->getLine()); - } elseif (class_exists('PEAR_Error') && $cause instanceof PEAR_Error) { - $causes[] = array('class' => get_class($cause), - 'message' => $cause->getMessage(), - 'file' => 'unknown', - 'line' => 'unknown'); - } elseif (is_array($cause) && isset($cause['message'])) { - // PEAR_ErrorStack warning - $causes[] = array( - 'class' => $cause['package'], - 'message' => $cause['message'], - 'file' => isset($cause['context']['file']) ? - $cause['context']['file'] : - 'unknown', - 'line' => isset($cause['context']['line']) ? - $cause['context']['line'] : - 'unknown', - ); - } - } - } - } - - public function getTraceSafe() - { - if (!isset($this->_trace)) { - $this->_trace = $this->getTrace(); - if (empty($this->_trace)) { - $backtrace = debug_backtrace(); - $this->_trace = array($backtrace[count($backtrace)-1]); - } - } - return $this->_trace; - } - - public function getErrorClass() - { - $trace = $this->getTraceSafe(); - return $trace[0]['class']; - } - - public function getErrorMethod() - { - $trace = $this->getTraceSafe(); - return $trace[0]['function']; - } - - public function __toString() - { - if (isset($_SERVER['REQUEST_URI'])) { - return $this->toHtml(); - } - return $this->toText(); - } - - public function toHtml() - { - $trace = $this->getTraceSafe(); - $causes = array(); - $this->getCauseMessage($causes); - $html = '' . "\n"; - foreach ($causes as $i => $cause) { - $html .= '\n"; - } - $html .= '' . "\n" - . '' - . '' - . '' . "\n"; - - foreach ($trace as $k => $v) { - $html .= '' - . '' - . '' . "\n"; - } - $html .= '' - . '' - . '' . "\n" - . '
' - . str_repeat('-', $i) . ' ' . $cause['class'] . ': ' - . htmlspecialchars($cause['message']) . ' in ' . $cause['file'] . ' ' - . 'on line ' . $cause['line'] . '' - . "
Exception trace
#FunctionLocation
' . $k . ''; - if (!empty($v['class'])) { - $html .= $v['class'] . $v['type']; - } - $html .= $v['function']; - $args = array(); - if (!empty($v['args'])) { - foreach ($v['args'] as $arg) { - if (is_null($arg)) $args[] = 'null'; - elseif (is_array($arg)) $args[] = 'Array'; - elseif (is_object($arg)) $args[] = 'Object('.get_class($arg).')'; - elseif (is_bool($arg)) $args[] = $arg ? 'true' : 'false'; - elseif (is_int($arg) || is_double($arg)) $args[] = $arg; - else { - $arg = (string)$arg; - $str = htmlspecialchars(substr($arg, 0, 16)); - if (strlen($arg) > 16) $str .= '…'; - $args[] = "'" . $str . "'"; - } - } - } - $html .= '(' . implode(', ',$args) . ')' - . '' . (isset($v['file']) ? $v['file'] : 'unknown') - . ':' . (isset($v['line']) ? $v['line'] : 'unknown') - . '
' . ($k+1) . '{main} 
'; - return $html; - } - - public function toText() - { - $causes = array(); - $this->getCauseMessage($causes); - $causeMsg = ''; - foreach ($causes as $i => $cause) { - $causeMsg .= str_repeat(' ', $i) . $cause['class'] . ': ' - . $cause['message'] . ' in ' . $cause['file'] - . ' on line ' . $cause['line'] . "\n"; - } - return $causeMsg . $this->getTraceAsString(); - } -} - -?>PEAR-1.8.0/PEAR/FixPHP5PEARWarnings.php100777 764 764 231 100777 12077 PEAR-1.8.0/PEAR/Frontend.php100664 764 764 15445 100664 10355 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Frontend.php,v 1.18 2009/02/24 23:38:22 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * Include error handling - */ -//require_once 'PEAR.php'; - -/** - * Which user interface class is being used. - * @var string class name - */ -$GLOBALS['_PEAR_FRONTEND_CLASS'] = 'PEAR_Frontend_CLI'; - -/** - * Instance of $_PEAR_Command_uiclass. - * @var object - */ -$GLOBALS['_PEAR_FRONTEND_SINGLETON'] = null; - -/** - * Singleton-based frontend for PEAR user input/output - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Frontend extends PEAR -{ - /** - * Retrieve the frontend object - * @return PEAR_Frontend_CLI|PEAR_Frontend_Web|PEAR_Frontend_Gtk - * @static - */ - function &singleton($type = null) - { - if ($type === null) { - if (!isset($GLOBALS['_PEAR_FRONTEND_SINGLETON'])) { - $a = false; - return $a; - } - return $GLOBALS['_PEAR_FRONTEND_SINGLETON']; - } - - $a = PEAR_Frontend::setFrontendClass($type); - return $a; - } - - /** - * Set the frontend class that will be used by calls to {@link singleton()} - * - * Frontends are expected to conform to the PEAR naming standard of - * _ => DIRECTORY_SEPARATOR (PEAR_Frontend_CLI is in PEAR/Frontend/CLI.php) - * @param string $uiclass full class name - * @return PEAR_Frontend - * @static - */ - function &setFrontendClass($uiclass) - { - if (is_object($GLOBALS['_PEAR_FRONTEND_SINGLETON']) && - is_a($GLOBALS['_PEAR_FRONTEND_SINGLETON'], $uiclass)) { - return $GLOBALS['_PEAR_FRONTEND_SINGLETON']; - } - - if (!class_exists($uiclass)) { - $file = str_replace('_', '/', $uiclass) . '.php'; - if (PEAR_Frontend::isIncludeable($file)) { - include_once $file; - } - } - - if (class_exists($uiclass)) { - $obj = &new $uiclass; - // quick test to see if this class implements a few of the most - // important frontend methods - if (is_a($obj, 'PEAR_Frontend')) { - $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = &$obj; - $GLOBALS['_PEAR_FRONTEND_CLASS'] = $uiclass; - return $obj; - } - - $err = PEAR::raiseError("not a frontend class: $uiclass"); - return $err; - } - - $err = PEAR::raiseError("no such class: $uiclass"); - return $err; - } - - /** - * Set the frontend class that will be used by calls to {@link singleton()} - * - * Frontends are expected to be a descendant of PEAR_Frontend - * @param PEAR_Frontend - * @return PEAR_Frontend - * @static - */ - function &setFrontendObject($uiobject) - { - if (is_object($GLOBALS['_PEAR_FRONTEND_SINGLETON']) && - is_a($GLOBALS['_PEAR_FRONTEND_SINGLETON'], get_class($uiobject))) { - return $GLOBALS['_PEAR_FRONTEND_SINGLETON']; - } - - if (!is_a($uiobject, 'PEAR_Frontend')) { - $err = PEAR::raiseError('not a valid frontend class: (' . - get_class($uiobject) . ')'); - return $err; - } - - $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = &$uiobject; - $GLOBALS['_PEAR_FRONTEND_CLASS'] = get_class($uiobject); - return $uiobject; - } - - /** - * @param string $path relative or absolute include path - * @return boolean - * @static - */ - function isIncludeable($path) - { - if (file_exists($path) && is_readable($path)) { - return true; - } - - $fp = @fopen($path, 'r', true); - if ($fp) { - fclose($fp); - return true; - } - - return false; - } - - /** - * @param PEAR_Config - */ - function setConfig(&$config) - { - } - - /** - * This can be overridden to allow session-based temporary file management - * - * By default, all files are deleted at the end of a session. The web installer - * needs to be able to sustain a list over many sessions in order to support - * user interaction with install scripts - */ - function addTempFile($file) - { - $GLOBALS['_PEAR_Common_tempfiles'][] = $file; - } - - /** - * Log an action - * - * @param string $msg the message to log - * @param boolean $append_crlf - * @return boolean true - * @abstract - */ - function log($msg, $append_crlf = true) - { - } - - /** - * Run a post-installation script - * - * @param array $scripts array of post-install scripts - * @abstract - */ - function runPostinstallScripts(&$scripts) - { - } - - /** - * Display human-friendly output formatted depending on the - * $command parameter. - * - * This should be able to handle basic output data with no command - * @param mixed $data data structure containing the information to display - * @param string $command command from which this method was called - * @abstract - */ - function outputData($data, $command = '_default') - { - } - - /** - * Display a modal form dialog and return the given input - * - * A frontend that requires multiple requests to retrieve and process - * data must take these needs into account, and implement the request - * handling code. - * @param string $command command from which this method was called - * @param array $prompts associative array. keys are the input field names - * and values are the description - * @param array $types array of input field types (text, password, - * etc.) keys have to be the same like in $prompts - * @param array $defaults array of default values. again keys have - * to be the same like in $prompts. Do not depend - * on a default value being set. - * @return array input sent by the user - * @abstract - */ - function userDialog($command, $prompts, $types = array(), $defaults = array()) - { - } -}PEAR-1.8.0/PEAR/Installer.php100664 764 764 211556 100664 10554 - * @author Tomas V.V. Cox - * @author Martin Jansen - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Installer.php,v 1.259 2009/04/09 00:55:07 dufuz Exp $ - * @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'; + unset($data['dependencies'][$channel][$package]); + if (!count($data['dependencies'][$channel])) { + unset($data['dependencies'][$channel]); + } -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 - * @author Tomas V.V. Cox - * @author Martin Jansen - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 - */ -class PEAR_Installer extends PEAR_Downloader -{ - // {{{ properties + if (!count($data['dependencies'])) { + unset($data['dependencies']); + } - /** name of the package directory, for example Foo-1.0 - * @var string - */ - var $pkgdir; + if (!count($data['packages'])) { + unset($data['packages']); + } - /** directory where PHP code files go - * @var string - */ - var $phpdir; + $this->_writeDepDB($data); + } - /** directory where PHP extension files go - * @var string + /** + * Rebuild the dependency DB by reading registry entries. + * @return true|PEAR_Error */ - var $extdir; + function rebuildDB() + { + $depdb = array('_version' => $this->_version); + if (!$this->hasWriteAccess()) { + // allow startup for read-only with older Registry + return $depdb; + } - /** directory where documentation goes - * @var string - */ - var $docdir; + $packages = $this->_registry->listAllPackages(); + if (PEAR::isError($packages)) { + return $packages; + } - /** installation root directory (ala PHP's INSTALL_ROOT or - * automake's DESTDIR - * @var string - */ - var $installroot = ''; + foreach ($packages as $channel => $ps) { + foreach ($ps as $package) { + $package = $this->_registry->getPackage($package, $channel); + if (PEAR::isError($package)) { + return $package; + } + $this->_setPackageDeps($depdb, $package); + } + } - /** debug level - * @var int - */ - var $debug = 1; + $error = $this->_writeDepDB($depdb); + if (PEAR::isError($error)) { + return $error; + } - /** temporary directory - * @var string - */ - var $tmpdir; + $this->_cache = $depdb; + return true; + } /** - * PEAR_Registry object used by the installer - * @var PEAR_Registry + * Register usage of the dependency DB to prevent race conditions + * @param int one of the LOCK_* constants + * @return true|PEAR_Error + * @access private */ - var $registry; + function _lock($mode = LOCK_EX) + { + if (stristr(php_uname(), 'Windows 9')) { + return true; + } - /** - * array of PEAR_Downloader_Packages - * @var array - */ - var $_downloadedPackages; + if ($mode != LOCK_UN && is_resource($this->_lockFp)) { + // XXX does not check type of lock (LOCK_SH/LOCK_EX) + return true; + } - /** 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(); + $open_mode = 'w'; + // XXX People reported problems with LOCK_SH and 'w' + if ($mode === LOCK_SH) { + if (!file_exists($this->_lockfile)) { + touch($this->_lockfile); + } elseif (!is_file($this->_lockfile)) { + return PEAR::raiseError('could not create Dependency lock file, ' . + 'it exists and is not a regular file'); + } + $open_mode = 'r'; + } - // }}} + if (!is_resource($this->_lockFp)) { + $this->_lockFp = @fopen($this->_lockfile, $open_mode); + } - // {{{ constructor + if (!is_resource($this->_lockFp)) { + return PEAR::raiseError("could not create Dependency lock file" . + (isset($php_errormsg) ? ": " . $php_errormsg : "")); + } - /** - * PEAR_Installer constructor. - * - * @param object $ui user interface object (instance of PEAR_Frontend_*) - * - * @access public - */ - function PEAR_Installer(&$ui) - { - parent::PEAR_Common(); - $this->setFrontendObject($ui); - $this->debug = $this->config->get('verbose'); - } + if (!(int)flock($this->_lockFp, $mode)) { + switch ($mode) { + case LOCK_SH: $str = 'shared'; break; + case LOCK_EX: $str = 'exclusive'; break; + case LOCK_UN: $str = 'unlock'; break; + default: $str = 'unknown'; break; + } - function setOptions($options) - { - $this->_options = $options; - } + return PEAR::raiseError("could not acquire $str lock ($this->_lockfile)"); + } - function setConfig(&$config) - { - $this->config = &$config; - $this->_registry = &$config->getRegistry(); + return true; } - // }}} - - function _removeBackups($files) + /** + * Release usage of dependency DB + * @return true|PEAR_Error + * @access private + */ + function _unlock() { - foreach ($files as $path) { - $this->addFileOperation('removebackup', array($path)); + $ret = $this->_lock(LOCK_UN); + if (is_resource($this->_lockFp)) { + fclose($this->_lockFp); } + $this->_lockFp = null; + return $ret; } - // {{{ _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 + * Load the dependency database from disk, or return the cache + * @return array|PEAR_Error */ - function _deletePackageFiles($package, $channel = false, $backup = false) + function _getDepDB() { - if (!$channel) { - $channel = 'pear.php.net'; - } - - if (!strlen($package)) { - return $this->raiseError("No package to uninstall given"); + if (!$this->hasWriteAccess()) { + return array('_version' => $this->_version); } - 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'; + if (isset($this->_cache)) { + return $this->_cache; } - $filelist = $this->_registry->packageInfo($package, 'filelist', $channel); - if ($filelist == null) { - return $this->raiseError("$channel/$package not installed"); + if (!$fp = fopen($this->_depdb, 'r')) { + $err = PEAR::raiseError("Could not open dependencies file `".$this->_depdb."'"); + return $err; } - $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; - } + $rt = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + clearstatcache(); + fclose($fp); + $data = unserialize(file_get_contents($this->_depdb)); + set_magic_quotes_runtime($rt); + $this->_cache = $data; + return $data; + } - $this->addFileOperation('delete', array($path)); + /** + * Write out the dependency database to disk + * @param array the database + * @return true|PEAR_Error + * @access private + */ + function _writeDepDB(&$deps) + { + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; } - if ($backup) { - return $ret; + if (!$fp = fopen($this->_depdb, 'wb')) { + $this->_unlock(); + return PEAR::raiseError("Could not open dependencies file `".$this->_depdb."' for writing"); } + $rt = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + fwrite($fp, serialize($deps)); + set_magic_quotes_runtime($rt); + fclose($fp); + $this->_unlock(); + $this->_cache = $deps; return true; } - // }}} - // {{{ _installFile() - /** - * @param string filename - * @param array attributes from tag in package.xml - * @param string path to install the file in - * @param array options from command-line + * Register all dependencies from a package in the dependencies database, in essence + * "installing" the package's dependency information + * @param array the database + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 * @access private */ - function _installFile($file, $atts, $tmp_path, $options) + function _setPackageDeps(&$data, &$pkg) { - // {{{ return if this file is meant for another platform - static $os; - if (!isset($this->_registry)) { - $this->_registry = &$this->config->getRegistry(); + $pkg->setConfig($this->_config); + if ($pkg->getPackagexmlVersion() == '1.0') { + $gen = &$pkg->getDefaultGenerator(); + $deps = $gen->dependenciesToV2(); + } else { + $deps = $pkg->getDeps(true); } - 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; - } + if (!$deps) { + return; } - // }}} - $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"); + if (!is_array($data)) { + $data = array(); } - $save_destdir = $dest_dir; - if (!empty($atts['baseinstalldir'])) { - $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir']; + if (!isset($data['dependencies'])) { + $data['dependencies'] = array(); } - if (dirname($file) != '.' && empty($atts['install-as'])) { - $dest_dir .= DIRECTORY_SEPARATOR . dirname($file); - } + $channel = strtolower($pkg->getChannel()); + $package = strtolower($pkg->getPackage()); - if (empty($atts['install-as'])) { - $dest_file = $dest_dir . DIRECTORY_SEPARATOR . basename($file); - } else { - $dest_file = $dest_dir . DIRECTORY_SEPARATOR . $atts['install-as']; + if (!isset($data['dependencies'][$channel])) { + $data['dependencies'][$channel] = array(); } - $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); - } + $data['dependencies'][$channel][$package] = array(); + if (isset($deps['required']['package'])) { + if (!isset($deps['required']['package'][0])) { + $deps['required']['package'] = array($deps['required']['package']); + } - $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); + foreach ($deps['required']['package'] as $dep) { + $this->_registerDep($data, $pkg, $dep, 'required'); + } } - // }}} - 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); + if (isset($deps['optional']['package'])) { + if (!isset($deps['optional']['package'][0])) { + $deps['optional']['package'] = array($deps['optional']['package']); + } + + foreach ($deps['optional']['package'] as $dep) { + $this->_registerDep($data, $pkg, $dep, 'optional'); } - $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 (isset($deps['required']['subpackage'])) { + if (!isset($deps['required']['subpackage'][0])) { + $deps['required']['subpackage'] = array($deps['required']['subpackage']); + } - if (!@copy($orig_file, $dest_file)) { - return $this->raiseError("failed to write $dest_file: $php_errormsg", - PEAR_INSTALLER_FAILED); - } + foreach ($deps['required']['subpackage'] as $dep) { + $this->_registerDep($data, $pkg, $dep, 'required'); + } + } - $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); - } + if (isset($deps['optional']['subpackage'])) { + if (!isset($deps['optional']['subpackage'][0])) { + $deps['optional']['subpackage'] = array($deps['optional']['subpackage']); + } - $contents = file_get_contents($orig_file); - if ($contents === false) { - $contents = ''; - } + foreach ($deps['optional']['subpackage'] as $dep) { + $this->_registerDep($data, $pkg, $dep, 'optional'); + } + } - if (isset($atts['md5sum'])) { - $md5sum = md5($contents); - } + if (isset($deps['group'])) { + if (!isset($deps['group'][0])) { + $deps['group'] = array($deps['group']); + } - $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; + foreach ($deps['group'] as $group) { + if (isset($group['package'])) { + if (!isset($group['package'][0])) { + $group['package'] = array($group['package']); } - } - - $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); + foreach ($group['package'] as $dep) { + $this->_registerDep($data, $pkg, $dep, 'optional', + $group['attribs']['name']); + } } - 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); - } - - 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"); - } + if (isset($group['subpackage'])) { + if (!isset($group['subpackage'][0])) { + $group['subpackage'] = array($group['subpackage']); } - } - } - // }}} - // {{{ 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"); - } + foreach ($group['subpackage'] as $dep) { + $this->_registerDep($data, $pkg, $dep, 'optional', + $group['attribs']['name']); } } } - // }}} - - 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))))); + if ($data['dependencies'][$channel][$package] == array()) { + unset($data['dependencies'][$channel][$package]); + if (!count($data['dependencies'][$channel])) { + unset($data['dependencies'][$channel]); + } } - - //$this->log(2, "installed: $dest_file"); - return PEAR_INSTALLER_OK; } - // }}} - // {{{ _installFile2() - /** + * @param array the database * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @param string filename - * @param array attributes from tag in package.xml - * @param string path to install the file in - * @param array options from command-line - * @access private + * @param array the specific dependency + * @param required|optional whether this is a required or an optional dep + * @param string|false dependency group this dependency is from, or false for ordinary dep */ - function _installFile2(&$pkg, $file, &$real_atts, $tmp_path, $options) + function _registerDep(&$data, &$pkg, $dep, $type, $group = false) { - $atts = $real_atts; - if (!isset($this->_registry)) { - $this->_registry = &$this->config->getRegistry(); - } + $info = array( + 'dep' => $dep, + 'type' => $type, + 'group' => $group + ); - $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"); + $dep = array_map('strtolower', $dep); + $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri'; + if (!isset($data['dependencies'])) { + $data['dependencies'] = array(); } - $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; - } + $channel = strtolower($pkg->getChannel()); + $package = strtolower($pkg->getPackage()); - $info = $role->processInstallation($pkg, $atts['attribs'], $file, $tmp_path); - if (PEAR::isError($info)) { - return $info; + if (!isset($data['dependencies'][$channel])) { + $data['dependencies'][$channel] = array(); } - 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); + if (!isset($data['dependencies'][$channel][$package])) { + $data['dependencies'][$channel][$package] = array(); } - $final_dest_file = $installed_as = $dest_file; - if (isset($this->_options['packagingroot'])) { - $final_dest_file = $this->_prependPath($final_dest_file, - $this->_options['packagingroot']); - } + $data['dependencies'][$channel][$package][] = $info; + if (isset($data['packages'][$depchannel][$dep['name']])) { + $found = false; + foreach ($data['packages'][$depchannel][$dep['name']] as $i => $p) { + if ($p['channel'] == $channel && $p['package'] == $package) { + $found = true; + break; + } + } + } else { + if (!isset($data['packages'])) { + $data['packages'] = array(); + } - $dest_dir = dirname($final_dest_file); - $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); - // }}} + if (!isset($data['packages'][$depchannel])) { + $data['packages'][$depchannel] = array(); + } - 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"); + if (!isset($data['packages'][$depchannel][$dep['name']])) { + $data['packages'][$depchannel][$dep['name']] = array(); } + + $found = false; } - $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 (!$found) { + $data['packages'][$depchannel][$dep['name']][] = array( + 'channel' => $channel, + 'package' => $package + ); + } + } +}PEAR-1.9.0/PEAR/Dependency2.php100664 764 764 142517 100664 10760 + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Dependency2.php 286494 2009-07-29 06:57:11Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ - if (!@copy($orig_file, $dest_file)) { - return $this->raiseError("failed to write $dest_file: $php_errormsg", - PEAR_INSTALLER_FAILED); - } +/** + * Required for the PEAR_VALIDATE_* constants + */ +require_once 'PEAR/Validate.php'; - $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); - } +/** + * Dependency check for PEAR packages + * + * This class handles both version 1.0 and 2.0 dependencies + * WARNING: *any* changes to this class must be duplicated in the + * test_PEAR_Dependency2 class found in tests/PEAR_Dependency2/setup.php.inc, + * or unit tests will not actually validate the changes + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Dependency2 +{ + /** + * One of the PEAR_VALIDATE_* states + * @see PEAR_VALIDATE_NORMAL + * @var integer + */ + var $_state; - $contents = file_get_contents($orig_file); - if ($contents === false) { - $contents = ''; - } + /** + * Command-line options to install/upgrade/uninstall commands + * @param array + */ + var $_options; - if (isset($attribs['md5sum'])) { - $md5sum = md5($contents); - } + /** + * @var OS_Guess + */ + var $_os; - 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 - } + /** + * @var PEAR_Registry + */ + var $_registry; - if (PEAR::isError($res)) { - return $res; - } + /** + * @var PEAR_Config + */ + var $_config; - $contents = $res; // save changes - } + /** + * @var PEAR_DependencyDB + */ + var $_dependencydb; - $wp = @fopen($dest_file, "wb"); - if (!is_resource($wp)) { - return $this->raiseError("failed to create $dest_file: $php_errormsg", - PEAR_INSTALLER_FAILED); - } + /** + * Output of PEAR_Registry::parsedPackageName() + * @var array + */ + var $_currentPackage; - if (fwrite($wp, $contents) === false) { - return $this->raiseError("failed writing to $dest_file: $php_errormsg", - PEAR_INSTALLER_FAILED); - } + /** + * @param PEAR_Config + * @param array installation options + * @param array format of PEAR_Registry::parsedPackageName() + * @param int installation state (one of PEAR_VALIDATE_*) + */ + function PEAR_Dependency2(&$config, $installoptions, $package, + $state = PEAR_VALIDATE_INSTALLING) + { + $this->_config = &$config; + if (!class_exists('PEAR_DependencyDB')) { + require_once 'PEAR/DependencyDB.php'; + } - fclose($wp); - } - } + if (isset($installoptions['packagingroot'])) { + // make sure depdb is in the right location + $config->setInstallRoot($installoptions['packagingroot']); + } - // {{{ check the md5 - if (isset($md5sum)) { - // Make sure the original md5 sum matches with expected - if (strtolower($md5sum) === strtolower($attribs['md5sum'])) { - $this->log(2, "md5sum ok: $final_dest_file"); + $this->_registry = &$config->getRegistry(); + $this->_dependencydb = &PEAR_DependencyDB::singleton($config); + if (isset($installoptions['packagingroot'])) { + $config->setInstallRoot(false); + } - if (isset($contents)) { - // set md5 sum based on $content in case any tasks were run. - $real_atts['attribs']['md5sum'] = md5($contents); - } - } else { - if (empty($options['force'])) { - // delete the file - if (file_exists($dest_file)) { - unlink($dest_file); - } + $this->_options = $installoptions; + $this->_state = $state; + if (!class_exists('OS_Guess')) { + require_once 'OS/Guess.php'; + } - if (!isset($options['ignore-errors'])) { - return $this->raiseError("bad md5sum for file $final_dest_file", - PEAR_INSTALLER_FAILED); - } + $this->_os = new OS_Guess; + $this->_currentPackage = $package; + } - 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"); - } - } + function _getExtraString($dep) + { + $extra = ' ('; + if (isset($dep['uri'])) { + return ''; + } + + if (isset($dep['recommended'])) { + $extra .= 'recommended version ' . $dep['recommended']; + } else { + if (isset($dep['min'])) { + $extra .= 'version >= ' . $dep['min']; + } + + if (isset($dep['max'])) { + if ($extra != ' (') { + $extra .= ', '; } - } else { - $real_atts['attribs']['md5sum'] = md5_file($dest_file); + $extra .= 'version <= ' . $dep['max']; } - // }}} - // {{{ 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 (isset($dep['exclude'])) { + if (!is_array($dep['exclude'])) { + $dep['exclude'] = array($dep['exclude']); } - 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 ($extra != ' (') { + $extra .= ', '; } - } - // }}} - 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())); + $extra .= 'excluded versions: '; + foreach ($dep['exclude'] as $i => $exclude) { + if ($i) { + $extra .= ', '; + } + $extra .= $exclude; + } } } - // 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))))); + $extra .= ')'; + if ($extra == ' ()') { + $extra = ''; } - //$this->log(2, "installed: $dest_file"); - return PEAR_INSTALLER_OK; + return $extra; } - // }}} - // {{{ addFileOperation() + /** + * This makes unit-testing a heck of a lot easier + */ + function getPHP_OS() + { + return PHP_OS; + } /** - * 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. + * This makes unit-testing a heck of a lot easier + */ + function getsysname() + { + return $this->_os->getSysname(); + } + + /** + * Specify a dependency on an OS. Use arch for detailed os/processor information * - * 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 + * There are two generic OS dependencies that will be the most common, unix and windows. + * Other options are linux, freebsd, darwin (OS X), sunos, irix, hpux, aix */ - function addFileOperation($type, $data) + function validateOsDependency($dep) { - if (!is_array($data)) { - return $this->raiseError('Internal Error: $data in addFileOperation' - . ' must be an array, was ' . gettype($data)); + if ($this->_state != PEAR_VALIDATE_INSTALLING && $this->_state != PEAR_VALIDATE_DOWNLOADING) { + return true; } - 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)); + if ($dep['name'] == '*') { + return true; } - $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(); - } + $not = isset($dep['conflicts']) ? true : false; + switch (strtolower($dep['name'])) { + case 'windows' : + if ($not) { + if (strtolower(substr($this->getPHP_OS(), 0, 3)) == 'win') { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError("Cannot install %s on Windows"); + } - // }}} - // {{{ commitFileTransaction() + return $this->warning("warning: Cannot install %s on Windows"); + } + } else { + if (strtolower(substr($this->getPHP_OS(), 0, 3)) != 'win') { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError("Can only install %s on Windows"); + } - 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"; + return $this->warning("warning: Can only install %s on Windows"); } + } + break; + case 'unix' : + $unices = array('linux', 'freebsd', 'darwin', 'sunos', 'irix', 'hpux', 'aix'); + if ($not) { + if (in_array($this->getSysname(), $unices)) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError("Cannot install %s on any Unix system"); + } - // check that dest dir. is writable - if (!is_writable(dirname($data[1]))) { - $errors[] = "permission denied ($type): $data[1]"; + return $this->warning( "warning: Cannot install %s on any Unix system"); } - break; - case 'chmod': - // check that file is writable - if (!is_writable($data[1])) { - $errors[] = "permission denied ($type): $data[1] " . decoct($data[0]); + } else { + if (!in_array($this->getSysname(), $unices)) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError("Can only install %s on a Unix system"); + } + + return $this->warning("warning: Can only install %s on a Unix system"); } - break; - case 'delete': - if (!file_exists($data[0])) { - $this->log(2, "warning: file $data[0] doesn't exist, can't be deleted"); + } + break; + default : + if ($not) { + if (strtolower($dep['name']) == strtolower($this->getSysname())) { + if (!isset($this->_options['nodeps']) && + !isset($this->_options['force'])) { + return $this->raiseError('Cannot install %s on ' . $dep['name'] . + ' operating system'); + } + + return $this->warning('warning: Cannot install %s on ' . + $dep['name'] . ' operating system'); } - // 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); - } + } else { + if (strtolower($dep['name']) != strtolower($this->getSysname())) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('Cannot install %s on ' . + $this->getSysname() . + ' operating system, can only install on ' . $dep['name']); } + + return $this->warning('warning: Cannot install %s on ' . + $this->getSysname() . + ' operating system, can only install on ' . $dep['name']); } - break; - } + } + } + return true; + } + + /** + * This makes unit-testing a heck of a lot easier + */ + function matchSignature($pattern) + { + return $this->_os->matchSignature($pattern); + } + /** + * Specify a complex dependency on an OS/processor/kernel version, + * Use OS for simple operating system dependency. + * + * This is the only dependency that accepts an eregable pattern. The pattern + * will be matched against the php_uname() output parsed by OS_Guess + */ + function validateArchDependency($dep) + { + if ($this->_state != PEAR_VALIDATE_INSTALLING) { + return true; } - // }}} - $m = count($errors); - if ($m > 0) { - foreach ($errors as $error) { - if (!isset($this->_options['soft'])) { - $this->log(1, $error); + + $not = isset($dep['conflicts']) ? true : false; + if (!$this->matchSignature($dep['pattern'])) { + if (!$not) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s Architecture dependency failed, does not ' . + 'match "' . $dep['pattern'] . '"'); } - } - if (!isset($this->_options['ignore-errors'])) { - return false; + return $this->warning('warning: %s Architecture dependency failed, does ' . + 'not match "' . $dep['pattern'] . '"'); } + + return true; } - $this->_dirtree = array(); - // {{{ really commit the transaction - foreach ($this->file_operations as $i => $tr) { - if (!$tr) { - // support removal of non-existing backups - continue; + if ($not) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s Architecture dependency failed, required "' . + $dep['pattern'] . '"'); } - list($type, $data) = $tr; - switch ($type) { - case 'backup': - if (!file_exists($data[0])) { - $this->file_operations[$i] = false; - break; - } + return $this->warning('warning: %s Architecture dependency failed, ' . + 'required "' . $dep['pattern'] . '"'); + } - 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': - $test = file_exists($data[1]) ? @unlink($data[1]) : null; - if (!$test && file_exists($data[1])) { - if ($data[2]) { - $extra = ', this extension must be installed manually. Rename to "' . - basename($data[1]) . '"'; - } else { - $extra = ''; - } + return true; + } - if (!isset($this->_options['soft'])) { - $this->log(1, 'Could not delete ' . $data[1] . ', cannot rename ' . - $data[0] . $extra); - } + /** + * This makes unit-testing a heck of a lot easier + */ + function extension_loaded($name) + { + return extension_loaded($name); + } - if (!isset($this->_options['ignore-errors'])) { - return false; - } - } + /** + * This makes unit-testing a heck of a lot easier + */ + function phpversion($name = null) + { + if ($name !== null) { + return phpversion($name); + } - // 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; - } + return phpversion(); + } - // 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; - } + function validateExtensionDependency($dep, $required = true) + { + if ($this->_state != PEAR_VALIDATE_INSTALLING && + $this->_state != PEAR_VALIDATE_DOWNLOADING) { + return true; + } - $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 - } + $loaded = $this->extension_loaded($dep['name']); + $extra = $this->_getExtraString($dep); + if (isset($dep['exclude'])) { + if (!is_array($dep['exclude'])) { + $dep['exclude'] = array($dep['exclude']); + } + } - 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); + if (!isset($dep['min']) && !isset($dep['max']) && + !isset($dep['recommended']) && !isset($dep['exclude']) + ) { + if ($loaded) { + if (isset($dep['conflicts'])) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s conflicts with PHP extension "' . + $dep['name'] . '"' . $extra); } - 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; + return $this->warning('warning: %s conflicts with PHP extension "' . + $dep['name'] . '"' . $extra); + } + + return true; } - } - // }}} - $this->log(2, "successfully committed $n file operations"); - $this->file_operations = array(); - return true; - } - // }}} - // {{{ rollbackFileTransaction() + if (isset($dep['conflicts'])) { + return true; + } - 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; + if ($required) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires PHP extension "' . + $dep['name'] . '"' . $extra); + } + + return $this->warning('warning: %s requires PHP extension "' . + $dep['name'] . '"' . $extra); } + + return $this->warning('%s can optionally use PHP extension "' . + $dep['name'] . '"' . $extra); } - $this->pkginfo->resetDirtree(); - $this->file_operations = array(); - } - // }}} - // {{{ mkDirHier($dir) + if (!$loaded) { + if (isset($dep['conflicts'])) { + return true; + } - function mkDirHier($dir) - { - $this->addFileOperation('mkdir', array($dir)); - return parent::mkDirHier($dir); - } + if (!$required) { + return $this->warning('%s can optionally use PHP extension "' . + $dep['name'] . '"' . $extra); + } - // }}} - // {{{ download() + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires PHP extension "' . $dep['name'] . + '"' . $extra); + } - /** - * 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: - * - * - * array('pkg' => 'package_name', 'file' => '/path/to/local/file', - * 'info' => array() // parsed package.xml - * ); - * - * @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; - } + return $this->warning('warning: %s requires PHP extension "' . $dep['name'] . + '"' . $extra); + } - // }}} - // {{{ _parsePackageXml() + $version = (string) $this->phpversion($dep['name']); + if (empty($version)) { + $version = '0'; + } - function _parsePackageXml(&$descfile, &$tmpdir) - { - if (substr($descfile, -4) == '.xml') { - $tmpdir = false; - } else { - // {{{ Decompress pack in tmp dir ------------------------------------- + $fail = false; + if (isset($dep['min']) && !version_compare($version, $dep['min'], '>=')) { + $fail = true; + } - // To allow relative package file names - $descfile = realpath($descfile); + if (isset($dep['max']) && !version_compare($version, $dep['max'], '<=')) { + $fail = true; + } - if (PEAR::isError($tmpdir = System::mktemp('-d'))) { - return $tmpdir; + if ($fail && !isset($dep['conflicts'])) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires PHP extension "' . $dep['name'] . + '"' . $extra . ', installed version is ' . $version); } - $this->log(3, '+ tmp dir created at ' . $tmpdir); - // }}} + + return $this->warning('warning: %s requires PHP extension "' . $dep['name'] . + '"' . $extra . ', installed version is ' . $version); + } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail && isset($dep['conflicts'])) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s conflicts with PHP extension "' . + $dep['name'] . '"' . $extra . ', installed version is ' . $version); + } + + return $this->warning('warning: %s conflicts with PHP extension "' . + $dep['name'] . '"' . $extra . ', installed version is ' . $version); } - // 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']); + if (isset($dep['exclude'])) { + foreach ($dep['exclude'] as $exclude) { + if (version_compare($version, $exclude, '==')) { + if (isset($dep['conflicts'])) { + continue; + } + + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s is not compatible with PHP extension "' . + $dep['name'] . '" version ' . + $exclude); } + + return $this->warning('warning: %s is not compatible with PHP extension "' . + $dep['name'] . '" version ' . + $exclude); + } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s conflicts with PHP extension "' . + $dep['name'] . '"' . $extra . ', installed version is ' . $version); + } + + return $this->warning('warning: %s conflicts with PHP extension "' . + $dep['name'] . '"' . $extra . ', installed version is ' . $version); } } - return $this->raiseError('Installation failed: invalid package file'); } - $descfile = $p->getPackageFile(); - return $p; - } + if (isset($dep['recommended'])) { + if (version_compare($version, $dep['recommended'], '==')) { + return true; + } - // }}} - /** - * 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; + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s dependency: PHP extension ' . $dep['name'] . + ' version "' . $version . '"' . + ' is not the recommended version "' . $dep['recommended'] . + '", but may be compatible, use --force to install'); + } + + return $this->warning('warning: %s dependency: PHP extension ' . + $dep['name'] . ' version "' . $version . '"' . + ' is not the recommended version "' . $dep['recommended'].'"'); } - $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; + return true; } - function getInstallPackages() + function validatePhpDependency($dep) { - 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 - */ + if ($this->_state != PEAR_VALIDATE_INSTALLING && + $this->_state != PEAR_VALIDATE_DOWNLOADING) { + return true; + } - 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 = ''; - $pkg = &$this->_parsePackageXml($descfile, $tmpdir); - if (PEAR::isError($pkg)) { - return $pkg; + $version = $this->phpversion(); + $extra = $this->_getExtraString($dep); + if (isset($dep['exclude'])) { + if (!is_array($dep['exclude'])) { + $dep['exclude'] = array($dep['exclude']); } } - if (realpath($descfile) != realpath($pkgfile)) { - $tar = new Archive_Tar($pkgfile); - if (!$tar->extract($tmpdir)) { - return $this->raiseError("unable to unpack $pkgfile"); + if (isset($dep['min'])) { + if (!version_compare($version, $dep['min'], '>=')) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires PHP' . + $extra . ', installed version is ' . $version); + } + + return $this->warning('warning: %s requires PHP' . + $extra . ', installed version is ' . $version); } } - $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']); + if (isset($dep['max'])) { + if (!version_compare($version, $dep['max'], '<=')) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires PHP' . + $extra . ', installed version is ' . $version); + } - $packrootphp_dir = $this->_prependPath( - $this->config->get('php_dir', null, $channel), - $this->_options['packagingroot']); + return $this->warning('warning: %s requires PHP' . + $extra . ', installed version is ' . $version); + } } - 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); + if (isset($dep['exclude'])) { + foreach ($dep['exclude'] as $exclude) { + if (version_compare($version, $exclude, '==')) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s is not compatible with PHP version ' . + $exclude); + } + + return $this->warning( + 'warning: %s is not compatible with PHP version ' . + $exclude); } - $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; - } + return true; + } - // ensure we have the most accurate registry - $installregistry->flushFileMap(); - $test = $installregistry->checkFileMap($instfilelist, $testp, '1.1'); - if (PEAR::isError($test)) { - return $test; + /** + * This makes unit-testing a heck of a lot easier + */ + function getPEARVersion() + { + return '1.9.0'; + } + + function validatePearinstallerDependency($dep) + { + $pearversion = $this->getPEARVersion(); + $extra = $this->_getExtraString($dep); + if (isset($dep['exclude'])) { + if (!is_array($dep['exclude'])) { + $dep['exclude'] = array($dep['exclude']); } + } - if (sizeof($test)) { - $pkgs = $this->getInstallPackages(); - $found = false; - foreach ($pkgs as $param) { - if ($pkg->isSubpackageOf($param)) { - $found = true; - break; - } - } + if (version_compare($pearversion, $dep['min'], '<')) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires PEAR Installer' . $extra . + ', installed version is ' . $pearversion); + } - if ($found) { - // subpackages can conflict with earlier versions of parent packages - $parentreg = $installregistry->packageInfo($param->getPackage(), null, $param->getChannel()); - $tmp = $test; - foreach ($tmp as $file => $info) { - if (is_array($info)) { - if (strtolower($info[1]) == strtolower($param->getPackage()) && - strtolower($info[0]) == strtolower($param->getChannel()) - ) { - if (isset($parentreg['filelist'][$file])) { - unset($parentreg['filelist'][$file]); - } else{ - $pos = strpos($file, '/'); - $basedir = substr($file, 0, $pos); - $file2 = substr($file, $pos + 1); - if (isset($parentreg['filelist'][$file2]['baseinstalldir']) - && $parentreg['filelist'][$file2]['baseinstalldir'] === $basedir - ) { - unset($parentreg['filelist'][$file2]); - } - } + return $this->warning('warning: %s requires PEAR Installer' . $extra . + ', installed version is ' . $pearversion); + } - unset($test[$file]); - } - } else { - if (strtolower($param->getChannel()) != 'pear.php.net') { - continue; - } + if (isset($dep['max'])) { + if (version_compare($pearversion, $dep['max'], '>')) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires PEAR Installer' . $extra . + ', installed version is ' . $pearversion); + } - if (strtolower($info) == strtolower($param->getPackage())) { - if (isset($parentreg['filelist'][$file])) { - unset($parentreg['filelist'][$file]); - } else{ - $pos = strpos($file, '/'); - $basedir = substr($file, 0, $pos); - $file2 = substr($file, $pos + 1); - if (isset($parentreg['filelist'][$file2]['baseinstalldir']) - && $parentreg['filelist'][$file2]['baseinstalldir'] === $basedir - ) { - unset($parentreg['filelist'][$file2]); - } - } + return $this->warning('warning: %s requires PEAR Installer' . $extra . + ', installed version is ' . $pearversion); + } + } - unset($test[$file]); - } - } + if (isset($dep['exclude'])) { + if (!isset($dep['exclude'][0])) { + $dep['exclude'] = array($dep['exclude']); + } + + foreach ($dep['exclude'] as $exclude) { + if (version_compare($exclude, $pearversion, '==')) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s is not compatible with PEAR Installer ' . + 'version ' . $exclude); } - $pfk = &new PEAR_PackageFile($this->config); - $parentpkg = &$pfk->fromArray($parentreg); - $installregistry->updatePackage2($parentpkg); + return $this->warning('warning: %s is not compatible with PEAR ' . + 'Installer version ' . $exclude); } + } + } - if ($param->getChannel() == 'pecl.php.net' && isset($options['upgrade'])) { - $tmp = $test; - foreach ($tmp as $file => $info) { - if (is_string($info)) { - // pear.php.net packages are always stored as strings - if (strtolower($info) == strtolower($param->getPackage())) { - // upgrading existing package - unset($test[$file]); - } - } - } - } + return true; + } - if (count($test)) { - $msg = "$channel/$pkgname: conflicting files found:\n"; - $longest = max(array_map("strlen", array_keys($test))); - $fmt = "%${longest}s (%s)\n"; - foreach ($test as $file => $info) { - if (!is_array($info)) { - $info = array('pear.php.net', $info); - } - $info = $info[0] . '/' . $info[1]; - $msg .= sprintf($fmt, $file, $info); - } + function validateSubpackageDependency($dep, $required, $params) + { + return $this->validatePackageDependency($dep, $required, $params); + } - if (!isset($options['ignore-errors'])) { - return $this->raiseError($msg); - } + /** + * @param array dependency information (2.0 format) + * @param boolean whether this is a required dependency + * @param array a list of downloaded packages to be installed, if any + * @param boolean if true, then deps on pear.php.net that fail will also check + * against pecl.php.net packages to accomodate extensions that have + * moved to pecl.php.net from pear.php.net + */ + function validatePackageDependency($dep, $required, $params, $depv1 = false) + { + if ($this->_state != PEAR_VALIDATE_INSTALLING && + $this->_state != PEAR_VALIDATE_DOWNLOADING) { + return true; + } - if (!isset($options['soft'])) { - $this->log(0, "WARNING: $msg"); - } + if (isset($dep['providesextension'])) { + if ($this->extension_loaded($dep['providesextension'])) { + $save = $dep; + $subdep = $dep; + $subdep['name'] = $subdep['providesextension']; + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $ret = $this->validateExtensionDependency($subdep, $required); + PEAR::popErrorHandling(); + if (!PEAR::isError($ret)) { + return true; } } } - // }}} - $this->startFileTransaction(); + if ($this->_state == PEAR_VALIDATE_INSTALLING) { + return $this->_validatePackageInstall($dep, $required, $depv1); + } - if (empty($options['upgrade']) && empty($options['soft'])) { - // checks to do only when installing new packages - if ($channel == 'pecl.php.net') { - $test = $installregistry->packageExists($pkgname, $channel); - if (!$test) { - $test = $installregistry->packageExists($pkgname, 'pear.php.net'); + if ($this->_state == PEAR_VALIDATE_DOWNLOADING) { + return $this->_validatePackageDownload($dep, $required, $params, $depv1); + } + } + + function _validatePackageDownload($dep, $required, $params, $depv1 = false) + { + $dep['package'] = $dep['name']; + if (isset($dep['uri'])) { + $dep['channel'] = '__uri'; + } + + $depname = $this->_registry->parsedPackageNameToString($dep, true); + $found = false; + foreach ($params as $param) { + if ($param->isEqual( + array('package' => $dep['name'], + 'channel' => $dep['channel']))) { + $found = true; + break; + } + + if ($depv1 && $dep['channel'] == 'pear.php.net') { + if ($param->isEqual( + array('package' => $dep['name'], + 'channel' => 'pecl.php.net'))) { + $found = true; + break; } - } else { - $test = $installregistry->packageExists($pkgname, $channel); } + } - if (empty($options['force']) && $test) { - return $this->raiseError("$channel/$pkgname is already installed"); + if (!$found && isset($dep['providesextension'])) { + foreach ($params as $param) { + if ($param->isExtension($dep['providesextension'])) { + $found = true; + break; + } } + } + + if ($found) { + $version = $param->getVersion(); + $installed = false; + $downloaded = true; } else { - $usechannel = $channel; - if ($channel == 'pecl.php.net') { - $test = $installregistry->packageExists($pkgname, $channel); - if (!$test) { - $test = $installregistry->packageExists($pkgname, 'pear.php.net'); - $usechannel = 'pear.php.net'; - } + if ($this->_registry->packageExists($dep['name'], $dep['channel'])) { + $installed = true; + $downloaded = false; + $version = $this->_registry->packageinfo($dep['name'], 'version', + $dep['channel']); } else { - $test = $installregistry->packageExists($pkgname, $channel); + if ($dep['channel'] == 'pecl.php.net' && $this->_registry->packageExists($dep['name'], + 'pear.php.net')) { + $installed = true; + $downloaded = false; + $version = $this->_registry->packageinfo($dep['name'], 'version', + 'pear.php.net'); + } else { + $version = 'not installed or downloaded'; + $installed = false; + $downloaded = false; + } } + } - if ($test) { - $v1 = $installregistry->packageInfo($pkgname, 'version', $usechannel); - $v2 = $pkg->getVersion(); - $cmp = version_compare("$v1", "$v2", 'gt'); - if (empty($options['force']) && !version_compare("$v2", "$v1", 'gt')) { - return $this->raiseError("upgrade to a newer version ($v2 is not newer than $v1)"); - } + $extra = $this->_getExtraString($dep); + if (isset($dep['exclude']) && !is_array($dep['exclude'])) { + $dep['exclude'] = array($dep['exclude']); + } - if (empty($options['register-only'])) { - // when upgrading, remove old release's files first: - if (PEAR::isError($err = $this->_deletePackageFiles($pkgname, $usechannel, - true))) { - if (!isset($options['ignore-errors'])) { - return $this->raiseError($err); - } + if (!isset($dep['min']) && !isset($dep['max']) && + !isset($dep['recommended']) && !isset($dep['exclude']) + ) { + if ($installed || $downloaded) { + $installed = $installed ? 'installed' : 'downloaded'; + if (isset($dep['conflicts'])) { + $rest = ''; + if ($version) { + $rest = ", $installed version is " . $version; + } - if (!isset($options['soft'])) { - $this->log(0, 'WARNING: ' . $err->getMessage()); - } - } else { - $backedup = $err; + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s conflicts with package "' . $depname . '"' . $extra . $rest); } + + return $this->warning('warning: %s conflicts with package "' . $depname . '"' . $extra . $rest); } + + return true; } - } - // {{{ Copy files to dest dir --------------------------------------- + if (isset($dep['conflicts'])) { + return true; + } - // info from the package it self we want to access from _installFile - $this->pkginfo = &$pkg; - // used to determine whether we should build any C code - $this->source_files = 0; + if ($required) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires package "' . $depname . '"' . $extra); + } - $savechannel = $this->config->get('default_channel'); - if (empty($options['register-only']) && !is_dir($php_dir)) { - if (PEAR::isError(System::mkdir(array('-p'), $php_dir))) { - return $this->raiseError("no installation destination directory '$php_dir'\n"); + return $this->warning('warning: %s requires package "' . $depname . '"' . $extra); } - } - $tmp_path = dirname($descfile); - if (substr($pkgfile, -4) != '.xml') { - $tmp_path .= DIRECTORY_SEPARATOR . $pkgname . '-' . $pkg->getVersion(); + return $this->warning('%s can optionally use package "' . $depname . '"' . $extra); } - $this->configSet('default_channel', $channel); - // {{{ install files + if (!$installed && !$downloaded) { + if (isset($dep['conflicts'])) { + return true; + } - $ver = $pkg->getPackagexmlVersion(); - if (version_compare($ver, '2.0', '>=')) { - $filelist = $pkg->getInstallationFilelist(); - } else { - $filelist = $pkg->getFileList(); + if ($required) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires package "' . $depname . '"' . $extra); + } + + return $this->warning('warning: %s requires package "' . $depname . '"' . $extra); + } + + return $this->warning('%s can optionally use package "' . $depname . '"' . $extra); } - if (PEAR::isError($filelist)) { - return $filelist; + $fail = false; + if (isset($dep['min']) && version_compare($version, $dep['min'], '<')) { + $fail = true; } - $p = &$installregistry->getPackage($pkgname, $channel); - if (empty($options['register-only']) && $p) { - $dirtree = $p->getDirTree(); - } else { - $dirtree = false; + if (isset($dep['max']) && version_compare($version, $dep['max'], '>')) { + $fail = true; } - $pkg->resetFilelist(); - $pkg->setLastInstalledVersion($installregistry->packageInfo($pkg->getPackage(), - 'version', $pkg->getChannel())); - foreach ($filelist as $file => $atts) { - $this->expectError(PEAR_INSTALLER_FAILED); - if ($pkg->getPackagexmlVersion() == '1.0') { - $res = $this->_installFile($file, $atts, $tmp_path, $options); - } else { - $res = $this->_installFile2($pkg, $file, $atts, $tmp_path, $options); + if ($fail && !isset($dep['conflicts'])) { + $installed = $installed ? 'installed' : 'downloaded'; + $dep['package'] = $dep['name']; + $dep = $this->_registry->parsedPackageNameToString($dep, true); + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires package "' . $depname . '"' . + $extra . ", $installed version is " . $version); } - $this->popExpect(); - - if (PEAR::isError($res)) { - if (empty($options['ignore-errors'])) { - $this->rollbackFileTransaction(); - if ($res->getMessage() == "file does not exist") { - $this->raiseError("file $file in package.xml does not exist"); - } - - return $this->raiseError($res); - } - if (!isset($options['soft'])) { - $this->log(0, "Warning: " . $res->getMessage()); - } + return $this->warning('warning: %s requires package "' . $depname . '"' . + $extra . ", $installed version is " . $version); + } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail && + isset($dep['conflicts']) && !isset($dep['exclude'])) { + $installed = $installed ? 'installed' : 'downloaded'; + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s conflicts with package "' . $depname . '"' . $extra . + ", $installed version is " . $version); } - $real = isset($atts['attribs']) ? $atts['attribs'] : $atts; - if ($res == PEAR_INSTALLER_OK && $real['role'] != 'src') { - // Register files that were installed - $pkg->installedFile($file, $atts); - } + return $this->warning('warning: %s conflicts with package "' . $depname . '"' . + $extra . ", $installed version is " . $version); } - // }}} - // {{{ compile and install source files - if ($this->source_files > 0 && empty($options['nobuild'])) { - if (PEAR::isError($err = - $this->_compileSourceFiles($savechannel, $pkg))) { - return $err; - } - } - // }}} + if (isset($dep['exclude'])) { + $installed = $installed ? 'installed' : 'downloaded'; + foreach ($dep['exclude'] as $exclude) { + if (version_compare($version, $exclude, '==') && !isset($dep['conflicts'])) { + if (!isset($this->_options['nodeps']) && + !isset($this->_options['force']) + ) { + return $this->raiseError('%s is not compatible with ' . + $installed . ' package "' . + $depname . '" version ' . + $exclude); + } - if (isset($backedup)) { - $this->_removeBackups($backedup); - } + return $this->warning('warning: %s is not compatible with ' . + $installed . ' package "' . + $depname . '" version ' . + $exclude); + } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) { + $installed = $installed ? 'installed' : 'downloaded'; + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s conflicts with package "' . $depname . '"' . + $extra . ", $installed version is " . $version); + } - if (!$this->commitFileTransaction()) { - $this->rollbackFileTransaction(); - $this->configSet('default_channel', $savechannel); - return $this->raiseError("commit failed", PEAR_INSTALLER_FAILED); + return $this->warning('warning: %s conflicts with package "' . $depname . '"' . + $extra . ", $installed version is " . $version); + } + } } - // }}} - $ret = false; - $installphase = 'install'; - $oldversion = false; - // {{{ Register that the package is installed ----------------------- - if (empty($options['upgrade'])) { - // if 'force' is used, replace the info in registry - $usechannel = $channel; - if ($channel == 'pecl.php.net') { - $test = $installregistry->packageExists($pkgname, $channel); - if (!$test) { - $test = $installregistry->packageExists($pkgname, 'pear.php.net'); - $usechannel = 'pear.php.net'; - } - } else { - $test = $installregistry->packageExists($pkgname, $channel); + if (isset($dep['recommended'])) { + $installed = $installed ? 'installed' : 'downloaded'; + if (version_compare($version, $dep['recommended'], '==')) { + return true; } - if (!empty($options['force']) && $test) { - $oldversion = $installregistry->packageInfo($pkgname, 'version', $usechannel); - $installregistry->deletePackage($pkgname, $usechannel); + if (!$found && $installed) { + $param = $this->_registry->getPackage($dep['name'], $dep['channel']); } - $ret = $installregistry->addPackage2($pkg); - } else { - if ($dirtree) { - $this->startFileTransaction(); - // attempt to delete empty directories - uksort($dirtree, array($this, '_sortDirs')); - foreach($dirtree as $dir => $notused) { - $this->addFileOperation('rmdir', array($dir)); + + if ($param) { + $found = false; + foreach ($params as $parent) { + if ($parent->isEqual($this->_currentPackage)) { + $found = true; + break; + } } - $this->commitFileTransaction(); - } - $usechannel = $channel; - if ($channel == 'pecl.php.net') { - $test = $installregistry->packageExists($pkgname, $channel); - if (!$test) { - $test = $installregistry->packageExists($pkgname, 'pear.php.net'); - $usechannel = 'pear.php.net'; + if ($found) { + if ($param->isCompatible($parent)) { + return true; + } + } else { // this is for validPackage() calls + $parent = $this->_registry->getPackage($this->_currentPackage['package'], + $this->_currentPackage['channel']); + if ($parent !== null && $param->isCompatible($parent)) { + return true; + } } - } else { - $test = $installregistry->packageExists($pkgname, $channel); } - // new: upgrade installs a package if it isn't installed - if (!$test) { - $ret = $installregistry->addPackage2($pkg); - } else { - if ($usechannel != $channel) { - $installregistry->deletePackage($pkgname, $usechannel); - $ret = $installregistry->addPackage2($pkg); - } else { - $ret = $installregistry->updatePackage2($pkg); - } - $installphase = 'upgrade'; + if (!isset($this->_options['nodeps']) && !isset($this->_options['force']) && + !isset($this->_options['loose']) + ) { + return $this->raiseError('%s dependency package "' . $depname . + '" ' . $installed . ' version ' . $version . + ' is not the recommended version ' . $dep['recommended'] . + ', but may be compatible, use --force to install'); } - } - if (!$ret) { - $this->configSet('default_channel', $savechannel); - return $this->raiseError("Adding package $channel/$pkgname to registry failed"); + return $this->warning('warning: %s dependency package "' . $depname . + '" ' . $installed . ' version ' . $version . + ' is not the recommended version ' . $dep['recommended']); } - // }}} - $this->configSet('default_channel', $savechannel); - if (class_exists('PEAR_Task_Common')) { // this is auto-included if any tasks exist - if (PEAR_Task_Common::hasPostinstallTasks()) { - PEAR_Task_Common::runPostinstallTasks($installphase); - } - } - - return $pkg->toArray(true); + return true; } - // }}} + function _validatePackageInstall($dep, $required, $depv1 = false) + { + return $this->_validatePackageDownload($dep, $required, array(), $depv1); + } - // {{{ _compileSourceFiles() /** - * @param string - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * Verify that uninstalling packages passed in to command line is OK. + * + * @param PEAR_Installer $dl + * @return PEAR_Error|true */ - function _compileSourceFiles($savechannel, &$filelist) + function validatePackageUninstall(&$dl) { - require_once 'PEAR/Builder.php'; - $this->log(1, "$this->source_files source files, building"); - $bob = &new PEAR_Builder($this->ui); - $bob->debug = $this->debug; - $built = $bob->build($filelist, array(&$this, '_buildCallback')); - if (PEAR::isError($built)) { - $this->rollbackFileTransaction(); - $this->configSet('default_channel', $savechannel); - return $built; + if (PEAR::isError($this->_dependencydb)) { + return $this->_dependencydb; } - $this->log(1, "\nBuild process completed successfully"); - foreach ($built as $ext) { - $bn = basename($ext['file']); - list($_ext_name, $_ext_suff) = explode('.', $bn); - if ($_ext_suff == '.so' || $_ext_suff == '.dll') { - if (extension_loaded($_ext_name)) { - $this->raiseError("Extension '$_ext_name' already loaded. " . - 'Please unload it in your php.ini file ' . - 'prior to install or upgrade'); + $params = array(); + // construct an array of "downloaded" packages to fool the package dependency checker + // into using these to validate uninstalls of circular dependencies + $downloaded = &$dl->getUninstallPackages(); + foreach ($downloaded as $i => $pf) { + if (!class_exists('PEAR_Downloader_Package')) { + require_once 'PEAR/Downloader/Package.php'; + } + $dp = &new PEAR_Downloader_Package($dl); + $dp->setPackageFile($downloaded[$i]); + $params[$i] = &$dp; + } + + // check cache + $memyselfandI = strtolower($this->_currentPackage['channel']) . '/' . + strtolower($this->_currentPackage['package']); + if (isset($dl->___uninstall_package_cache)) { + $badpackages = $dl->___uninstall_package_cache; + if (isset($badpackages[$memyselfandI]['warnings'])) { + foreach ($badpackages[$memyselfandI]['warnings'] as $warning) { + $dl->log(0, $warning[0]); } - $role = 'ext'; - } else { - $role = 'src'; } - $dest = $ext['dest']; - $packagingroot = ''; - if (isset($this->_options['packagingroot'])) { - $packagingroot = $this->_options['packagingroot']; + if (isset($badpackages[$memyselfandI]['errors'])) { + foreach ($badpackages[$memyselfandI]['errors'] as $error) { + if (is_array($error)) { + $dl->log(0, $error[0]); + } else { + $dl->log(0, $error->getMessage()); + } + } + + if (isset($this->_options['nodeps']) || isset($this->_options['force'])) { + return $this->warning( + 'warning: %s should not be uninstalled, other installed packages depend ' . + 'on this package'); + } + + return $this->raiseError( + '%s cannot be uninstalled, other installed packages depend on this package'); } - $copyto = $this->_prependPath($dest, $packagingroot); - if ($copyto != $dest) { - $this->log(1, "Installing '$dest' as '$copyto'"); - } else { - $this->log(1, "Installing '$dest'"); + return true; + } + + // first, list the immediate parents of each package to be uninstalled + $perpackagelist = array(); + $allparents = array(); + foreach ($params as $i => $param) { + $a = array( + 'channel' => strtolower($param->getChannel()), + 'package' => strtolower($param->getPackage()) + ); + + $deps = $this->_dependencydb->getDependentPackages($a); + if ($deps) { + foreach ($deps as $d) { + $pardeps = $this->_dependencydb->getDependencies($d); + foreach ($pardeps as $dep) { + if (strtolower($dep['dep']['channel']) == $a['channel'] && + strtolower($dep['dep']['name']) == $a['package']) { + if (!isset($perpackagelist[$a['channel'] . '/' . $a['package']])) { + $perpackagelist[$a['channel'] . '/' . $a['package']] = array(); + } + $perpackagelist[$a['channel'] . '/' . $a['package']][] + = array($d['channel'] . '/' . $d['package'], $dep); + if (!isset($allparents[$d['channel'] . '/' . $d['package']])) { + $allparents[$d['channel'] . '/' . $d['package']] = array(); + } + if (!isset($allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']])) { + $allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']] = array(); + } + $allparents[$d['channel'] . '/' . $d['package']] + [$a['channel'] . '/' . $a['package']][] + = array($d, $dep); + } + } + } } + } - $copydir = dirname($copyto); - // pretty much nothing happens if we are only registering the install - if (empty($this->_options['register-only'])) { - if (!file_exists($copydir) || !is_dir($copydir)) { - if (!$this->mkDirHier($copydir)) { - return $this->raiseError("failed to mkdir $copydir", - PEAR_INSTALLER_FAILED); + // next, remove any packages from the parents list that are not installed + $remove = array(); + foreach ($allparents as $parent => $d1) { + foreach ($d1 as $d) { + if ($this->_registry->packageExists($d[0][0]['package'], $d[0][0]['channel'])) { + continue; + } + $remove[$parent] = true; + } + } + + // next remove any packages from the parents list that are not passed in for + // uninstallation + foreach ($allparents as $parent => $d1) { + foreach ($d1 as $d) { + foreach ($params as $param) { + if (strtolower($param->getChannel()) == $d[0][0]['channel'] && + strtolower($param->getPackage()) == $d[0][0]['package']) { + // found it + continue 3; } + } + $remove[$parent] = true; + } + } - $this->log(3, "+ mkdir $copydir"); + // remove all packages whose dependencies fail + // save which ones failed for error reporting + $badchildren = array(); + do { + $fail = false; + foreach ($remove as $package => $unused) { + if (!isset($allparents[$package])) { + continue; } - if (!@copy($ext['file'], $copyto)) { - return $this->raiseError("failed to write $copyto ($php_errormsg)", PEAR_INSTALLER_FAILED); + foreach ($allparents[$package] as $kid => $d1) { + foreach ($d1 as $depinfo) { + if ($depinfo[1]['type'] != 'optional') { + if (isset($badchildren[$kid])) { + continue; + } + $badchildren[$kid] = true; + $remove[$kid] = true; + $fail = true; + continue 2; + } + } + } + if ($fail) { + // start over, we removed some children + continue 2; } + } + } while ($fail); - $this->log(3, "+ cp $ext[file] $copyto"); - $this->addFileOperation('rename', array($ext['file'], $copyto)); - if (!OS_WINDOWS) { - $mode = 0666 & ~(int)octdec($this->config->get('umask')); - $this->addFileOperation('chmod', array($mode, $copyto)); - if (!@chmod($copyto, $mode)) { - $this->log(0, "failed to change mode of $copyto ($php_errormsg)"); + // next, construct the list of packages that can't be uninstalled + $badpackages = array(); + $save = $this->_currentPackage; + foreach ($perpackagelist as $package => $packagedeps) { + foreach ($packagedeps as $parent) { + if (!isset($remove[$parent[0]])) { + continue; + } + + $packagename = $this->_registry->parsePackageName($parent[0]); + $packagename['channel'] = $this->_registry->channelAlias($packagename['channel']); + $pa = $this->_registry->getPackage($packagename['package'], $packagename['channel']); + $packagename['package'] = $pa->getPackage(); + $this->_currentPackage = $packagename; + // parent is not present in uninstall list, make sure we can actually + // uninstall it (parent dep is optional) + $parentname['channel'] = $this->_registry->channelAlias($parent[1]['dep']['channel']); + $pa = $this->_registry->getPackage($parent[1]['dep']['name'], $parent[1]['dep']['channel']); + $parentname['package'] = $pa->getPackage(); + $parent[1]['dep']['package'] = $parentname['package']; + $parent[1]['dep']['channel'] = $parentname['channel']; + if ($parent[1]['type'] == 'optional') { + $test = $this->_validatePackageUninstall($parent[1]['dep'], false, $dl); + if ($test !== true) { + $badpackages[$package]['warnings'][] = $test; + } + } else { + $test = $this->_validatePackageUninstall($parent[1]['dep'], true, $dl); + if ($test !== true) { + $badpackages[$package]['errors'][] = $test; } } } + } - if ($filelist->getPackageXmlVersion() == '1.0') { - $filelist->installedFile($bn, array( - 'role' => $role, - 'name' => $bn, - 'installed_as' => $dest, - 'php_api' => $ext['php_api'], - 'zend_mod_api' => $ext['zend_mod_api'], - 'zend_ext_api' => $ext['zend_ext_api'], - )); - } else { - $filelist->installedFile($bn, array('attribs' => array( - 'role' => $role, - 'name' => $bn, - 'installed_as' => $dest, - 'php_api' => $ext['php_api'], - 'zend_mod_api' => $ext['zend_mod_api'], - 'zend_ext_api' => $ext['zend_ext_api'], - ))); + $this->_currentPackage = $save; + $dl->___uninstall_package_cache = $badpackages; + if (isset($badpackages[$memyselfandI])) { + if (isset($badpackages[$memyselfandI]['warnings'])) { + foreach ($badpackages[$memyselfandI]['warnings'] as $warning) { + $dl->log(0, $warning[0]); + } + } + + if (isset($badpackages[$memyselfandI]['errors'])) { + foreach ($badpackages[$memyselfandI]['errors'] as $error) { + if (is_array($error)) { + $dl->log(0, $error[0]); + } else { + $dl->log(0, $error->getMessage()); + } + } + + if (isset($this->_options['nodeps']) || isset($this->_options['force'])) { + return $this->warning( + 'warning: %s should not be uninstalled, other installed packages depend ' . + 'on this package'); + } + + return $this->raiseError( + '%s cannot be uninstalled, other installed packages depend on this package'); } } - } - // }}} - function &getUninstallPackages() - { - return $this->_downloadedPackages; + return true; } - // {{{ uninstall() - /** - * Uninstall a package - * - * This method removes all files installed by the application, and then - * removes any empty directories. - * @param string package name - * @param array Command-line options. Possibilities include: - * - * - installroot: base installation dir, if not the default - * - register-only : update registry but don't remove files - * - nodeps: do not process dependencies of other packages to ensure - * uninstallation does not break things - */ - function uninstall($package, $options = array()) + function _validatePackageUninstall($dep, $required, $dl) { - if (isset($options['installroot'])) { - $this->config->setInstallRoot($options['installroot']); - } else { - $this->config->setInstallRoot(''); + $depname = $this->_registry->parsedPackageNameToString($dep, true); + $version = $this->_registry->packageinfo($dep['package'], 'version', $dep['channel']); + if (!$version) { + return true; } - $this->installroot = ''; - $this->_registry = &$this->config->getRegistry(); - if (is_object($package)) { - $channel = $package->getChannel(); - $pkg = $package; - $package = $pkg->getPackage(); - } else { - $pkg = false; - $info = $this->_registry->parsePackageName($package, - $this->config->get('default_channel')); - $channel = $info['channel']; - $package = $info['package']; + $extra = $this->_getExtraString($dep); + if (isset($dep['exclude']) && !is_array($dep['exclude'])) { + $dep['exclude'] = array($dep['exclude']); } - $savechannel = $this->config->get('default_channel'); - $this->configSet('default_channel', $channel); - if (!is_object($pkg)) { - $pkg = $this->_registry->getPackage($package, $channel); + if (isset($dep['conflicts'])) { + return true; // uninstall OK - these packages conflict (probably installed with --force) } - if (!$pkg) { - $this->configSet('default_channel', $savechannel); - return $this->raiseError($this->_registry->parsedPackageNameToString( - array( - 'channel' => $channel, - 'package' => $package - ), true) . ' not installed'); + if (!isset($dep['min']) && !isset($dep['max'])) { + if (!$required) { + return $this->warning('"' . $depname . '" can be optionally used by ' . + 'installed package %s' . $extra); + } + + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('"' . $depname . '" is required by ' . + 'installed package %s' . $extra); + } + + return $this->warning('warning: "' . $depname . '" is required by ' . + 'installed package %s' . $extra); } - if ($pkg->getInstalledBinary()) { - // this is just an alias for a binary package - return $this->_registry->deletePackage($package, $channel); + $fail = false; + if (isset($dep['min']) && version_compare($version, $dep['min'], '>=')) { + $fail = true; } - $filelist = $pkg->getFilelist(); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - if (!class_exists('PEAR_Dependency2')) { - require_once 'PEAR/Dependency2.php'; + if (isset($dep['max']) && version_compare($version, $dep['max'], '<=')) { + $fail = true; } - $depchecker = &new PEAR_Dependency2($this->config, $options, - array('channel' => $channel, 'package' => $package), - PEAR_VALIDATE_UNINSTALLING); - $e = $depchecker->validatePackageUninstall($this); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($e)) { - if (!isset($options['ignore-errors'])) { - return $this->raiseError($e); - } + // we re-use this variable, preserve the original value + $saverequired = $required; + if (!$required) { + return $this->warning($depname . $extra . ' can be optionally used by installed package' . + ' "%s"'); + } - if (!isset($options['soft'])) { - $this->log(0, 'WARNING: ' . $e->getMessage()); - } - } elseif (is_array($e)) { - if (!isset($options['soft'])) { - $this->log(0, $e[0]); - } + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError($depname . $extra . ' is required by installed package' . + ' "%s"'); } - $this->pkginfo = &$pkg; - // pretty much nothing happens if we are only registering the uninstall - if (empty($options['register-only'])) { - // {{{ Delete the files - $this->startFileTransaction(); - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - if (PEAR::isError($err = $this->_deletePackageFiles($package, $channel))) { - PEAR::popErrorHandling(); - $this->rollbackFileTransaction(); - $this->configSet('default_channel', $savechannel); - if (!isset($options['ignore-errors'])) { - return $this->raiseError($err); - } + return $this->raiseError('warning: ' . $depname . $extra . + ' is required by installed package "%s"'); + } - if (!isset($options['soft'])) { - $this->log(0, 'WARNING: ' . $err->getMessage()); - } - } else { - PEAR::popErrorHandling(); - } + /** + * validate a downloaded package against installed packages + * + * As of PEAR 1.4.3, this will only validate + * + * @param array|PEAR_Downloader_Package|PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * $pkg package identifier (either + * array('package' => blah, 'channel' => blah) or an array with + * index 'info' referencing an object) + * @param PEAR_Downloader $dl + * @param array $params full list of packages to install + * @return true|PEAR_Error + */ + function validatePackage($pkg, &$dl, $params = array()) + { + if (is_array($pkg) && isset($pkg['info'])) { + $deps = $this->_dependencydb->getDependentPackageDependencies($pkg['info']); + } else { + $deps = $this->_dependencydb->getDependentPackageDependencies($pkg); + } - if (!$this->commitFileTransaction()) { - $this->rollbackFileTransaction(); - if (!isset($options['ignore-errors'])) { - return $this->raiseError("uninstall failed"); - } + $fail = false; + if ($deps) { + if (!class_exists('PEAR_Downloader_Package')) { + require_once 'PEAR/Downloader/Package.php'; + } - if (!isset($options['soft'])) { - $this->log(0, 'WARNING: uninstall failed'); - } + $dp = &new PEAR_Downloader_Package($dl); + if (is_object($pkg)) { + $dp->setPackageFile($pkg); } else { - $this->startFileTransaction(); - if ($dirtree = $pkg->getDirTree()) { - // attempt to delete empty directories - uksort($dirtree, array($this, '_sortDirs')); - foreach($dirtree as $dir => $notused) { - $this->addFileOperation('rmdir', array($dir)); - } - } else { - $this->configSet('default_channel', $savechannel); - return $this->_registry->deletePackage($package, $channel); - } + $dp->setDownloadURL($pkg); + } - if (!$this->commitFileTransaction()) { - $this->rollbackFileTransaction(); - if (!isset($options['ignore-errors'])) { - return $this->raiseError("uninstall failed"); + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + foreach ($deps as $channel => $info) { + foreach ($info as $package => $ds) { + foreach ($params as $packd) { + if (strtolower($packd->getPackage()) == strtolower($package) && + $packd->getChannel() == $channel) { + $dl->log(3, 'skipping installed package check of "' . + $this->_registry->parsedPackageNameToString( + array('channel' => $channel, 'package' => $package), + true) . + '", version "' . $packd->getVersion() . '" will be ' . + 'downloaded and installed'); + continue 2; // jump to next package + } } - if (!isset($options['soft'])) { - $this->log(0, 'WARNING: uninstall failed'); + foreach ($ds as $d) { + $checker = &new PEAR_Dependency2($this->_config, $this->_options, + array('channel' => $channel, 'package' => $package), $this->_state); + $dep = $d['dep']; + $required = $d['type'] == 'required'; + $ret = $checker->_validatePackageDownload($dep, $required, array(&$dp)); + if (is_array($ret)) { + $dl->log(0, $ret[0]); + } elseif (PEAR::isError($ret)) { + $dl->log(0, $ret->getMessage()); + $fail = true; + } } } } - // }}} + PEAR::popErrorHandling(); } - $this->configSet('default_channel', $savechannel); - // Register that the package is no longer installed - return $this->_registry->deletePackage($package, $channel); + if ($fail) { + return $this->raiseError( + '%s cannot be installed, conflicts with installed packages'); + } + + return true; } /** - * Sort a list of arrays of array(downloaded packagefilename) by dependency. - * - * It also removes duplicate dependencies - * @param array an array of PEAR_PackageFile_v[1/2] objects - * @return array|PEAR_Error array of array(packagefilename, package.xml contents) + * validate a package.xml 1.0 dependency */ - function sortPackagesForUninstall(&$packages) + function validateDependency1($dep, $params = array()) { - $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->config); - if (PEAR::isError($this->_dependencyDB)) { - return $this->_dependencyDB; + if (!isset($dep['optional'])) { + $dep['optional'] = 'no'; } - usort($packages, array(&$this, '_sortUninstall')); - } - function _sortUninstall($a, $b) - { - if (!$a->getDeps() && !$b->getDeps()) { - return 0; // neither package has dependencies, order is insignificant - } - if ($a->getDeps() && !$b->getDeps()) { - return -1; // $a must be installed after $b because $a has dependencies - } - if (!$a->getDeps() && $b->getDeps()) { - return 1; // $b must be installed after $a because $b has dependencies - } - // both packages have dependencies - if ($this->_dependencyDB->dependsOn($a, $b)) { - return -1; + list($newdep, $type) = $this->normalizeDep($dep); + if (!$newdep) { + return $this->raiseError("Invalid Dependency"); } - if ($this->_dependencyDB->dependsOn($b, $a)) { - return 1; + + if (method_exists($this, "validate{$type}Dependency")) { + return $this->{"validate{$type}Dependency"}($newdep, $dep['optional'] == 'no', + $params, true); } - return 0; } - // }}} - // {{{ _sortDirs() - function _sortDirs($a, $b) + /** + * Convert a 1.0 dep into a 2.0 dep + */ + function normalizeDep($dep) { - if (strnatcmp($a, $b) == -1) return 1; - if (strnatcmp($a, $b) == 1) return -1; - return 0; - } + $types = array( + 'pkg' => 'Package', + 'ext' => 'Extension', + 'os' => 'Os', + 'php' => 'Php' + ); - // }}} + if (!isset($types[$dep['type']])) { + return array(false, false); + } - // {{{ _buildCallback() + $type = $types[$dep['type']]; - function _buildCallback($what, $data) + $newdep = array(); + switch ($type) { + case 'Package' : + $newdep['channel'] = 'pear.php.net'; + case 'Extension' : + case 'Os' : + $newdep['name'] = $dep['name']; + break; + } + + $dep['rel'] = PEAR_Dependency2::signOperator($dep['rel']); + switch ($dep['rel']) { + case 'has' : + return array($newdep, $type); + break; + case 'not' : + $newdep['conflicts'] = true; + break; + case '>=' : + case '>' : + $newdep['min'] = $dep['version']; + if ($dep['rel'] == '>') { + $newdep['exclude'] = $dep['version']; + } + break; + case '<=' : + case '<' : + $newdep['max'] = $dep['version']; + if ($dep['rel'] == '<') { + $newdep['exclude'] = $dep['version']; + } + break; + case 'ne' : + case '!=' : + $newdep['min'] = '0'; + $newdep['max'] = '100000'; + $newdep['exclude'] = $dep['version']; + break; + case '==' : + $newdep['min'] = $dep['version']; + $newdep['max'] = $dep['version']; + break; + } + if ($type == 'Php') { + if (!isset($newdep['min'])) { + $newdep['min'] = '4.4.0'; + } + + if (!isset($newdep['max'])) { + $newdep['max'] = '6.0.0'; + } + } + return array($newdep, $type); + } + + /** + * Converts text comparing operators to them sign equivalents + * + * Example: 'ge' to '>=' + * + * @access public + * @param string Operator + * @return string Sign equivalent + */ + function signOperator($operator) { - if (($what == 'cmdoutput' && $this->debug > 1) || - ($what == 'output' && $this->debug > 0)) { - $this->ui->outputData(rtrim($data), 'build'); + switch($operator) { + case 'lt': return '<'; + case 'le': return '<='; + case 'gt': return '>'; + case 'ge': return '>='; + case 'eq': return '=='; + case 'ne': return '!='; + default: + return $operator; } } - // }}} -}PEAR-1.8.0/PEAR/PackageFile.php100664 764 764 37507 100664 10734 _options['ignore-errors'])) { + return $this->warning($msg); + } + + return PEAR::raiseError(sprintf($msg, $this->_registry->parsedPackageNameToString( + $this->_currentPackage, true))); + } + + function warning($msg) + { + return array(sprintf($msg, $this->_registry->parsedPackageNameToString( + $this->_currentPackage, true))); + } +}PEAR-1.9.0/PEAR/Downloader.php100664 764 764 201412 100664 10704 + * @author Stig Bakken + * @author Tomas V. V. Cox + * @author Martin Jansen * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: PackageFile.php,v 1.48 2009/04/09 22:16:26 dufuz Exp $ + * @version CVS: $Id: Downloader.php 287109 2009-08-11 18:50:30Z dufuz $ * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 + * @since File available since Release 1.3.0 */ /** - * needed for PEAR_VALIDATE_* constants - */ -require_once 'PEAR/Validate.php'; -/** - * Error code if the package.xml tag does not contain a valid version - */ -define('PEAR_PACKAGEFILE_ERROR_NO_PACKAGEVERSION', 1); -/** - * Error code if the package.xml tag version is not supported (version 1.0 and 1.1 are the only supported versions, - * currently + * Needed for constants, extending */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_PACKAGEVERSION', 2); +require_once 'PEAR/Common.php'; + +define('PEAR_INSTALLER_OK', 1); +define('PEAR_INSTALLER_FAILED', 0); +define('PEAR_INSTALLER_SKIPPED', -1); +define('PEAR_INSTALLER_ERROR_NO_PREF_STATE', 2); + /** - * Abstraction for the package.xml package description file + * Administration class used to download anything from the internet (PEAR Packages, + * static URLs, xml files) * * @category pear * @package PEAR * @author Greg Beaver + * @author Stig Bakken + * @author Tomas V. V. Cox + * @author Martin Jansen * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 + * @since Class available since Release 1.3.0 */ -class PEAR_PackageFile +class PEAR_Downloader extends PEAR_Common { /** - * @var PEAR_Config + * @var PEAR_Registry + * @access private */ - var $_config; - var $_debug; + var $_registry; + /** - * Temp directory for uncompressing tgz files. - * @var string|false + * Preferred Installation State (snapshot, devel, alpha, beta, stable) + * @var string|null + * @access private */ - var $_tmpdir; - var $_logger = false; + var $_preferredState; + /** - * @var boolean + * Options from command-line passed to Install. + * + * Recognized options:
+ * - onlyreqdeps : install all required dependencies as well + * - alldeps : install all dependencies, including optional + * - installroot : base relative path to install files in + * - force : force a download even if warnings would prevent it + * - nocompress : download uncompressed tarballs + * @see PEAR_Command_Install + * @access private + * @var array */ - var $_rawReturn = false; + var $_options; /** + * Downloaded Packages after a call to download(). * - * @param PEAR_Config $config - * @param ? $debug - * @param string @tmpdir Optional temporary directory for uncompressing - * files + * Format of each entry: + * + * + * array('pkg' => 'package_name', 'file' => '/path/to/local/file', + * 'info' => array() // parsed package.xml + * ); + * + * @access private + * @var array */ - function PEAR_PackageFile(&$config, $debug = false, $tmpdir = false) - { - $this->_config = $config; - $this->_debug = $debug; - $this->_tmpdir = $tmpdir; - } + var $_downloadedPackages = array(); /** - * Turn off validation - return a parsed package.xml without checking it + * Packages slated for download. * - * This is used by the package-validate command + * This is used to prevent downloading a package more than once should it be a dependency + * for two packages to be installed. + * Format of each entry: + * + *
+     * array('package_name1' => parsed package.xml, 'package_name2' => parsed package.xml,
+     * );
+     * 
+ * @access private + * @var array */ - function rawReturn() - { - $this->_rawReturn = true; - } - - function setLogger(&$l) - { - $this->_logger = &$l; - } + var $_toDownload = array(); /** - * Create a PEAR_PackageFile_Parser_v* of a given version. - * @param int $version - * @return PEAR_PackageFile_Parser_v1|PEAR_PackageFile_Parser_v1 + * Array of every package installed, with names lower-cased. + * + * Format: + * + * array('package1' => 0, 'package2' => 1, ); + * + * @var array */ - function &parserFactory($version) - { - if (!in_array($version{0}, array('1', '2'))) { - $a = false; - return $a; - } + var $_installed = array(); - include_once 'PEAR/PackageFile/Parser/v' . $version{0} . '.php'; - $version = $version{0}; - $class = "PEAR_PackageFile_Parser_v$version"; - $a = new $class; - return $a; - } + /** + * @var array + * @access private + */ + var $_errorStack = array(); /** - * For simpler unit-testing - * @return string + * @var boolean + * @access private */ - function getClassPrefix() - { - return 'PEAR_PackageFile_v'; - } + var $_internalDownload = false; /** - * Create a PEAR_PackageFile_v* of a given version. - * @param int $version - * @return PEAR_PackageFile_v1|PEAR_PackageFile_v1 + * Temporary variable used in sorting packages by dependency in {@link sortPkgDeps()} + * @var array + * @access private */ - function &factory($version) - { - if (!in_array($version{0}, array('1', '2'))) { - $a = false; - return $a; - } + var $_packageSortTree; - include_once 'PEAR/PackageFile/v' . $version{0} . '.php'; - $version = $version{0}; - $class = $this->getClassPrefix() . $version; - $a = new $class; - return $a; - } + /** + * Temporary directory, or configuration value where downloads will occur + * @var string + */ + var $_downloadDir; /** - * Create a PEAR_PackageFile_v* from its toArray() method - * - * WARNING: no validation is performed, the array is assumed to be valid, - * always parse from xml if you want validation. - * @param array $arr - * @return PEAR_PackageFileManager_v1|PEAR_PackageFileManager_v2 - * @uses factory() to construct the returned object. + * @param PEAR_Frontend_* + * @param array + * @param PEAR_Config */ - function &fromArray($arr) + function PEAR_Downloader(&$ui, $options, &$config) { - if (isset($arr['xsdversion'])) { - $obj = &$this->factory($arr['xsdversion']); - if ($this->_logger) { - $obj->setLogger($this->_logger); - } - - $obj->setConfig($this->_config); - $obj->fromArray($arr); - return $obj; + parent::PEAR_Common(); + $this->_options = $options; + $this->config = &$config; + $this->_preferredState = $this->config->get('preferred_state'); + $this->ui = &$ui; + if (!$this->_preferredState) { + // don't inadvertantly use a non-set preferred_state + $this->_preferredState = null; } - if (isset($arr['package']['attribs']['version'])) { - $obj = &$this->factory($arr['package']['attribs']['version']); - } else { - $obj = &$this->factory('1.0'); + if (isset($this->_options['installroot'])) { + $this->config->setInstallRoot($this->_options['installroot']); } + $this->_registry = &$config->getRegistry(); - if ($this->_logger) { - $obj->setLogger($this->_logger); + if (isset($this->_options['alldeps']) || isset($this->_options['onlyreqdeps'])) { + $this->_installed = $this->_registry->listAllPackages(); + foreach ($this->_installed as $key => $unused) { + if (!count($unused)) { + continue; + } + $strtolower = create_function('$a','return strtolower($a);'); + array_walk($this->_installed[$key], $strtolower); + } } - - $obj->setConfig($this->_config); - $obj->fromArray($arr); - return $obj; } /** - * Create a PEAR_PackageFile_v* from an XML string. - * @access public - * @param string $data contents of package.xml file - * @param int $state package state (one of PEAR_VALIDATE_* constants) - * @param string $file full path to the package.xml file (and the files - * it references) - * @param string $archive optional name of the archive that the XML was - * extracted from, if any - * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @uses parserFactory() to construct a parser to load the package. + * Attempt to discover a channel's remote capabilities from + * its server name + * @param string + * @return boolean */ - function &fromXmlString($data, $state, $file, $archive = false) + function discover($channel) { - if (preg_match('/]+version="([0-9]+\.[0-9]+)"/', $data, $packageversion)) { - if (!in_array($packageversion[1], array('1.0', '2.0', '2.1'))) { - return PEAR::raiseError('package.xml version "' . $packageversion[1] . - '" is not supported, only 1.0, 2.0, and 2.1 are supported.'); - } - - $object = &$this->parserFactory($packageversion[1]); - if ($this->_logger) { - $object->setLogger($this->_logger); - } - - $object->setConfig($this->_config); - $pf = $object->parse($data, $file, $archive); - if (PEAR::isError($pf)) { - return $pf; - } - - if ($this->_rawReturn) { - return $pf; - } - - if (!$pf->validate($state)) { - if ($this->_config->get('verbose') > 0 - && $this->_logger && $pf->getValidationWarnings(false)) { - foreach ($pf->getValidationWarnings(false) as $warning) { - $this->_logger->log(0, 'ERROR: ' . $warning['message']); - } - } - - $a = PEAR::raiseError('Parsing of package.xml from file "' . $file . '" failed', - 2, null, null, $pf->getValidationWarnings()); - return $a; - } - - if ($this->_logger && $pf->getValidationWarnings(false)) { - foreach ($pf->getValidationWarnings() as $warning) { - $this->_logger->log(0, 'WARNING: ' . $warning['message']); - } - } - - if (method_exists($pf, 'flattenFilelist')) { - $pf->flattenFilelist(); // for v2 - } - - return $pf; - } elseif (preg_match('/]+version="([^"]+)"/', $data, $packageversion)) { - $a = PEAR::raiseError('package.xml file "' . $file . - '" has unsupported package.xml version "' . $packageversion[1] . '"'); - return $a; - } else { - if (!class_exists('PEAR_ErrorStack')) { - require_once 'PEAR/ErrorStack.php'; - } - - PEAR_ErrorStack::staticPush('PEAR_PackageFile', - PEAR_PACKAGEFILE_ERROR_NO_PACKAGEVERSION, - 'warning', array('xml' => $data), 'package.xml "' . $file . - '" has no package.xml version'); - $object = &$this->parserFactory('1.0'); - $object->setConfig($this->_config); - $pf = $object->parse($data, $file, $archive); - if (PEAR::isError($pf)) { - return $pf; - } + $this->log(1, 'Attempting to discover channel "' . $channel . '"...'); + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $callback = $this->ui ? array(&$this, '_downloadCallback') : null; + if (!class_exists('System')) { + require_once 'System.php'; + } - if ($this->_rawReturn) { - return $pf; + $tmp = System::mktemp(array('-d')); + $a = $this->downloadHttp('http://' . $channel . '/channel.xml', $this->ui, $tmp, $callback, false); + PEAR::popErrorHandling(); + if (PEAR::isError($a)) { + // Attempt to fallback to https automatically. + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $this->log(1, 'Attempting fallback to https instead of http on channel "' . $channel . '"...'); + $a = $this->downloadHttp('https://' . $channel . '/channel.xml', $this->ui, $tmp, $callback, false); + PEAR::popErrorHandling(); + if (PEAR::isError($a)) { + return false; } + } - if (!$pf->validate($state)) { - $a = PEAR::raiseError('Parsing of package.xml from file "' . $file . '" failed', - 2, null, null, $pf->getValidationWarnings()); - return $a; - } + list($a, $lastmodified) = $a; + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } - if ($this->_logger && $pf->getValidationWarnings(false)) { - foreach ($pf->getValidationWarnings() as $warning) { - $this->_logger->log(0, 'WARNING: ' . $warning['message']); + $b = new PEAR_ChannelFile; + if ($b->fromXmlFile($a)) { + unlink($a); + if ($this->config->get('auto_discover')) { + $this->_registry->addChannel($b, $lastmodified); + $alias = $b->getName(); + if ($b->getName() == $this->_registry->channelName($b->getAlias())) { + $alias = $b->getAlias(); } - } - if (method_exists($pf, 'flattenFilelist')) { - $pf->flattenFilelist(); // for v2 + $this->log(1, 'Auto-discovered channel "' . $channel . + '", alias "' . $alias . '", adding to registry'); } - return $pf; + return true; } + + unlink($a); + return false; } /** - * Register a temporary file or directory. When the destructor is - * executed, all registered temporary files and directories are - * removed. - * - * @param string $file name of file or directory - * @return void + * For simpler unit-testing + * @param PEAR_Downloader + * @return PEAR_Downloader_Package */ - function addTempFile($file) + function &newDownloaderPackage(&$t) { - $GLOBALS['_PEAR_Common_tempfiles'][] = $file; + if (!class_exists('PEAR_Downloader_Package')) { + require_once 'PEAR/Downloader/Package.php'; + } + $a = &new PEAR_Downloader_Package($t); + return $a; } /** - * Create a PEAR_PackageFile_v* from a compresed Tar or Tgz file. - * @access public - * @param string contents of package.xml file - * @param int package state (one of PEAR_VALIDATE_* constants) - * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @using Archive_Tar to extract the files - * @using fromPackageFile() to load the package after the package.xml - * file is extracted. + * For simpler unit-testing + * @param PEAR_Config + * @param array + * @param array + * @param int */ - function &fromTgzFile($file, $state) + function &getDependency2Object(&$c, $i, $p, $s) { - if (!class_exists('Archive_Tar')) { - require_once 'Archive/Tar.php'; + if (!class_exists('PEAR_Dependency2')) { + require_once 'PEAR/Dependency2.php'; } + $z = &new PEAR_Dependency2($c, $i, $p, $s); + return $z; + } - $tar = new Archive_Tar($file); - if ($this->_debug <= 1) { - $tar->pushErrorHandling(PEAR_ERROR_RETURN); + function &download($params) + { + if (!count($params)) { + $a = array(); + return $a; } - $content = $tar->listContent(); - if ($this->_debug <= 1) { - $tar->popErrorHandling(); + if (!isset($this->_registry)) { + $this->_registry = &$this->config->getRegistry(); } - if (!is_array($content)) { - if (is_string($file) && strlen($file < 255) && - (!file_exists($file) || !@is_file($file))) { - $ret = PEAR::raiseError("could not open file \"$file\""); - return $ret; + $channelschecked = array(); + // convert all parameters into PEAR_Downloader_Package objects + foreach ($params as $i => $param) { + $params[$i] = &$this->newDownloaderPackage($this); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $err = $params[$i]->initialize($param); + PEAR::staticPopErrorHandling(); + if (!$err) { + // skip parameters that were missed by preferred_state + continue; } - $file = realpath($file); - $ret = PEAR::raiseError("Could not get contents of package \"$file\"". - '. Invalid tgz file.'); - return $ret; - } else { - if (!count($content) && !@is_file($file)) { - $ret = PEAR::raiseError("could not open file \"$file\""); - return $ret; - } - } + if (PEAR::isError($err)) { + if (!isset($this->_options['soft']) && $err->getMessage() !== '') { + $this->log(0, $err->getMessage()); + } - $xml = null; - $origfile = $file; - foreach ($content as $file) { - $name = $file['filename']; - if ($name == 'package2.xml') { // allow a .tgz to distribute both versions - $xml = $name; - break; - } + $params[$i] = false; + if (is_object($param)) { + $param = $param->getChannel() . '/' . $param->getPackage(); + } - if ($name == 'package.xml') { - $xml = $name; - break; - } elseif (preg_match('/package.xml$/', $name, $match)) { - $xml = $name; - break; - } - } + if (!isset($this->_options['soft'])) { + $this->log(2, 'Package "' . $param . '" is not valid'); + } - if ($this->_tmpdir) { - $tmpdir = $this->_tmpdir; - } else { - $tmpdir = System::mkTemp(array('-t', $this->_config->get('temp_dir'), '-d', 'pear')); - if ($tmpdir === false) { - $ret = PEAR::raiseError("there was a problem with getting the configured temp directory"); - return $ret; - } + // Message logged above in a specific verbose mode, passing null to not show up on CLI + $this->pushError(null, PEAR_INSTALLER_SKIPPED); + } else { + do { + if ($params[$i] && $params[$i]->getType() == 'local') { + // bug #7090 skip channel.xml check for local packages + break; + } - PEAR_PackageFile::addTempFile($tmpdir); - } + if ($params[$i] && !isset($channelschecked[$params[$i]->getChannel()]) && + !isset($this->_options['offline']) + ) { + $channelschecked[$params[$i]->getChannel()] = true; + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + if (!class_exists('System')) { + require_once 'System.php'; + } - $this->_extractErrors(); - PEAR::staticPushErrorHandling(PEAR_ERROR_CALLBACK, array($this, '_extractErrors')); - if (!$xml || !$tar->extractList(array($xml), $tmpdir)) { - $extra = implode("\n", $this->_extractErrors()); - if ($extra) { - $extra = ' ' . $extra; - } + $curchannel = &$this->_registry->getChannel($params[$i]->getChannel()); + if (PEAR::isError($curchannel)) { + PEAR::staticPopErrorHandling(); + return $this->raiseError($curchannel); + } - PEAR::staticPopErrorHandling(); - $ret = PEAR::raiseError('could not extract the package.xml file from "' . - $origfile . '"' . $extra); - return $ret; - } + if (PEAR::isError($dir = $this->getDownloadDir())) { + PEAR::staticPopErrorHandling(); + break; + } - PEAR::staticPopErrorHandling(); - $ret = &PEAR_PackageFile::fromPackageFile("$tmpdir/$xml", $state, $origfile); - return $ret; - } + $mirror = $this->config->get('preferred_mirror', null, $params[$i]->getChannel()); + $url = 'http://' . $mirror . '/channel.xml'; + $a = $this->downloadHttp($url, $this->ui, $dir, null, $curchannel->lastModified()); - /** - * helper for extracting Archive_Tar errors - * @var array - * @access private - */ - var $_extractErrors = array(); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($a) || !$a) { + // Attempt fallback to https automatically + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $a = $this->downloadHttp('https://' . $mirror . + '/channel.xml', $this->ui, $dir, null, $curchannel->lastModified()); - /** - * helper callback for extracting Archive_Tar errors - * - * @param PEAR_Error|null $err - * @return array - * @access private - */ - function _extractErrors($err = null) - { - static $errors = array(); - if ($err === null) { - $e = $errors; - $errors = array(); - return $e; - } - $errors[] = $err->getMessage(); - } + PEAR::staticPopErrorHandling(); + if (PEAR::isError($a) || !$a) { + break; + } + } + $this->log(0, 'WARNING: channel "' . $params[$i]->getChannel() . '" has ' . + 'updated its protocols, use "' . PEAR_RUNTYPE . ' channel-update ' . $params[$i]->getChannel() . + '" to update'); + } + } while (false); - /** - * Create a PEAR_PackageFile_v* from a package.xml file. - * - * @access public - * @param string $descfile name of package xml file - * @param int $state package state (one of PEAR_VALIDATE_* constants) - * @param string|false $archive name of the archive this package.xml came - * from, if any - * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @uses PEAR_PackageFile::fromXmlString to create the oject after the - * XML is loaded from the package.xml file. - */ - function &fromPackageFile($descfile, $state, $archive = false) - { - $fp = false; - if (is_string($descfile) && strlen($descfile) < 255 && - ( - !file_exists($descfile) || !is_file($descfile) || !is_readable($descfile) - || (!$fp = @fopen($descfile, 'r')) - ) - ) { - $a = PEAR::raiseError("Unable to open $descfile"); - return $a; - } + if ($params[$i] && !isset($this->_options['downloadonly'])) { + if (isset($this->_options['packagingroot'])) { + $checkdir = $this->_prependPath( + $this->config->get('php_dir', null, $params[$i]->getChannel()), + $this->_options['packagingroot']); + } else { + $checkdir = $this->config->get('php_dir', + null, $params[$i]->getChannel()); + } - // read the whole thing so we only get one cdata callback - // for each block of cdata - fclose($fp); - $data = file_get_contents($descfile); - $ret = &PEAR_PackageFile::fromXmlString($data, $state, $descfile, $archive); - return $ret; - } + while ($checkdir && $checkdir != '/' && !file_exists($checkdir)) { + $checkdir = dirname($checkdir); + } + if ($checkdir == '.') { + $checkdir = '/'; + } - /** - * Create a PEAR_PackageFile_v* from a .tgz archive or package.xml file. - * - * This method is able to extract information about a package from a .tgz - * archive or from a XML package definition file. - * - * @access public - * @param string $info file name - * @param int $state package state (one of PEAR_VALIDATE_* constants) - * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @uses fromPackageFile() if the file appears to be XML - * @uses fromTgzFile() to load all non-XML files - */ - function &fromAnyFile($info, $state) - { - if (is_dir($info)) { - $dir_name = realpath($info); - if (file_exists($dir_name . '/package.xml')) { - $info = PEAR_PackageFile::fromPackageFile($dir_name . '/package.xml', $state); - } elseif (file_exists($dir_name . '/package2.xml')) { - $info = PEAR_PackageFile::fromPackageFile($dir_name . '/package2.xml', $state); - } else { - $info = PEAR::raiseError("No package definition found in '$info' directory"); + if (!is_writeable($checkdir)) { + return PEAR::raiseError('Cannot install, php_dir for channel "' . + $params[$i]->getChannel() . '" is not writeable by the current user'); + } + } } - - return $info; } - $fp = false; - if (is_string($info) && strlen($info) < 255 && - (file_exists($info) || ($fp = @fopen($info, 'r'))) - ) { - - if ($fp) { - fclose($fp); - } + unset($channelschecked); + PEAR_Downloader_Package::removeDuplicates($params); + if (!count($params)) { + $a = array(); + return $a; + } - $tmp = substr($info, -4); - if ($tmp == '.xml') { - $info = &PEAR_PackageFile::fromPackageFile($info, $state); - } elseif ($tmp == '.tar' || $tmp == '.tgz') { - $info = &PEAR_PackageFile::fromTgzFile($info, $state); - } else { - $fp = fopen($info, 'r'); - $test = fread($fp, 5); - fclose($fp); - if ($test == '_options['nodeps']) && !isset($this->_options['offline'])) { + $reverify = true; + while ($reverify) { + $reverify = false; + foreach ($params as $i => $param) { + //PHP Bug 40768 / PEAR Bug #10944 + //Nested foreaches fail in PHP 5.2.1 + key($params); + $ret = $params[$i]->detectDependencies($params); + if (PEAR::isError($ret)) { + $reverify = true; + $params[$i] = false; + PEAR_Downloader_Package::removeDuplicates($params); + if (!isset($this->_options['soft'])) { + $this->log(0, $ret->getMessage()); + } + continue 2; + } } } - - return $info; } - $info = PEAR::raiseError("Cannot open '$info' for parsing"); - return $info; - } -}PEAR-1.8.0/PEAR/Packager.php100664 764 764 15603 100664 10307 - * @author Tomas V. V. Cox - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Packager.php,v 1.75 2009/02/24 23:38:22 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/** - * base class - */ -require_once 'PEAR/Common.php'; -require_once 'PEAR/PackageFile.php'; -require_once 'System.php'; - -/** - * Administration class used to make a PEAR release tarball. - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 - */ -class PEAR_Packager extends PEAR_Common -{ - /** - * @var PEAR_Registry - */ - var $_registry; + if (isset($this->_options['offline'])) { + $this->log(3, 'Skipping dependency download check, --offline specified'); + } - function package($pkgfile = null, $compress = true, $pkg2 = null) - { - // {{{ validate supplied package.xml file - if (empty($pkgfile)) { - $pkgfile = 'package.xml'; + if (!count($params)) { + $a = array(); + return $a; } - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $pkg = &new PEAR_PackageFile($this->config, $this->debug); - $pf = &$pkg->fromPackageFile($pkgfile, PEAR_VALIDATE_NORMAL); - $main = &$pf; - PEAR::staticPopErrorHandling(); - if (PEAR::isError($pf)) { - if (is_array($pf->getUserInfo())) { - foreach ($pf->getUserInfo() as $error) { - $this->log(0, 'Error: ' . $error['message']); + while (PEAR_Downloader_Package::mergeDependencies($params)); + PEAR_Downloader_Package::removeDuplicates($params, true); + $errorparams = array(); + if (PEAR_Downloader_Package::detectStupidDuplicates($params, $errorparams)) { + if (count($errorparams)) { + foreach ($errorparams as $param) { + $name = $this->_registry->parsedPackageNameToString($param->getParsedPackage()); + $this->pushError('Duplicate package ' . $name . ' found', PEAR_INSTALLER_FAILED); } + $a = array(); + return $a; } + } - $this->log(0, $pf->getMessage()); - return $this->raiseError("Cannot package, errors in package file"); + PEAR_Downloader_Package::removeInstalled($params); + if (!count($params)) { + $this->pushError('No valid packages found', PEAR_INSTALLER_FAILED); + $a = array(); + return $a; } - foreach ($pf->getValidationWarnings() as $warning) { - $this->log(1, 'Warning: ' . $warning['message']); + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $err = $this->analyzeDependencies($params); + PEAR::popErrorHandling(); + if (!count($params)) { + $this->pushError('No valid packages found', PEAR_INSTALLER_FAILED); + $a = array(); + return $a; } - // }}} - if ($pkg2) { - $this->log(0, 'Attempting to process the second package file'); + $ret = array(); + $newparams = array(); + if (isset($this->_options['pretend'])) { + return $params; + } + + $somefailed = false; + foreach ($params as $i => $package) { PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $pf2 = &$pkg->fromPackageFile($pkg2, PEAR_VALIDATE_NORMAL); + $pf = &$params[$i]->download(); PEAR::staticPopErrorHandling(); - if (PEAR::isError($pf2)) { - if (is_array($pf2->getUserInfo())) { - foreach ($pf2->getUserInfo() as $error) { - $this->log(0, 'Error: ' . $error['message']); - } + if (PEAR::isError($pf)) { + if (!isset($this->_options['soft'])) { + $this->log(1, $pf->getMessage()); + $this->log(0, 'Error: cannot download "' . + $this->_registry->parsedPackageNameToString($package->getParsedPackage(), + true) . + '"'); } - $this->log(0, $pf2->getMessage()); - return $this->raiseError("Cannot package, errors in second package file"); - } - - foreach ($pf2->getValidationWarnings() as $warning) { - $this->log(1, 'Warning: ' . $warning['message']); - } - - if ($pf2->getPackagexmlVersion() == '2.0' || - $pf2->getPackagexmlVersion() == '2.1' - ) { - $main = &$pf2; - $other = &$pf; - } else { - $main = &$pf; - $other = &$pf2; - } - - if ($main->getPackagexmlVersion() != '2.0' && - $main->getPackagexmlVersion() != '2.1') { - return PEAR::raiseError('Error: cannot package two package.xml version 1.0, can ' . - 'only package together a package.xml 1.0 and package.xml 2.0'); + $somefailed = true; + continue; } - if ($other->getPackagexmlVersion() != '1.0') { - return PEAR::raiseError('Error: cannot package two package.xml version 2.0, can ' . - 'only package together a package.xml 1.0 and package.xml 2.0'); - } + $newparams[] = &$params[$i]; + $ret[] = array( + 'file' => $pf->getArchiveFile(), + 'info' => &$pf, + 'pkg' => $pf->getPackage() + ); } - $main->setLogger($this); - if (!$main->validate(PEAR_VALIDATE_PACKAGING)) { - foreach ($main->getValidationWarnings() as $warning) { - $this->log(0, 'Error: ' . $warning['message']); + if ($somefailed) { + // remove params that did not download successfully + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $err = $this->analyzeDependencies($newparams, true); + PEAR::popErrorHandling(); + if (!count($newparams)) { + $this->pushError('Download failed', PEAR_INSTALLER_FAILED); + $a = array(); + return $a; } - return $this->raiseError("Cannot package, errors in package"); } - foreach ($main->getValidationWarnings() as $warning) { - $this->log(1, 'Warning: ' . $warning['message']); + $this->_downloadedPackages = $ret; + return $newparams; + } + + /** + * @param array all packages to be installed + */ + function analyzeDependencies(&$params, $force = false) + { + $hasfailed = $failed = false; + if (isset($this->_options['downloadonly'])) { + return; } - if ($pkg2) { - $other->setLogger($this); - $a = false; - if (!$other->validate(PEAR_VALIDATE_NORMAL) || $a = !$main->isEquivalent($other)) { - foreach ($other->getValidationWarnings() as $warning) { - $this->log(0, 'Error: ' . $warning['message']); - } + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $redo = true; + $reset = false; + while ($redo) { + $redo = false; + foreach ($params as $i => $param) { + $deps = $param->getDeps(); + if (!$deps) { + $depchecker = &$this->getDependency2Object($this->config, $this->getOptions(), + $param->getParsedPackage(), PEAR_VALIDATE_DOWNLOADING); + $send = $param->getPackageFile(); - foreach ($main->getValidationWarnings() as $warning) { - $this->log(0, 'Error: ' . $warning['message']); + $installcheck = $depchecker->validatePackage($send, $this, $params); + if (PEAR::isError($installcheck)) { + if (!isset($this->_options['soft'])) { + $this->log(0, $installcheck->getMessage()); + } + $hasfailed = true; + $params[$i] = false; + $reset = true; + $redo = true; + $failed = false; + PEAR_Downloader_Package::removeDuplicates($params); + continue 2; + } + continue; } - if ($a) { - return $this->raiseError('The two package.xml files are not equivalent!'); + if (!$reset && $param->alreadyValidated() && !$force) { + continue; } - return $this->raiseError("Cannot package, errors in package"); - } + if (count($deps)) { + $depchecker = &$this->getDependency2Object($this->config, $this->getOptions(), + $param->getParsedPackage(), PEAR_VALIDATE_DOWNLOADING); + $send = $param->getPackageFile(); + if ($send === null) { + $send = $param->getDownloadURL(); + } - foreach ($other->getValidationWarnings() as $warning) { - $this->log(1, 'Warning: ' . $warning['message']); - } + $installcheck = $depchecker->validatePackage($send, $this, $params); + if (PEAR::isError($installcheck)) { + if (!isset($this->_options['soft'])) { + $this->log(0, $installcheck->getMessage()); + } + $hasfailed = true; + $params[$i] = false; + $reset = true; + $redo = true; + $failed = false; + PEAR_Downloader_Package::removeDuplicates($params); + continue 2; + } - $gen = &$main->getDefaultGenerator(); - $tgzfile = $gen->toTgz2($this, $other, $compress); - if (PEAR::isError($tgzfile)) { - return $tgzfile; - } + $failed = false; + if (isset($deps['required'])) { + foreach ($deps['required'] as $type => $dep) { + // note: Dependency2 will never return a PEAR_Error if ignore-errors + // is specified, so soft is needed to turn off logging + if (!isset($dep[0])) { + if (PEAR::isError($e = $depchecker->{"validate{$type}Dependency"}($dep, + true, $params))) { + $failed = true; + if (!isset($this->_options['soft'])) { + $this->log(0, $e->getMessage()); + } + } elseif (is_array($e) && !$param->alreadyValidated()) { + if (!isset($this->_options['soft'])) { + $this->log(0, $e[0]); + } + } + } else { + foreach ($dep as $d) { + if (PEAR::isError($e = + $depchecker->{"validate{$type}Dependency"}($d, + true, $params))) { + $failed = true; + if (!isset($this->_options['soft'])) { + $this->log(0, $e->getMessage()); + } + } elseif (is_array($e) && !$param->alreadyValidated()) { + if (!isset($this->_options['soft'])) { + $this->log(0, $e[0]); + } + } + } + } + } - $dest_package = basename($tgzfile); - $pkgdir = dirname($pkgfile); + if (isset($deps['optional'])) { + foreach ($deps['optional'] as $type => $dep) { + if (!isset($dep[0])) { + if (PEAR::isError($e = + $depchecker->{"validate{$type}Dependency"}($dep, + false, $params))) { + $failed = true; + if (!isset($this->_options['soft'])) { + $this->log(0, $e->getMessage()); + } + } elseif (is_array($e) && !$param->alreadyValidated()) { + if (!isset($this->_options['soft'])) { + $this->log(0, $e[0]); + } + } + } else { + foreach ($dep as $d) { + if (PEAR::isError($e = + $depchecker->{"validate{$type}Dependency"}($d, + false, $params))) { + $failed = true; + if (!isset($this->_options['soft'])) { + $this->log(0, $e->getMessage()); + } + } elseif (is_array($e) && !$param->alreadyValidated()) { + if (!isset($this->_options['soft'])) { + $this->log(0, $e[0]); + } + } + } + } + } + } - // TAR the Package ------------------------------------------- - $this->log(1, "Package $dest_package done"); - if (file_exists("$pkgdir/CVS/Root")) { - $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $pf->getVersion()); - $cvstag = "RELEASE_$cvsversion"; - $this->log(1, 'Tag the released code with "pear cvstag ' . - $main->getPackageFile() . '"'); - $this->log(1, "(or set the CVS tag $cvstag by hand)"); - } - } else { // this branch is executed for single packagefile packaging - $gen = &$pf->getDefaultGenerator(); - $tgzfile = $gen->toTgz($this, $compress); - if (PEAR::isError($tgzfile)) { - $this->log(0, $tgzfile->getMessage()); - return $this->raiseError("Cannot package, errors in package"); - } + $groupname = $param->getGroup(); + if (isset($deps['group']) && $groupname) { + if (!isset($deps['group'][0])) { + $deps['group'] = array($deps['group']); + } - $dest_package = basename($tgzfile); - $pkgdir = dirname($pkgfile); + $found = false; + foreach ($deps['group'] as $group) { + if ($group['attribs']['name'] == $groupname) { + $found = true; + break; + } + } - // TAR the Package ------------------------------------------- - $this->log(1, "Package $dest_package done"); - if (file_exists("$pkgdir/CVS/Root")) { - $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $pf->getVersion()); - $cvstag = "RELEASE_$cvsversion"; - $this->log(1, "Tag the released code with `pear cvstag $pkgfile'"); - $this->log(1, "(or set the CVS tag $cvstag by hand)"); + if ($found) { + unset($group['attribs']); + foreach ($group as $type => $dep) { + if (!isset($dep[0])) { + if (PEAR::isError($e = + $depchecker->{"validate{$type}Dependency"}($dep, + false, $params))) { + $failed = true; + if (!isset($this->_options['soft'])) { + $this->log(0, $e->getMessage()); + } + } elseif (is_array($e) && !$param->alreadyValidated()) { + if (!isset($this->_options['soft'])) { + $this->log(0, $e[0]); + } + } + } else { + foreach ($dep as $d) { + if (PEAR::isError($e = + $depchecker->{"validate{$type}Dependency"}($d, + false, $params))) { + $failed = true; + if (!isset($this->_options['soft'])) { + $this->log(0, $e->getMessage()); + } + } elseif (is_array($e) && !$param->alreadyValidated()) { + if (!isset($this->_options['soft'])) { + $this->log(0, $e[0]); + } + } + } + } + } + } + } + } else { + foreach ($deps as $dep) { + if (PEAR::isError($e = $depchecker->validateDependency1($dep, $params))) { + $failed = true; + if (!isset($this->_options['soft'])) { + $this->log(0, $e->getMessage()); + } + } elseif (is_array($e) && !$param->alreadyValidated()) { + if (!isset($this->_options['soft'])) { + $this->log(0, $e[0]); + } + } + } + } + $params[$i]->setValidated(); + } + + if ($failed) { + $hasfailed = true; + $params[$i] = false; + $reset = true; + $redo = true; + $failed = false; + PEAR_Downloader_Package::removeDuplicates($params); + continue 2; + } + } + } + PEAR::staticPopErrorHandling(); + if ($hasfailed && (isset($this->_options['ignore-errors']) || + isset($this->_options['nodeps']))) { + // this is probably not needed, but just in case + if (!isset($this->_options['soft'])) { + $this->log(0, 'WARNING: dependencies failed'); } } - - return $dest_package; - } -}PEAR-1.8.0/PEAR/Registry.php100664 764 764 226577 100664 10440 - * @author Tomas V. V. Cox - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Registry.php,v 1.179 2009/04/10 19:42:18 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/** - * for PEAR_Error - */ -require_once 'PEAR.php'; -require_once 'PEAR/DependencyDB.php'; - -define('PEAR_REGISTRY_ERROR_LOCK', -2); -define('PEAR_REGISTRY_ERROR_FORMAT', -3); -define('PEAR_REGISTRY_ERROR_FILE', -4); -define('PEAR_REGISTRY_ERROR_CONFLICT', -5); -define('PEAR_REGISTRY_ERROR_CHANNEL_FILE', -6); - -/** - * Administration class used to maintain the installed package database. - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Tomas V. V. Cox - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Registry extends PEAR -{ - /** - * File containing all channel information. - * @var string - */ - var $channels = ''; - - /** Directory where registry files are stored. - * @var string - */ - var $statedir = ''; - - /** File where the file map is stored - * @var string - */ - var $filemap = ''; - - /** Directory where registry files for channels are stored. - * @var string - */ - var $channelsdir = ''; - - /** Name of file used for locking the registry - * @var string - */ - var $lockfile = ''; - - /** File descriptor used during locking - * @var resource - */ - var $lock_fp = null; - - /** Mode used during locking - * @var int - */ - var $lock_mode = 0; // XXX UNUSED - - /** Cache of package information. Structure: - * array( - * 'package' => array('id' => ... ), - * ... ) - * @var array - */ - var $pkginfo_cache = array(); - - /** Cache of file map. Structure: - * array( '/path/to/file' => 'package', ... ) - * @var array - */ - var $filemap_cache = array(); - - /** - * @var false|PEAR_ChannelFile - */ - var $_pearChannel; - - /** - * @var false|PEAR_ChannelFile - */ - var $_peclChannel; - - /** - * @var false|PEAR_ChannelFile - */ - var $_docChannel; - - /** - * @var PEAR_DependencyDB - */ - var $_dependencyDB; - - /** - * @var PEAR_Config - */ - var $_config; - - /** - * PEAR_Registry constructor. - * - * @param string (optional) PEAR install directory (for .php files) - * @param PEAR_ChannelFile PEAR_ChannelFile object representing the PEAR channel, if - * default values are not desired. Only used the very first time a PEAR - * repository is initialized - * @param PEAR_ChannelFile PEAR_ChannelFile object representing the PECL channel, if - * default values are not desired. Only used the very first time a PEAR - * repository is initialized - * - * @access public - */ - function PEAR_Registry($pear_install_dir = PEAR_INSTALL_DIR, $pear_channel = false, - $pecl_channel = false) - { - parent::PEAR(); - $this->setInstallDir($pear_install_dir); - $this->_pearChannel = $pear_channel; - $this->_peclChannel = $pecl_channel; - $this->_config = false; - } - - function setInstallDir($pear_install_dir = PEAR_INSTALL_DIR) - { - $ds = DIRECTORY_SEPARATOR; - $this->install_dir = $pear_install_dir; - $this->channelsdir = $pear_install_dir.$ds.'.channels'; - $this->statedir = $pear_install_dir.$ds.'.registry'; - $this->filemap = $pear_install_dir.$ds.'.filemap'; - $this->lockfile = $pear_install_dir.$ds.'.lock'; - } - - function hasWriteAccess() - { - if (!file_exists($this->install_dir)) { - $dir = $this->install_dir; - while ($dir && $dir != '.') { - $olddir = $dir; - $dir = dirname($dir); - if ($dir != '.' && file_exists($dir)) { - if (is_writeable($dir)) { - return true; - } - - return false; - } - - if ($dir == $olddir) { // this can happen in safe mode - return @is_writable($dir); - } - } - - return false; - } - - return is_writeable($this->install_dir); - } - - function setConfig(&$config, $resetInstallDir = true) - { - $this->_config = &$config; - if ($resetInstallDir) { - $this->setInstallDir($config->get('php_dir')); - } - } - - function _initializeChannelDirs() - { - static $running = false; - if (!$running) { - $running = true; - $ds = DIRECTORY_SEPARATOR; - if (!is_dir($this->channelsdir) || - !file_exists($this->channelsdir . $ds . 'pear.php.net.reg') || - !file_exists($this->channelsdir . $ds . 'pecl.php.net.reg') || - !file_exists($this->channelsdir . $ds . 'doc.php.net.reg') || - !file_exists($this->channelsdir . $ds . '__uri.reg')) { - if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) { - $pear_channel = $this->_pearChannel; - if (!is_a($pear_channel, 'PEAR_ChannelFile') || !$pear_channel->validate()) { - if (!class_exists('PEAR_ChannelFile')) { - require_once 'PEAR/ChannelFile.php'; - } - - $pear_channel = new PEAR_ChannelFile; - $pear_channel->setName('pear.php.net'); - $pear_channel->setAlias('pear'); - $pear_channel->setServer('pear.php.net'); - $pear_channel->setSummary('PHP Extension and Application Repository'); - $pear_channel->setDefaultPEARProtocols(); - $pear_channel->setBaseURL('REST1.0', 'http://pear.php.net/rest/'); - $pear_channel->setBaseURL('REST1.1', 'http://pear.php.net/rest/'); - } else { - $pear_channel->setName('pear.php.net'); - $pear_channel->setAlias('pear'); - } - - $pear_channel->validate(); - $this->_addChannel($pear_channel); - } - - if (!file_exists($this->channelsdir . $ds . 'pecl.php.net.reg')) { - $pecl_channel = $this->_peclChannel; - if (!is_a($pecl_channel, 'PEAR_ChannelFile') || !$pecl_channel->validate()) { - if (!class_exists('PEAR_ChannelFile')) { - require_once 'PEAR/ChannelFile.php'; - } - - $pecl_channel = new PEAR_ChannelFile; - $pecl_channel->setName('pecl.php.net'); - $pecl_channel->setAlias('pecl'); - $pecl_channel->setServer('pecl.php.net'); - $pecl_channel->setSummary('PHP Extension Community Library'); - $pecl_channel->setDefaultPEARProtocols(); - $pecl_channel->setBaseURL('REST1.0', 'http://pecl.php.net/rest/'); - $pecl_channel->setBaseURL('REST1.1', 'http://pecl.php.net/rest/'); - $pecl_channel->setValidationPackage('PEAR_Validator_PECL', '1.0'); - } else { - $pecl_channel->setName('pecl.php.net'); - $pecl_channel->setAlias('pecl'); - } - - $pecl_channel->validate(); - $this->_addChannel($pecl_channel); - } - - if (!file_exists($this->channelsdir . $ds . 'doc.php.net.reg')) { - $doc_channel = $this->_docChannel; - if (!is_a($doc_channel, 'PEAR_ChannelFile') || !$doc_channel->validate()) { - if (!class_exists('PEAR_ChannelFile')) { - require_once 'PEAR/ChannelFile.php'; - } - - $doc_channel = new PEAR_ChannelFile; - $doc_channel->setName('doc.php.net'); - $doc_channel->setAlias('phpdocs'); - $doc_channel->setServer('doc.php.net'); - $doc_channel->setSummary('PHP Documentation Team'); - $doc_channel->setDefaultPEARProtocols(); - $doc_channel->setBaseURL('REST1.0', 'http://doc.php.net/Chiara_PEAR_Server_REST/'); - $doc_channel->setBaseURL('REST1.1', 'http://doc.php.net/Chiara_PEAR_Server_REST/'); - } else { - $doc_channel->setName('doc.php.net'); - $doc_channel->setAlias('doc'); - } - - $doc_channel->validate(); - $this->_addChannel($doc_channel); - } - - if (!file_exists($this->channelsdir . $ds . '__uri.reg')) { - if (!class_exists('PEAR_ChannelFile')) { - require_once 'PEAR/ChannelFile.php'; - } - - $private = new PEAR_ChannelFile; - $private->setName('__uri'); - $private->setDefaultPEARProtocols(); - $private->setBaseURL('REST1.0', '****'); - $private->setSummary('Pseudo-channel for static packages'); - $this->_addChannel($private); - } - $this->_rebuildFileMap(); - } - - $running = false; - } - } - - function _initializeDirs() - { - $ds = DIRECTORY_SEPARATOR; - // XXX Compatibility code should be removed in the future - // rename all registry files if any to lowercase - if (!OS_WINDOWS && file_exists($this->statedir) && is_dir($this->statedir) && - $handle = opendir($this->statedir)) { - $dest = $this->statedir . $ds; - while (false !== ($file = readdir($handle))) { - if (preg_match('/^.*[A-Z].*\.reg\\z/', $file)) { - rename($dest . $file, $dest . strtolower($file)); - } - } - closedir($handle); - } - - $this->_initializeChannelDirs(); - if (!file_exists($this->filemap)) { - $this->_rebuildFileMap(); - } - $this->_initializeDepDB(); - } - - function _initializeDepDB() - { - if (!isset($this->_dependencyDB)) { - static $initializing = false; - if (!$initializing) { - $initializing = true; - if (!$this->_config) { // never used? - $file = OS_WINDOWS ? 'pear.ini' : '.pearrc'; - $this->_config = &new PEAR_Config($this->statedir . DIRECTORY_SEPARATOR . - $file); - $this->_config->setRegistry($this); - $this->_config->set('php_dir', $this->install_dir); - } - - $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->_config); - if (PEAR::isError($this->_dependencyDB)) { - // attempt to recover by removing the dep db - if (file_exists($this->_config->get('php_dir', null, 'pear.php.net') . - DIRECTORY_SEPARATOR . '.depdb')) { - @unlink($this->_config->get('php_dir', null, 'pear.php.net') . - DIRECTORY_SEPARATOR . '.depdb'); - } - - $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->_config); - if (PEAR::isError($this->_dependencyDB)) { - echo $this->_dependencyDB->getMessage(); - echo 'Unrecoverable error'; - exit(1); - } - } - - $initializing = false; - } - } - } - - /** - * PEAR_Registry destructor. Makes sure no locks are forgotten. - * - * @access private - */ - function _PEAR_Registry() - { - parent::_PEAR(); - if (is_resource($this->lock_fp)) { - $this->_unlock(); - } - } - - /** - * Make sure the directory where we keep registry files exists. - * - * @return bool TRUE if directory exists, FALSE if it could not be - * created - * - * @access private - */ - function _assertStateDir($channel = false) - { - if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') { - return $this->_assertChannelStateDir($channel); - } - - static $init = false; - if (!file_exists($this->statedir)) { - if (!$this->hasWriteAccess()) { - return false; - } - - require_once 'System.php'; - if (!System::mkdir(array('-p', $this->statedir))) { - return $this->raiseError("could not create directory '{$this->statedir}'"); - } - $init = true; - } elseif (!is_dir($this->statedir)) { - return $this->raiseError('Cannot create directory ' . $this->statedir . ', ' . - 'it already exists and is not a directory'); - } - - $ds = DIRECTORY_SEPARATOR; - if (!file_exists($this->channelsdir)) { - if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg') || - !file_exists($this->channelsdir . $ds . 'pecl.php.net.reg') || - !file_exists($this->channelsdir . $ds . 'doc.php.net.reg') || - !file_exists($this->channelsdir . $ds . '__uri.reg')) { - $init = true; - } - } elseif (!is_dir($this->channelsdir)) { - return $this->raiseError('Cannot create directory ' . $this->channelsdir . ', ' . - 'it already exists and is not a directory'); - } - - if ($init) { - static $running = false; - if (!$running) { - $running = true; - $this->_initializeDirs(); - $running = false; - $init = false; - } - } else { - $this->_initializeDepDB(); - } - - return true; - } - - /** - * Make sure the directory where we keep registry files exists for a non-standard channel. - * - * @param string channel name - * @return bool TRUE if directory exists, FALSE if it could not be - * created - * - * @access private - */ - function _assertChannelStateDir($channel) - { - $ds = DIRECTORY_SEPARATOR; - if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') { - if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) { - $this->_initializeChannelDirs(); - } - return $this->_assertStateDir($channel); - } - - $channelDir = $this->_channelDirectoryName($channel); - if (!is_dir($this->channelsdir) || - !file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) { - $this->_initializeChannelDirs(); - } - - if (!file_exists($channelDir)) { - if (!$this->hasWriteAccess()) { - return false; - } - - require_once 'System.php'; - if (!System::mkdir(array('-p', $channelDir))) { - return $this->raiseError("could not create directory '" . $channelDir . - "'"); - } - } elseif (!is_dir($channelDir)) { - return $this->raiseError("could not create directory '" . $channelDir . - "', already exists and is not a directory"); - } - - return true; - } - - /** - * Make sure the directory where we keep registry files for channels exists - * - * @return bool TRUE if directory exists, FALSE if it could not be - * created - * - * @access private - */ - function _assertChannelDir() - { - if (!file_exists($this->channelsdir)) { - if (!$this->hasWriteAccess()) { - return false; - } - - require_once 'System.php'; - if (!System::mkdir(array('-p', $this->channelsdir))) { - return $this->raiseError("could not create directory '{$this->channelsdir}'"); - } - } elseif (!is_dir($this->channelsdir)) { - return $this->raiseError("could not create directory '{$this->channelsdir}" . - "', it already exists and is not a directory"); - } - - if (!file_exists($this->channelsdir . DIRECTORY_SEPARATOR . '.alias')) { - if (!$this->hasWriteAccess()) { - return false; - } - - require_once 'System.php'; - if (!System::mkdir(array('-p', $this->channelsdir . DIRECTORY_SEPARATOR . '.alias'))) { - return $this->raiseError("could not create directory '{$this->channelsdir}/.alias'"); - } - } elseif (!is_dir($this->channelsdir . DIRECTORY_SEPARATOR . '.alias')) { - return $this->raiseError("could not create directory '{$this->channelsdir}" . - "/.alias', it already exists and is not a directory"); - } - - return true; - } - - /** - * Get the name of the file where data for a given package is stored. - * - * @param string channel name, or false if this is a PEAR package - * @param string package name - * - * @return string registry file name - * - * @access public - */ - function _packageFileName($package, $channel = false) - { - if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') { - return $this->_channelDirectoryName($channel) . DIRECTORY_SEPARATOR . - strtolower($package) . '.reg'; - } - - return $this->statedir . DIRECTORY_SEPARATOR . strtolower($package) . '.reg'; - } - - /** - * Get the name of the file where data for a given channel is stored. - * @param string channel name - * @return string registry file name - */ - function _channelFileName($channel, $noaliases = false) - { - if (!$noaliases) { - if (file_exists($this->_getChannelAliasFileName($channel))) { - $channel = implode('', file($this->_getChannelAliasFileName($channel))); - } - } - return $this->channelsdir . DIRECTORY_SEPARATOR . str_replace('/', '_', - strtolower($channel)) . '.reg'; - } - - /** - * @param string - * @return string - */ - function _getChannelAliasFileName($alias) - { - return $this->channelsdir . DIRECTORY_SEPARATOR . '.alias' . - DIRECTORY_SEPARATOR . str_replace('/', '_', strtolower($alias)) . '.txt'; - } - - /** - * Get the name of a channel from its alias - */ - function _getChannelFromAlias($channel) - { - if (!$this->_channelExists($channel)) { - if ($channel == 'pear.php.net') { - return 'pear.php.net'; - } - - if ($channel == 'pecl.php.net') { - return 'pecl.php.net'; - } - - if ($channel == 'doc.php.net') { - return 'doc.php.net'; - } - - if ($channel == '__uri') { - return '__uri'; - } - - return false; - } - - $channel = strtolower($channel); - if (file_exists($this->_getChannelAliasFileName($channel))) { - // translate an alias to an actual channel - return implode('', file($this->_getChannelAliasFileName($channel))); - } - - return $channel; - } - - /** - * Get the alias of a channel from its alias or its name - */ - function _getAlias($channel) - { - if (!$this->_channelExists($channel)) { - if ($channel == 'pear.php.net') { - return 'pear'; - } - - if ($channel == 'pecl.php.net') { - return 'pecl'; - } - - if ($channel == 'doc.php.net') { - return 'phpdocs'; - } - - return false; - } - - $channel = $this->_getChannel($channel); - if (PEAR::isError($channel)) { - return $channel; - } - - return $channel->getAlias(); - } - - /** - * Get the name of the file where data for a given package is stored. - * - * @param string channel name, or false if this is a PEAR package - * @param string package name - * - * @return string registry file name - * - * @access public - */ - function _channelDirectoryName($channel) - { - if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') { - return $this->statedir; - } - - $ch = $this->_getChannelFromAlias($channel); - if (!$ch) { - $ch = $channel; - } - - return $this->statedir . DIRECTORY_SEPARATOR . strtolower('.channel.' . - str_replace('/', '_', $ch)); - } - - function _openPackageFile($package, $mode, $channel = false) - { - if (!$this->_assertStateDir($channel)) { - return null; - } - - if (!in_array($mode, array('r', 'rb')) && !$this->hasWriteAccess()) { - return null; - } - - $file = $this->_packageFileName($package, $channel); - if (!file_exists($file) && $mode == 'r' || $mode == 'rb') { - return null; - } - - $fp = @fopen($file, $mode); - if (!$fp) { - return null; - } - - return $fp; - } - - function _closePackageFile($fp) - { - fclose($fp); - } - - function _openChannelFile($channel, $mode) - { - if (!$this->_assertChannelDir()) { - return null; - } - - if (!in_array($mode, array('r', 'rb')) && !$this->hasWriteAccess()) { - return null; - } - - $file = $this->_channelFileName($channel); - if (!file_exists($file) && $mode == 'r' || $mode == 'rb') { - return null; - } - - $fp = @fopen($file, $mode); - if (!$fp) { - return null; - } - - return $fp; - } - - function _closeChannelFile($fp) - { - fclose($fp); - } - - function _rebuildFileMap() - { - if (!class_exists('PEAR_Installer_Role')) { - require_once 'PEAR/Installer/Role.php'; - } - - $channels = $this->_listAllPackages(); - $files = array(); - foreach ($channels as $channel => $packages) { - foreach ($packages as $package) { - $version = $this->_packageInfo($package, 'version', $channel); - $filelist = $this->_packageInfo($package, 'filelist', $channel); - if (!is_array($filelist)) { - continue; - } - - foreach ($filelist as $name => $attrs) { - if (isset($attrs['attribs'])) { - $attrs = $attrs['attribs']; - } - - // it is possible for conflicting packages in different channels to - // conflict with data files/doc files - if ($name == 'dirtree') { - continue; - } - - if (isset($attrs['role']) && !in_array($attrs['role'], - PEAR_Installer_Role::getInstallableRoles())) { - // these are not installed - continue; - } - - if (isset($attrs['role']) && !in_array($attrs['role'], - PEAR_Installer_Role::getBaseinstallRoles())) { - $attrs['baseinstalldir'] = $package; - } - - if (isset($attrs['baseinstalldir'])) { - $file = $attrs['baseinstalldir'].DIRECTORY_SEPARATOR.$name; - } else { - $file = $name; - } - - $file = preg_replace(',^/+,', '', $file); - if ($channel != 'pear.php.net') { - if (!isset($files[$attrs['role']])) { - $files[$attrs['role']] = array(); - } - $files[$attrs['role']][$file] = array(strtolower($channel), - strtolower($package)); - } else { - if (!isset($files[$attrs['role']])) { - $files[$attrs['role']] = array(); - } - $files[$attrs['role']][$file] = strtolower($package); - } - } - } - } - - - $this->_assertStateDir(); - if (!$this->hasWriteAccess()) { - return false; - } - - $fp = @fopen($this->filemap, 'wb'); - if (!$fp) { - return false; - } - - $this->filemap_cache = $files; - fwrite($fp, serialize($files)); - fclose($fp); - return true; - } - - function _readFileMap() - { - if (!file_exists($this->filemap)) { - return array(); - } - - $fp = @fopen($this->filemap, 'r'); - if (!$fp) { - return $this->raiseError('PEAR_Registry: could not open filemap "' . $this->filemap . '"', PEAR_REGISTRY_ERROR_FILE, null, null, $php_errormsg); - } - - clearstatcache(); - $rt = get_magic_quotes_runtime(); - set_magic_quotes_runtime(0); - $fsize = filesize($this->filemap); - fclose($fp); - $data = file_get_contents($this->filemap); - set_magic_quotes_runtime($rt); - $tmp = unserialize($data); - if (!$tmp && $fsize > 7) { - return $this->raiseError('PEAR_Registry: invalid filemap data', PEAR_REGISTRY_ERROR_FORMAT, null, null, $data); - } - - $this->filemap_cache = $tmp; - return true; - } - - /** - * Lock the registry. - * - * @param integer lock mode, one of LOCK_EX, LOCK_SH or LOCK_UN. - * See flock manual for more information. - * - * @return bool TRUE on success, FALSE if locking failed, or a - * PEAR error if some other error occurs (such as the - * lock file not being writable). - * - * @access private - */ - function _lock($mode = LOCK_EX) - { - if (stristr(php_uname(), 'Windows 9')) { - return true; - } - - if ($mode != LOCK_UN && is_resource($this->lock_fp)) { - // XXX does not check type of lock (LOCK_SH/LOCK_EX) - return true; - } - - if (!$this->_assertStateDir()) { - if ($mode == LOCK_EX) { - return $this->raiseError('Registry directory is not writeable by the current user'); - } - - return true; - } - - $open_mode = 'w'; - // XXX People reported problems with LOCK_SH and 'w' - if ($mode === LOCK_SH || $mode === LOCK_UN) { - if (!file_exists($this->lockfile)) { - touch($this->lockfile); - } - $open_mode = 'r'; - } - - if (!is_resource($this->lock_fp)) { - $this->lock_fp = @fopen($this->lockfile, $open_mode); - } - - if (!is_resource($this->lock_fp)) { - $this->lock_fp = null; - return $this->raiseError("could not create lock file" . - (isset($php_errormsg) ? ": " . $php_errormsg : "")); - } - - if (!(int)flock($this->lock_fp, $mode)) { - switch ($mode) { - case LOCK_SH: $str = 'shared'; break; - case LOCK_EX: $str = 'exclusive'; break; - case LOCK_UN: $str = 'unlock'; break; - default: $str = 'unknown'; break; - } - - //is resource at this point, close it on error. - fclose($this->lock_fp); - $this->lock_fp = null; - return $this->raiseError("could not acquire $str lock ($this->lockfile)", - PEAR_REGISTRY_ERROR_LOCK); - } - - return true; - } - - function _unlock() - { - $ret = $this->_lock(LOCK_UN); - if (is_resource($this->lock_fp)) { - fclose($this->lock_fp); - } - - $this->lock_fp = null; - return $ret; - } - - function _packageExists($package, $channel = false) - { - return file_exists($this->_packageFileName($package, $channel)); - } - - /** - * Determine whether a channel exists in the registry - * @param string Channel name - * @param bool if true, then aliases will be ignored - * @return boolean - */ - function _channelExists($channel, $noaliases = false) - { - $a = file_exists($this->_channelFileName($channel, $noaliases)); - if (!$a && $channel == 'pear.php.net') { - return true; - } - - if (!$a && $channel == 'pecl.php.net') { - return true; - } - - if (!$a && $channel == 'doc.php.net') { - return true; - } - - return $a; - } - - /** - * @param PEAR_ChannelFile Channel object - * @param donotuse - * @param string Last-Modified HTTP tag from remote request - * @return boolean|PEAR_Error True on creation, false if it already exists - */ - function _addChannel($channel, $update = false, $lastmodified = false) - { - if (!is_a($channel, 'PEAR_ChannelFile')) { - return false; - } - - if (!$channel->validate()) { - return false; - } - - if (file_exists($this->_channelFileName($channel->getName()))) { - if (!$update) { - return false; - } - - $checker = $this->_getChannel($channel->getName()); - if (PEAR::isError($checker)) { - return $checker; - } - - if ($channel->getAlias() != $checker->getAlias()) { - if (file_exists($this->_getChannelAliasFileName($checker->getAlias()))) { - @unlink($this->_getChannelAliasFileName($checker->getAlias())); - } - } - } else { - if ($update && !in_array($channel->getName(), array('pear.php.net', 'pecl.php.net', 'doc.php.net'))) { - return false; - } - } - - $ret = $this->_assertChannelDir(); - if (PEAR::isError($ret)) { - return $ret; - } - - $ret = $this->_assertChannelStateDir($channel->getName()); - if (PEAR::isError($ret)) { - return $ret; - } - - if ($channel->getAlias() != $channel->getName()) { - if (file_exists($this->_getChannelAliasFileName($channel->getAlias())) && - $this->_getChannelFromAlias($channel->getAlias()) != $channel->getName()) { - $channel->setAlias($channel->getName()); - } - - if (!$this->hasWriteAccess()) { - return false; - } - - $fp = @fopen($this->_getChannelAliasFileName($channel->getAlias()), 'w'); - if (!$fp) { - return false; - } - - fwrite($fp, $channel->getName()); - fclose($fp); - } - - if (!$this->hasWriteAccess()) { - return false; - } - - $fp = @fopen($this->_channelFileName($channel->getName()), 'wb'); - if (!$fp) { - return false; - } - - $info = $channel->toArray(); - if ($lastmodified) { - $info['_lastmodified'] = $lastmodified; - } else { - $info['_lastmodified'] = date('r'); - } - - fwrite($fp, serialize($info)); - fclose($fp); - return true; - } - - /** - * Deletion fails if there are any packages installed from the channel - * @param string|PEAR_ChannelFile channel name - * @return boolean|PEAR_Error True on deletion, false if it doesn't exist - */ - function _deleteChannel($channel) - { - if (!is_string($channel)) { - if (!is_a($channel, 'PEAR_ChannelFile')) { - return false; - } - - if (!$channel->validate()) { - return false; - } - $channel = $channel->getName(); - } - - if ($this->_getChannelFromAlias($channel) == '__uri') { - return false; - } - - if ($this->_getChannelFromAlias($channel) == 'pecl.php.net') { - return false; - } - - if ($this->_getChannelFromAlias($channel) == 'doc.php.net') { - return false; - } - - if (!$this->_channelExists($channel)) { - return false; - } - - if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') { - return false; - } - - $channel = $this->_getChannelFromAlias($channel); - if ($channel == 'pear.php.net') { - return false; - } - - $test = $this->_listChannelPackages($channel); - if (count($test)) { - return false; - } - - $test = @rmdir($this->_channelDirectoryName($channel)); - if (!$test) { - return false; - } - - $file = $this->_getChannelAliasFileName($this->_getAlias($channel)); - if (file_exists($file)) { - $test = @unlink($file); - if (!$test) { - return false; - } - } - - $file = $this->_channelFileName($channel); - $ret = true; - if (file_exists($file)) { - $ret = @unlink($file); - } - - return $ret; - } - - /** - * Determine whether a channel exists in the registry - * @param string Channel Alias - * @return boolean - */ - function _isChannelAlias($alias) - { - return file_exists($this->_getChannelAliasFileName($alias)); - } - - /** - * @param string|null - * @param string|null - * @param string|null - * @return array|null - * @access private - */ - function _packageInfo($package = null, $key = null, $channel = 'pear.php.net') - { - if ($package === null) { - if ($channel === null) { - $channels = $this->_listChannels(); - $ret = array(); - foreach ($channels as $channel) { - $channel = strtolower($channel); - $ret[$channel] = array(); - $packages = $this->_listPackages($channel); - foreach ($packages as $package) { - $ret[$channel][] = $this->_packageInfo($package, null, $channel); - } - } - - return $ret; - } - - $ps = $this->_listPackages($channel); - if (!count($ps)) { - return array(); - } - return array_map(array(&$this, '_packageInfo'), - $ps, array_fill(0, count($ps), null), - array_fill(0, count($ps), $channel)); - } - - $fp = $this->_openPackageFile($package, 'r', $channel); - if ($fp === null) { - return null; - } - - $rt = get_magic_quotes_runtime(); - set_magic_quotes_runtime(0); - clearstatcache(); - $this->_closePackageFile($fp); - $data = file_get_contents($this->_packageFileName($package, $channel)); - set_magic_quotes_runtime($rt); - $data = unserialize($data); - if ($key === null) { - return $data; - } - - // compatibility for package.xml version 2.0 - if (isset($data['old'][$key])) { - return $data['old'][$key]; - } - - if (isset($data[$key])) { - return $data[$key]; - } - - return null; - } - - /** - * @param string Channel name - * @param bool whether to strictly retrieve info of channels, not just aliases - * @return array|null - */ - function _channelInfo($channel, $noaliases = false) - { - if (!$this->_channelExists($channel, $noaliases)) { - return null; - } - - $fp = $this->_openChannelFile($channel, 'r'); - if ($fp === null) { - return null; - } - - $rt = get_magic_quotes_runtime(); - set_magic_quotes_runtime(0); - clearstatcache(); - $this->_closeChannelFile($fp); - $data = file_get_contents($this->_channelFileName($channel)); - set_magic_quotes_runtime($rt); - $data = unserialize($data); - return $data; - } - - function _listChannels() - { - $channellist = array(); - if (!file_exists($this->channelsdir) || !is_dir($this->channelsdir)) { - return array('pear.php.net', 'pecl.php.net', 'doc.php.net', '__uri'); - } - - $dp = opendir($this->channelsdir); - while ($ent = readdir($dp)) { - if ($ent{0} == '.' || substr($ent, -4) != '.reg') { - continue; - } - - if ($ent == '__uri.reg') { - $channellist[] = '__uri'; - continue; - } - - $channellist[] = str_replace('_', '/', substr($ent, 0, -4)); - } - - closedir($dp); - if (!in_array('pear.php.net', $channellist)) { - $channellist[] = 'pear.php.net'; - } - - if (!in_array('pecl.php.net', $channellist)) { - $channellist[] = 'pecl.php.net'; - } - - if (!in_array('doc.php.net', $channellist)) { - $channellist[] = 'doc.php.net'; - } - - - if (!in_array('__uri', $channellist)) { - $channellist[] = '__uri'; - } - - natsort($channellist); - return $channellist; - } - - function _listPackages($channel = false) - { - if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') { - return $this->_listChannelPackages($channel); - } - - if (!file_exists($this->statedir) || !is_dir($this->statedir)) { - return array(); - } - - $pkglist = array(); - $dp = opendir($this->statedir); - if (!$dp) { - return $pkglist; - } - - while ($ent = readdir($dp)) { - if ($ent{0} == '.' || substr($ent, -4) != '.reg') { - continue; - } - - $pkglist[] = substr($ent, 0, -4); - } - closedir($dp); - return $pkglist; - } - - function _listChannelPackages($channel) - { - $pkglist = array(); - if (!file_exists($this->_channelDirectoryName($channel)) || - !is_dir($this->_channelDirectoryName($channel))) { - return array(); - } - - $dp = opendir($this->_channelDirectoryName($channel)); - if (!$dp) { - return $pkglist; - } - - while ($ent = readdir($dp)) { - if ($ent{0} == '.' || substr($ent, -4) != '.reg') { - continue; - } - $pkglist[] = substr($ent, 0, -4); - } - - closedir($dp); - return $pkglist; - } - - function _listAllPackages() - { - $ret = array(); - foreach ($this->_listChannels() as $channel) { - $ret[$channel] = $this->_listPackages($channel); - } - - return $ret; - } - - /** - * Add an installed package to the registry - * @param string package name - * @param array package info (parsed by PEAR_Common::infoFrom*() methods) - * @return bool success of saving - * @access private - */ - function _addPackage($package, $info) - { - if ($this->_packageExists($package)) { - return false; - } - - $fp = $this->_openPackageFile($package, 'wb'); - if ($fp === null) { - return false; - } - - $info['_lastmodified'] = time(); - fwrite($fp, serialize($info)); - $this->_closePackageFile($fp); - if (isset($info['filelist'])) { - $this->_rebuildFileMap(); - } - - return true; - } - - /** - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @return bool - * @access private - */ - function _addPackage2($info) - { - if (!is_a($info, 'PEAR_PackageFile_v1') && !is_a($info, 'PEAR_PackageFile_v2')) { - return false; - } - - if (!$info->validate()) { - if (class_exists('PEAR_Common')) { - $ui = PEAR_Frontend::singleton(); - if ($ui) { - foreach ($info->getValidationWarnings() as $err) { - $ui->log($err['message'], true); - } - } - } - return false; - } - - $channel = $info->getChannel(); - $package = $info->getPackage(); - $save = $info; - if ($this->_packageExists($package, $channel)) { - return false; - } - - if (!$this->_channelExists($channel, true)) { - return false; - } - - $info = $info->toArray(true); - if (!$info) { - return false; - } - - $fp = $this->_openPackageFile($package, 'wb', $channel); - if ($fp === null) { - return false; - } - - $info['_lastmodified'] = time(); - fwrite($fp, serialize($info)); - $this->_closePackageFile($fp); - $this->_rebuildFileMap(); - return true; - } - - /** - * @param string Package name - * @param array parsed package.xml 1.0 - * @param bool this parameter is only here for BC. Don't use it. - * @access private - */ - function _updatePackage($package, $info, $merge = true) - { - $oldinfo = $this->_packageInfo($package); - if (empty($oldinfo)) { - return false; - } - - $fp = $this->_openPackageFile($package, 'w'); - if ($fp === null) { - return false; - } - - if (is_object($info)) { - $info = $info->toArray(); - } - $info['_lastmodified'] = time(); - - $newinfo = $info; - if ($merge) { - $info = array_merge($oldinfo, $info); - } else { - $diff = $info; - } - - fwrite($fp, serialize($info)); - $this->_closePackageFile($fp); - if (isset($newinfo['filelist'])) { - $this->_rebuildFileMap(); - } - - return true; - } - - /** - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @return bool - * @access private - */ - function _updatePackage2($info) - { - if (!$this->_packageExists($info->getPackage(), $info->getChannel())) { - return false; - } - - $fp = $this->_openPackageFile($info->getPackage(), 'w', $info->getChannel()); - if ($fp === null) { - return false; - } - - $save = $info; - $info = $save->getArray(true); - $info['_lastmodified'] = time(); - fwrite($fp, serialize($info)); - $this->_closePackageFile($fp); - $this->_rebuildFileMap(); - return true; - } - - /** - * @param string Package name - * @param string Channel name - * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|null - * @access private - */ - function &_getPackage($package, $channel = 'pear.php.net') - { - $info = $this->_packageInfo($package, null, $channel); - if ($info === null) { - return $info; - } - - $a = $this->_config; - if (!$a) { - $this->_config = &new PEAR_Config; - $this->_config->set('php_dir', $this->statedir); - } - - if (!class_exists('PEAR_PackageFile')) { - require_once 'PEAR/PackageFile.php'; - } - - $pkg = &new PEAR_PackageFile($this->_config); - $pf = &$pkg->fromArray($info); - return $pf; - } - - /** - * @param string channel name - * @param bool whether to strictly retrieve channel names - * @return PEAR_ChannelFile|PEAR_Error - * @access private - */ - function &_getChannel($channel, $noaliases = false) - { - $ch = false; - if ($this->_channelExists($channel, $noaliases)) { - $chinfo = $this->_channelInfo($channel, $noaliases); - if ($chinfo) { - if (!class_exists('PEAR_ChannelFile')) { - require_once 'PEAR/ChannelFile.php'; - } - - $ch = &PEAR_ChannelFile::fromArrayWithErrors($chinfo); - } - } - - if ($ch) { - if ($ch->validate()) { - return $ch; - } - - foreach ($ch->getErrors(true) as $err) { - $message = $err['message'] . "\n"; - } - - $ch = PEAR::raiseError($message); - return $ch; - } - - if ($this->_getChannelFromAlias($channel) == 'pear.php.net') { - // the registry is not properly set up, so use defaults - if (!class_exists('PEAR_ChannelFile')) { - require_once 'PEAR/ChannelFile.php'; - } - - $pear_channel = new PEAR_ChannelFile; - $pear_channel->setName('pear.php.net'); - $pear_channel->setAlias('pear'); - $pear_channel->setSummary('PHP Extension and Application Repository'); - $pear_channel->setDefaultPEARProtocols(); - $pear_channel->setBaseURL('REST1.0', 'http://pear.php.net/rest/'); - $pear_channel->setBaseURL('REST1.1', 'http://pear.php.net/rest/'); - return $pear_channel; - } - - if ($this->_getChannelFromAlias($channel) == 'pecl.php.net') { - // the registry is not properly set up, so use defaults - if (!class_exists('PEAR_ChannelFile')) { - require_once 'PEAR/ChannelFile.php'; - } - $pear_channel = new PEAR_ChannelFile; - $pear_channel->setName('pecl.php.net'); - $pear_channel->setAlias('pecl'); - $pear_channel->setSummary('PHP Extension Community Library'); - $pear_channel->setDefaultPEARProtocols(); - $pear_channel->setBaseURL('REST1.0', 'http://pecl.php.net/rest/'); - $pear_channel->setBaseURL('REST1.1', 'http://pecl.php.net/rest/'); - $pear_channel->setValidationPackage('PEAR_Validator_PECL', '1.0'); - return $pear_channel; - } - - if ($this->_getChannelFromAlias($channel) == 'doc.php.net') { - // the registry is not properly set up, so use defaults - if (!class_exists('PEAR_ChannelFile')) { - require_once 'PEAR/ChannelFile.php'; - } - - $doc_channel = new PEAR_ChannelFile; - $doc_channel->setName('doc.php.net'); - $doc_channel->setAlias('phpdocs'); - $doc_channel->setSummary('PHP Documentation Team'); - $doc_channel->setDefaultPEARProtocols(); - $doc_channel->setBaseURL('REST1.0', 'http://doc.php.net/Chiara_PEAR_Server_REST/'); - $doc_channel->setBaseURL('REST1.1', 'http://doc.php.net/Chiara_PEAR_Server_REST/'); - return $doc_channel; - } - - - if ($this->_getChannelFromAlias($channel) == '__uri') { - // the registry is not properly set up, so use defaults - if (!class_exists('PEAR_ChannelFile')) { - require_once 'PEAR/ChannelFile.php'; - } - - $private = new PEAR_ChannelFile; - $private->setName('__uri'); - $private->setDefaultPEARProtocols(); - $private->setBaseURL('REST1.0', '****'); - $private->setSummary('Pseudo-channel for static packages'); - return $private; - } - - return $ch; - } - - /** - * @param string Package name - * @param string Channel name - * @return bool - */ - function packageExists($package, $channel = 'pear.php.net') - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_packageExists($package, $channel); - $this->_unlock(); - return $ret; - } - - // }}} - - // {{{ channelExists() - - /** - * @param string channel name - * @param bool if true, then aliases will be ignored - * @return bool - */ - function channelExists($channel, $noaliases = false) - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_channelExists($channel, $noaliases); - $this->_unlock(); - return $ret; - } - - // }}} - - // {{{ isAlias() - - /** - * Determines whether the parameter is an alias of a channel - * @param string - * @return bool - */ - function isAlias($alias) - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_isChannelAlias($alias); - $this->_unlock(); - return $ret; - } - - // }}} - // {{{ packageInfo() - - /** - * @param string|null - * @param string|null - * @param string - * @return array|null - */ - function packageInfo($package = null, $key = null, $channel = 'pear.php.net') - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_packageInfo($package, $key, $channel); - $this->_unlock(); - return $ret; - } - - // }}} - // {{{ channelInfo() - - /** - * Retrieve a raw array of channel data. - * - * Do not use this, instead use {@link getChannel()} for normal - * operations. Array structure is undefined in this method - * @param string channel name - * @param bool whether to strictly retrieve information only on non-aliases - * @return array|null|PEAR_Error - */ - function channelInfo($channel = null, $noaliases = false) - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_channelInfo($channel, $noaliases); - $this->_unlock(); - return $ret; - } - - // }}} - - /** - * @param string - */ - function channelName($channel) - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_getChannelFromAlias($channel); - $this->_unlock(); - return $ret; - } - - /** - * @param string - */ - function channelAlias($channel) - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_getAlias($channel); - $this->_unlock(); - return $ret; - } - // {{{ listPackages() - - function listPackages($channel = false) - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_listPackages($channel); - $this->_unlock(); - return $ret; - } - - // }}} - // {{{ listAllPackages() - - function listAllPackages() - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_listAllPackages(); - $this->_unlock(); - return $ret; - } - - // }}} - // {{{ listChannel() - - function listChannels() - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_listChannels(); - $this->_unlock(); - return $ret; - } - - // }}} - // {{{ addPackage() - - /** - * Add an installed package to the registry - * @param string|PEAR_PackageFile_v1|PEAR_PackageFile_v2 package name or object - * that will be passed to {@link addPackage2()} - * @param array package info (parsed by PEAR_Common::infoFrom*() methods) - * @return bool success of saving - */ - function addPackage($package, $info) - { - if (is_object($info)) { - return $this->addPackage2($info); - } - if (PEAR::isError($e = $this->_lock(LOCK_EX))) { - return $e; - } - $ret = $this->_addPackage($package, $info); - $this->_unlock(); - if ($ret) { - if (!class_exists('PEAR_PackageFile_v1')) { - require_once 'PEAR/PackageFile/v1.php'; - } - $pf = new PEAR_PackageFile_v1; - $pf->setConfig($this->_config); - $pf->fromArray($info); - $this->_dependencyDB->uninstallPackage($pf); - $this->_dependencyDB->installPackage($pf); - } - return $ret; - } - - // }}} - // {{{ addPackage2() - - function addPackage2($info) - { - if (!is_object($info)) { - return $this->addPackage($info['package'], $info); - } - if (PEAR::isError($e = $this->_lock(LOCK_EX))) { - return $e; - } - $ret = $this->_addPackage2($info); - $this->_unlock(); - if ($ret) { - $this->_dependencyDB->uninstallPackage($info); - $this->_dependencyDB->installPackage($info); - } - return $ret; - } - - // }}} - // {{{ updateChannel() - - /** - * For future expandibility purposes, separate this - * @param PEAR_ChannelFile - */ - function updateChannel($channel, $lastmodified = null) - { - if ($channel->getName() == '__uri') { - return false; - } - return $this->addChannel($channel, $lastmodified, true); - } - - // }}} - // {{{ deleteChannel() - - /** - * Deletion fails if there are any packages installed from the channel - * @param string|PEAR_ChannelFile channel name - * @return boolean|PEAR_Error True on deletion, false if it doesn't exist - */ - function deleteChannel($channel) - { - if (PEAR::isError($e = $this->_lock(LOCK_EX))) { - return $e; - } - $ret = $this->_deleteChannel($channel); - $this->_unlock(); - if ($ret && is_a($this->_config, 'PEAR_Config')) { - $this->_config->setChannels($this->listChannels()); - } - return $ret; - } - - // }}} - // {{{ addChannel() - - /** - * @param PEAR_ChannelFile Channel object - * @param string Last-Modified header from HTTP for caching - * @return boolean|PEAR_Error True on creation, false if it already exists - */ - function addChannel($channel, $lastmodified = false, $update = false) - { - if (!is_a($channel, 'PEAR_ChannelFile')) { - return false; - } - if (!$channel->validate()) { - return false; - } - if (PEAR::isError($e = $this->_lock(LOCK_EX))) { - return $e; - } - $ret = $this->_addChannel($channel, $update, $lastmodified); - $this->_unlock(); - if (!$update && $ret && is_a($this->_config, 'PEAR_Config')) { - $this->_config->setChannels($this->listChannels()); - } - return $ret; - } - - // }}} - // {{{ deletePackage() - - function deletePackage($package, $channel = 'pear.php.net') - { - if (PEAR::isError($e = $this->_lock(LOCK_EX))) { - return $e; - } - $file = $this->_packageFileName($package, $channel); - if (file_exists($file)) { - $ret = @unlink($file); - } else { - $ret = false; - } - $this->_rebuildFileMap(); - $this->_unlock(); - $p = array('channel' => $channel, 'package' => $package); - $this->_dependencyDB->uninstallPackage($p); - return $ret; - } - - // }}} - // {{{ updatePackage() - - function updatePackage($package, $info, $merge = true) - { - if (is_object($info)) { - return $this->updatePackage2($info, $merge); - } - if (PEAR::isError($e = $this->_lock(LOCK_EX))) { - return $e; - } - $ret = $this->_updatePackage($package, $info, $merge); - $this->_unlock(); - if ($ret) { - if (!class_exists('PEAR_PackageFile_v1')) { - require_once 'PEAR/PackageFile/v1.php'; - } - $pf = new PEAR_PackageFile_v1; - $pf->setConfig($this->_config); - $pf->fromArray($this->packageInfo($package)); - $this->_dependencyDB->uninstallPackage($pf); - $this->_dependencyDB->installPackage($pf); - } - return $ret; - } - - // }}} - // {{{ updatePackage2() - - function updatePackage2($info) - { - - if (!is_object($info)) { - return $this->updatePackage($info['package'], $info, $merge); - } - - if (!$info->validate(PEAR_VALIDATE_DOWNLOADING)) { - return false; - } - - if (PEAR::isError($e = $this->_lock(LOCK_EX))) { - return $e; - } - - $ret = $this->_updatePackage2($info); - $this->_unlock(); - if ($ret) { - $this->_dependencyDB->uninstallPackage($info); - $this->_dependencyDB->installPackage($info); - } - - return $ret; - } - - // }}} - // {{{ getChannel() - /** - * @param string channel name - * @param bool whether to strictly return raw channels (no aliases) - * @return PEAR_ChannelFile|PEAR_Error - */ - function &getChannel($channel, $noaliases = false) - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = &$this->_getChannel($channel, $noaliases); - $this->_unlock(); - if (!$ret) { - return PEAR::raiseError('Unknown channel: ' . $channel); - } - return $ret; - } - - // }}} - // {{{ getPackage() - /** - * @param string package name - * @param string channel name - * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|null - */ - function &getPackage($package, $channel = 'pear.php.net') - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $pf = &$this->_getPackage($package, $channel); - $this->_unlock(); - return $pf; - } - - // }}} - - /** - * Get PEAR_PackageFile_v[1/2] objects representing the contents of - * a dependency group that are installed. - * - * This is used at uninstall-time - * @param array - * @return array|false - */ - function getInstalledGroup($group) - { - $ret = array(); - if (isset($group['package'])) { - if (!isset($group['package'][0])) { - $group['package'] = array($group['package']); - } - foreach ($group['package'] as $package) { - $depchannel = isset($package['channel']) ? $package['channel'] : '__uri'; - $p = &$this->getPackage($package['name'], $depchannel); - if ($p) { - $save = &$p; - $ret[] = &$save; - } - } - } - if (isset($group['subpackage'])) { - if (!isset($group['subpackage'][0])) { - $group['subpackage'] = array($group['subpackage']); - } - foreach ($group['subpackage'] as $package) { - $depchannel = isset($package['channel']) ? $package['channel'] : '__uri'; - $p = &$this->getPackage($package['name'], $depchannel); - if ($p) { - $save = &$p; - $ret[] = &$save; - } - } - } - if (!count($ret)) { - return false; - } - return $ret; - } - - // {{{ getChannelValidator() - /** - * @param string channel name - * @return PEAR_Validate|false - */ - function &getChannelValidator($channel) - { - $chan = $this->getChannel($channel); - if (PEAR::isError($chan)) { - return $chan; - } - $val = $chan->getValidationObject(); - return $val; - } - // }}} - // {{{ getChannels() - /** - * @param string channel name - * @return array an array of PEAR_ChannelFile objects representing every installed channel - */ - function &getChannels() - { - $ret = array(); - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - foreach ($this->_listChannels() as $channel) { - $e = &$this->_getChannel($channel); - if (!$e || PEAR::isError($e)) { - continue; - } - $ret[] = $e; - } - $this->_unlock(); - return $ret; - } - - // }}} - // {{{ checkFileMap() - - /** - * Test whether a file or set of files belongs to a package. - * - * If an array is passed in - * @param string|array file path, absolute or relative to the pear - * install dir - * @param string|array name of PEAR package or array('package' => name, 'channel' => - * channel) of a package that will be ignored - * @param string API version - 1.1 will exclude any files belonging to a package - * @param array private recursion variable - * @return array|false which package and channel the file belongs to, or an empty - * string if the file does not belong to an installed package, - * or belongs to the second parameter's package - */ - function checkFileMap($path, $package = false, $api = '1.0', $attrs = false) - { - if (is_array($path)) { - static $notempty; - if (empty($notempty)) { - if (!class_exists('PEAR_Installer_Role')) { - require_once 'PEAR/Installer/Role.php'; - } - $notempty = create_function('$a','return !empty($a);'); - } - $package = is_array($package) ? array(strtolower($package[0]), strtolower($package[1])) - : strtolower($package); - $pkgs = array(); - foreach ($path as $name => $attrs) { - if (is_array($attrs)) { - if (isset($attrs['install-as'])) { - $name = $attrs['install-as']; - } - if (!in_array($attrs['role'], PEAR_Installer_Role::getInstallableRoles())) { - // these are not installed - continue; - } - if (!in_array($attrs['role'], PEAR_Installer_Role::getBaseinstallRoles())) { - $attrs['baseinstalldir'] = is_array($package) ? $package[1] : $package; - } - if (isset($attrs['baseinstalldir'])) { - $name = $attrs['baseinstalldir'] . DIRECTORY_SEPARATOR . $name; - } - } - $pkgs[$name] = $this->checkFileMap($name, $package, $api, $attrs); - if (PEAR::isError($pkgs[$name])) { - return $pkgs[$name]; - } - } - return array_filter($pkgs, $notempty); - } - if (empty($this->filemap_cache)) { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $err = $this->_readFileMap(); - $this->_unlock(); - if (PEAR::isError($err)) { - return $err; - } - } - if (!$attrs) { - $attrs = array('role' => 'php'); // any old call would be for PHP role only - } - if (isset($this->filemap_cache[$attrs['role']][$path])) { - if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path] == $package) { - return false; - } - return $this->filemap_cache[$attrs['role']][$path]; - } - $l = strlen($this->install_dir); - if (substr($path, 0, $l) == $this->install_dir) { - $path = preg_replace('!^'.DIRECTORY_SEPARATOR.'+!', '', substr($path, $l)); - } - if (isset($this->filemap_cache[$attrs['role']][$path])) { - if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path] == $package) { - return false; - } - return $this->filemap_cache[$attrs['role']][$path]; - } - return false; - } - - // }}} - // {{{ flush() - /** - * Force a reload of the filemap - * @since 1.5.0RC3 - */ - function flushFileMap() - { - $this->filemap_cache = null; - clearstatcache(); // ensure that the next read gets the full, current filemap - } - - // }}} - // {{{ apiVersion() - /** - * Get the expected API version. Channels API is version 1.1, as it is backwards - * compatible with 1.0 - * @return string - */ - function apiVersion() - { - return '1.1'; - } - // }}} - - - /** - * Parse a package name, or validate a parsed package name array - * @param string|array pass in an array of format - * array( - * 'package' => 'pname', - * ['channel' => 'channame',] - * ['version' => 'version',] - * ['state' => 'state',] - * ['group' => 'groupname']) - * or a string of format - * [channel://][channame/]pname[-version|-state][/group=groupname] - * @return array|PEAR_Error - */ - function parsePackageName($param, $defaultchannel = 'pear.php.net') - { - $saveparam = $param; - if (is_array($param)) { - // convert to string for error messages - $saveparam = $this->parsedPackageNameToString($param); - // process the array - if (!isset($param['package'])) { - return PEAR::raiseError('parsePackageName(): array $param ' . - 'must contain a valid package name in index "param"', - 'package', null, null, $param); - } - if (!isset($param['uri'])) { - if (!isset($param['channel'])) { - $param['channel'] = $defaultchannel; - } - } else { - $param['channel'] = '__uri'; - } - } else { - $components = @parse_url((string) $param); - if (isset($components['scheme'])) { - if ($components['scheme'] == 'http') { - // uri package - $param = array('uri' => $param, 'channel' => '__uri'); - } elseif($components['scheme'] != 'channel') { - return PEAR::raiseError('parsePackageName(): only channel:// uris may ' . - 'be downloaded, not "' . $param . '"', 'invalid', null, null, $param); - } - } - if (!isset($components['path'])) { - return PEAR::raiseError('parsePackageName(): array $param ' . - 'must contain a valid package name in "' . $param . '"', - 'package', null, null, $param); - } - if (isset($components['host'])) { - // remove the leading "/" - $components['path'] = substr($components['path'], 1); - } - if (!isset($components['scheme'])) { - if (strpos($components['path'], '/') !== false) { - if ($components['path']{0} == '/') { - return PEAR::raiseError('parsePackageName(): this is not ' . - 'a package name, it begins with "/" in "' . $param . '"', - 'invalid', null, null, $param); - } - $parts = explode('/', $components['path']); - $components['host'] = array_shift($parts); - if (count($parts) > 1) { - $components['path'] = array_pop($parts); - $components['host'] .= '/' . implode('/', $parts); - } else { - $components['path'] = implode('/', $parts); - } - } else { - $components['host'] = $defaultchannel; - } - } else { - if (strpos($components['path'], '/')) { - $parts = explode('/', $components['path']); - $components['path'] = array_pop($parts); - $components['host'] .= '/' . implode('/', $parts); - } - } - - if (is_array($param)) { - $param['package'] = $components['path']; - } else { - $param = array( - 'package' => $components['path'] - ); - if (isset($components['host'])) { - $param['channel'] = $components['host']; - } - } - if (isset($components['fragment'])) { - $param['group'] = $components['fragment']; - } - if (isset($components['user'])) { - $param['user'] = $components['user']; - } - if (isset($components['pass'])) { - $param['pass'] = $components['pass']; - } - if (isset($components['query'])) { - parse_str($components['query'], $param['opts']); - } - // check for extension - $pathinfo = pathinfo($param['package']); - if (isset($pathinfo['extension']) && - in_array(strtolower($pathinfo['extension']), array('tgz', 'tar'))) { - $param['extension'] = $pathinfo['extension']; - $param['package'] = substr($pathinfo['basename'], 0, - strlen($pathinfo['basename']) - 4); - } - // check for version - if (strpos($param['package'], '-')) { - $test = explode('-', $param['package']); - if (count($test) != 2) { - return PEAR::raiseError('parsePackageName(): only one version/state ' . - 'delimiter "-" is allowed in "' . $saveparam . '"', - 'version', null, null, $param); - } - list($param['package'], $param['version']) = $test; - } - } - // validation - $info = $this->channelExists($param['channel']); - if (PEAR::isError($info)) { - return $info; - } - if (!$info) { - return PEAR::raiseError('unknown channel "' . $param['channel'] . - '" in "' . $saveparam . '"', 'channel', null, null, $param); - } - $chan = $this->getChannel($param['channel']); - if (PEAR::isError($chan)) { - return $chan; - } - if (!$chan) { - return PEAR::raiseError("Exception: corrupt registry, could not " . - "retrieve channel " . $param['channel'] . " information", - 'registry', null, null, $param); - } - $param['channel'] = $chan->getName(); - $validate = $chan->getValidationObject(); - $vpackage = $chan->getValidationPackage(); - // validate package name - if (!$validate->validPackageName($param['package'], $vpackage['_content'])) { - return PEAR::raiseError('parsePackageName(): invalid package name "' . - $param['package'] . '" in "' . $saveparam . '"', - 'package', null, null, $param); - } - if (isset($param['group'])) { - if (!PEAR_Validate::validGroupName($param['group'])) { - return PEAR::raiseError('parsePackageName(): dependency group "' . $param['group'] . - '" is not a valid group name in "' . $saveparam . '"', 'group', null, null, - $param); - } - } - if (isset($param['state'])) { - if (!in_array(strtolower($param['state']), $validate->getValidStates())) { - return PEAR::raiseError('parsePackageName(): state "' . $param['state'] - . '" is not a valid state in "' . $saveparam . '"', - 'state', null, null, $param); - } - } - if (isset($param['version'])) { - if (isset($param['state'])) { - return PEAR::raiseError('parsePackageName(): cannot contain both ' . - 'a version and a stability (state) in "' . $saveparam . '"', - 'version/state', null, null, $param); - } - // check whether version is actually a state - if (in_array(strtolower($param['version']), $validate->getValidStates())) { - $param['state'] = strtolower($param['version']); - unset($param['version']); - } else { - if (!$validate->validVersion($param['version'])) { - return PEAR::raiseError('parsePackageName(): "' . $param['version'] . - '" is neither a valid version nor a valid state in "' . - $saveparam . '"', 'version/state', null, null, $param); - } - } - } - return $param; - } - - /** - * @param array - * @return string - */ - function parsedPackageNameToString($parsed, $brief = false) - { - if (is_string($parsed)) { - return $parsed; - } - if (is_object($parsed)) { - $p = $parsed; - $parsed = array( - 'package' => $p->getPackage(), - 'channel' => $p->getChannel(), - 'version' => $p->getVersion(), - ); - } - if (isset($parsed['uri'])) { - return $parsed['uri']; - } - if ($brief) { - if ($channel = $this->channelAlias($parsed['channel'])) { - return $channel . '/' . $parsed['package']; - } - } - $upass = ''; - if (isset($parsed['user'])) { - $upass = $parsed['user']; - if (isset($parsed['pass'])) { - $upass .= ':' . $parsed['pass']; - } - $upass = "$upass@"; - } - $ret = 'channel://' . $upass . $parsed['channel'] . '/' . $parsed['package']; - if (isset($parsed['version']) || isset($parsed['state'])) { - $ver = isset($parsed['version']) ? $parsed['version'] : ''; - $ver .= isset($parsed['state']) ? $parsed['state'] : ''; - $ret .= '-' . $ver; - } - if (isset($parsed['extension'])) { - $ret .= '.' . $parsed['extension']; - } - if (isset($parsed['opts'])) { - $ret .= '?'; - foreach ($parsed['opts'] as $name => $value) { - $parsed['opts'][$name] = "$name=$value"; - } - $ret .= implode('&', $parsed['opts']); - } - if (isset($parsed['group'])) { - $ret .= '#' . $parsed['group']; - } - return $ret; - } -}PEAR-1.8.0/PEAR/REST.php100664 764 764 36152 100664 7351 - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: REST.php,v 1.40 2009/03/26 23:12:46 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * For downloading xml files - */ -require_once 'PEAR.php'; -require_once 'PEAR/XMLParser.php'; - -/** - * Intelligently retrieve data, following hyperlinks if necessary, and re-directing - * as well - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_REST -{ - var $config; - var $_options; - - function PEAR_REST(&$config, $options = array()) - { - $this->config = &$config; - $this->_options = $options; } /** - * Retrieve REST data, but always retrieve the local cache if it is available. - * - * This is useful for elements that should never change, such as information on a particular - * release - * @param string full URL to this resource - * @param array|false contents of the accept-encoding header - * @param boolean if true, xml will be returned as a string, otherwise, xml will be - * parsed using PEAR_XMLParser - * @return string|array + * Retrieve the directory that downloads will happen in + * @access private + * @return string */ - function retrieveCacheFirst($url, $accept = false, $forcestring = false, $channel = false) + function getDownloadDir() { - - $cachefile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . - md5($url) . 'rest.cachefile'; - - if (file_exists($cachefile)) { - return unserialize(implode('', file($cachefile))); - } - - return $this->retrieveData($url, $accept, $forcestring, $channel); - } - - /** - * Retrieve a remote REST resource - * @param string full URL to this resource - * @param array|false contents of the accept-encoding header - * @param boolean if true, xml will be returned as a string, otherwise, xml will be - * parsed using PEAR_XMLParser - * @return string|array - */ - function retrieveData($url, $accept = false, $forcestring = false, $channel = false) - { - $cacheId = $this->getCacheId($url); - if ($ret = $this->useLocalCache($url, $cacheId)) { - return $ret; - } - - $file = $trieddownload = false; - if (!isset($this->_options['offline'])) { - $trieddownload = true; - $file = $this->downloadHttp($url, $cacheId ? $cacheId['lastChange'] : false, $accept, $channel); + if (isset($this->_downloadDir)) { + return $this->_downloadDir; } - - if (PEAR::isError($file)) { - if ($file->getCode() !== -9276) { - return $file; + $downloaddir = $this->config->get('download_dir'); + if (empty($downloaddir) || (is_dir($downloaddir) && !is_writable($downloaddir))) { + if (is_dir($downloaddir) && !is_writable($downloaddir)) { + $this->log(0, 'WARNING: configuration download directory "' . $downloaddir . + '" is not writeable. Change download_dir config variable to ' . + 'a writeable dir to avoid this warning'); } - - $trieddownload = false; - $file = false; // use local copy if available on socket connect error - } - - if (!$file) { - $ret = $this->getCache($url); - if (!PEAR::isError($ret) && $trieddownload) { - // reset the age of the cache if the server says it was unmodified - $this->saveCache($url, $ret, null, true, $cacheId); + if (!class_exists('System')) { + require_once 'System.php'; } - - return $ret; - } - - if (is_array($file)) { - $headers = $file[2]; - $lastmodified = $file[1]; - $content = $file[0]; - } else { - $headers = array(); - $lastmodified = false; - $content = $file; - } - - if ($forcestring) { - $this->saveCache($url, $content, $lastmodified, false, $cacheId); - return $content; + if (PEAR::isError($downloaddir = System::mktemp('-d'))) { + return $downloaddir; + } + $this->log(3, '+ tmp dir created at ' . $downloaddir); } - - if (isset($headers['content-type'])) { - switch ($headers['content-type']) { - case 'text/xml' : - case 'application/xml' : - case 'text/plain' : - if ($headers['content-type'] === 'text/plain') { - $check = substr($content, 0, 5); - if ($check !== 'parse($content); - PEAR::popErrorHandling(); - if (PEAR::isError($err)) { - return PEAR::raiseError('Invalid xml downloaded from "' . $url . '": ' . - $err->getMessage()); - } - $content = $parser->getData(); - case 'text/html' : - default : - // use it as a string + if (!is_writable($downloaddir)) { + if (PEAR::isError(System::mkdir(array('-p', $downloaddir))) || + !is_writable($downloaddir)) { + return PEAR::raiseError('download directory "' . $downloaddir . + '" is not writeable. Change download_dir config variable to ' . + 'a writeable dir'); } - } else { - // assume XML - $parser = new PEAR_XMLParser; - $parser->parse($content); - $content = $parser->getData(); } - - $this->saveCache($url, $content, $lastmodified, false, $cacheId); - return $content; + return $this->_downloadDir = $downloaddir; } - function useLocalCache($url, $cacheid = null) + function setDownloadDir($dir) { - if ($cacheid === null) { - $cacheidfile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . - md5($url) . 'rest.cacheid'; - if (!file_exists($cacheidfile)) { - return false; + if (!@is_writable($dir)) { + if (PEAR::isError(System::mkdir(array('-p', $dir)))) { + return PEAR::raiseError('download directory "' . $dir . + '" is not writeable. Change download_dir config variable to ' . + 'a writeable dir'); } - - $cacheid = unserialize(implode('', file($cacheidfile))); - } - - $cachettl = $this->config->get('cache_ttl'); - // If cache is newer than $cachettl seconds, we use the cache! - if (time() - $cacheid['age'] < $cachettl) { - return $this->getCache($url); } - - return false; + $this->_downloadDir = $dir; } - function getCacheId($url) + function configSet($key, $value, $layer = 'user', $channel = false) { - $cacheidfile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . - md5($url) . 'rest.cacheid'; - - if (!file_exists($cacheidfile)) { - return false; + $this->config->set($key, $value, $layer, $channel); + $this->_preferredState = $this->config->get('preferred_state', null, $channel); + if (!$this->_preferredState) { + // don't inadvertantly use a non-set preferred_state + $this->_preferredState = null; } + } - $ret = unserialize(implode('', file($cacheidfile))); - return $ret; + function setOptions($options) + { + $this->_options = $options; } - function getCache($url) + // }}} + // {{{ setOptions() + function getOptions() { - $cachefile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . - md5($url) . 'rest.cachefile'; + return $this->_options; + } - if (!file_exists($cachefile)) { - return PEAR::raiseError('No cached content available for "' . $url . '"'); + /** + * For simpler unit-testing + * @param PEAR_Config + * @param int + * @param string + */ + function &getPackagefileObject(&$c, $d, $t = false) + { + if (!class_exists('PEAR_PackageFile')) { + require_once 'PEAR/PackageFile.php'; } - - return unserialize(implode('', file($cachefile))); + $a = &new PEAR_PackageFile($c, $d, $t); + return $a; } /** - * @param string full URL to REST resource - * @param string original contents of the REST resource - * @param array HTTP Last-Modified and ETag headers - * @param bool if true, then the cache id file should be regenerated to - * trigger a new time-to-live value + * @param array output of {@link parsePackageName()} + * @access private */ - function saveCache($url, $contents, $lastmodified, $nochange = false, $cacheid = null) + function _getPackageDownloadUrl($parr) { - $cacheidfile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . - md5($url) . 'rest.cacheid'; - - $cachefile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . - md5($url) . 'rest.cachefile'; + $curchannel = $this->config->get('default_channel'); + $this->configSet('default_channel', $parr['channel']); + // getDownloadURL returns an array. On error, it only contains information + // on the latest release as array(version, info). On success it contains + // array(version, info, download url string) + $state = isset($parr['state']) ? $parr['state'] : $this->config->get('preferred_state'); + if (!$this->_registry->channelExists($parr['channel'])) { + do { + if ($this->config->get('auto_discover') && $this->discover($parr['channel'])) { + break; + } - if ($cacheid === null && $nochange) { - $cacheid = unserialize(implode('', file($cacheidfile))); + $this->configSet('default_channel', $curchannel); + return PEAR::raiseError('Unknown remote channel: ' . $parr['channel']); + } while (false); } - $fp = @fopen($cacheidfile, 'wb'); - if (!$fp) { - $cache_dir = $this->config->get('cache_dir'); - if (is_dir($cache_dir)) { - return false; - } - - System::mkdir(array('-p', $cache_dir)); - $fp = @fopen($cacheidfile, 'wb'); - if (!$fp) { - return false; - } + $chan = &$this->_registry->getChannel($parr['channel']); + if (PEAR::isError($chan)) { + return $chan; } - if ($nochange) { - fwrite($fp, serialize(array( - 'age' => time(), - 'lastChange' => $cacheid['lastChange'], - )) - ); - - fclose($fp); - return true; + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $version = $this->_registry->packageInfo($parr['package'], 'version', $parr['channel']); + $stability = $this->_registry->packageInfo($parr['package'], 'stability', $parr['channel']); + // package is installed - use the installed release stability level + if (!isset($parr['state']) && $stability !== null) { + $state = $stability['release']; } + PEAR::staticPopErrorHandling(); + $base2 = false; - fwrite($fp, serialize(array( - 'age' => time(), - 'lastChange' => $lastmodified, - )) - ); - - fclose($fp); - $fp = @fopen($cachefile, 'wb'); - if (!$fp) { - if (file_exists($cacheidfile)) { - @unlink($cacheidfile); - } - - return false; + $preferred_mirror = $this->config->get('preferred_mirror'); + if (!$chan->supportsREST($preferred_mirror) || + ( + !($base2 = $chan->getBaseURL('REST1.3', $preferred_mirror)) + && + !($base = $chan->getBaseURL('REST1.0', $preferred_mirror)) + ) + ) { + return $this->raiseError($parr['channel'] . ' is using a unsupported protocol - This should never happen.'); } - fwrite($fp, serialize($contents)); - fclose($fp); - return true; - } - - /** - * Efficiently Download a file through HTTP. Returns downloaded file as a string in-memory - * This is best used for small files - * - * If an HTTP proxy has been configured (http_proxy PEAR_Config - * setting), the proxy will be used. - * - * @param string $url the URL to download - * @param string $save_dir directory to save file in - * @param false|string|array $lastmodified header values to check against for caching - * use false to return the header values from this download - * @param false|array $accept Accept headers to send - * @return string|array Returns the contents of the downloaded file or a PEAR - * error on failure. If the error is caused by - * socket-related errors, the error object will - * have the fsockopen error code available through - * getCode(). If caching is requested, then return the header - * values. - * - * @access public - */ - function downloadHttp($url, $lastmodified = null, $accept = false, $channel = false) - { - static $redirect = 0; - // always reset , so we are clean case of error - $wasredirect = $redirect; - $redirect = 0; - - $info = parse_url($url); - if (!isset($info['scheme']) || !in_array($info['scheme'], array('http', 'https'))) { - return PEAR::raiseError('Cannot download non-http URL "' . $url . '"'); + if ($base2) { + $rest = &$this->config->getREST('1.3', $this->_options); + $base = $base2; + } else { + $rest = &$this->config->getREST('1.0', $this->_options); } - if (!isset($info['host'])) { - return PEAR::raiseError('Cannot download from non-URL "' . $url . '"'); + $downloadVersion = false; + if (!isset($parr['version']) && !isset($parr['state']) && $version + && !PEAR::isError($version) + && !isset($this->_options['downloadonly']) + ) { + $downloadVersion = $version; } - $host = isset($info['host']) ? $info['host'] : null; - $port = isset($info['port']) ? $info['port'] : null; - $path = isset($info['path']) ? $info['path'] : null; - $schema = (isset($info['scheme']) && $info['scheme'] == 'https') ? 'https' : 'http'; - - $proxy_host = $proxy_port = $proxy_user = $proxy_pass = ''; - if ($this->config->get('http_proxy')&& - $proxy = parse_url($this->config->get('http_proxy')) - ) { - $proxy_host = isset($proxy['host']) ? $proxy['host'] : null; - if ($schema === 'https') { - $proxy_host = 'ssl://' . $proxy_host; - } + $url = $rest->getDownloadURL($base, $parr, $state, $downloadVersion, $chan->getName()); + if (PEAR::isError($url)) { + $this->configSet('default_channel', $curchannel); + return $url; + } - $proxy_port = isset($proxy['port']) ? $proxy['port'] : 8080; - $proxy_user = isset($proxy['user']) ? urldecode($proxy['user']) : null; - $proxy_pass = isset($proxy['pass']) ? urldecode($proxy['pass']) : null; - $proxy_schema = (isset($proxy['scheme']) && $proxy['scheme'] == 'https') ? 'https' : 'http'; + if ($parr['channel'] != $curchannel) { + $this->configSet('default_channel', $curchannel); } - if (empty($port)) { - $port = (isset($info['scheme']) && $info['scheme'] == 'https') ? 443 : 80; + if (!is_array($url)) { + return $url; } - if (isset($proxy['host'])) { - $request = "GET $url HTTP/1.1\r\n"; - } else { - $request = "GET $path HTTP/1.1\r\n"; + $url['raw'] = false; // no checking is necessary for REST + if (!is_array($url['info'])) { + return PEAR::raiseError('Invalid remote dependencies retrieved from REST - ' . + 'this should never happen'); } - $request .= "Host: $host:$port\r\n"; - $ifmodifiedsince = ''; - if (is_array($lastmodified)) { - if (isset($lastmodified['Last-Modified'])) { - $ifmodifiedsince = 'If-Modified-Since: ' . $lastmodified['Last-Modified'] . "\r\n"; + if (!isset($this->_options['force']) && + !isset($this->_options['downloadonly']) && + $version && + !PEAR::isError($version) && + !isset($parr['group']) + ) { + if (version_compare($version, $url['version'], '=')) { + return PEAR::raiseError($this->_registry->parsedPackageNameToString( + $parr, true) . ' is already installed and is the same as the ' . + 'released version ' . $url['version'], -976); } - if (isset($lastmodified['ETag'])) { - $ifmodifiedsince .= "If-None-Match: $lastmodified[ETag]\r\n"; + if (version_compare($version, $url['version'], '>')) { + return PEAR::raiseError($this->_registry->parsedPackageNameToString( + $parr, true) . ' is already installed and is newer than detected ' . + 'released version ' . $url['version'], -976); } - } else { - $ifmodifiedsince = ($lastmodified ? "If-Modified-Since: $lastmodified\r\n" : ''); } - $request .= $ifmodifiedsince . - "User-Agent: PEAR/1.8.0/PHP/" . PHP_VERSION . "\r\n"; - - $username = $this->config->get('username', null, $channel); - $password = $this->config->get('password', null, $channel); + if (isset($url['info']['required']) || $url['compatible']) { + require_once 'PEAR/PackageFile/v2.php'; + $pf = new PEAR_PackageFile_v2; + $pf->setRawChannel($parr['channel']); + if ($url['compatible']) { + $pf->setRawCompatible($url['compatible']); + } + } else { + require_once 'PEAR/PackageFile/v1.php'; + $pf = new PEAR_PackageFile_v1; + } - if ($username && $password) { - $tmp = base64_encode("$username:$password"); - $request .= "Authorization: Basic $tmp\r\n"; + $pf->setRawPackage($url['package']); + $pf->setDeps($url['info']); + if ($url['compatible']) { + $pf->setCompatible($url['compatible']); } - if ($proxy_host != '' && $proxy_user != '') { - $request .= 'Proxy-Authorization: Basic ' . - base64_encode($proxy_user . ':' . $proxy_pass) . "\r\n"; + $pf->setRawState($url['stability']); + $url['info'] = &$pf; + if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) { + $ext = '.tar'; + } else { + $ext = '.tgz'; } - if ($accept) { - $request .= 'Accept: ' . implode(', ', $accept) . "\r\n"; + if (is_array($url) && isset($url['url'])) { + $url['url'] .= $ext; } - $request .= "Accept-Encoding:\r\n"; - $request .= "Connection: close\r\n"; - $request .= "\r\n"; + return $url; + } - if ($proxy_host != '') { - $fp = @fsockopen($proxy_host, $proxy_port, $errno, $errstr, 15); - if (!$fp) { - return PEAR::raiseError("Connection to `$proxy_host:$proxy_port' failed: $errstr", -9276); + /** + * @param array dependency array + * @access private + */ + function _getDepPackageDownloadUrl($dep, $parr) + { + $xsdversion = isset($dep['rel']) ? '1.0' : '2.0'; + $curchannel = $this->config->get('default_channel'); + if (isset($dep['uri'])) { + $xsdversion = '2.0'; + $chan = &$this->_registry->getChannel('__uri'); + if (PEAR::isError($chan)) { + return $chan; } + + $version = $this->_registry->packageInfo($dep['name'], 'version', '__uri'); + $this->configSet('default_channel', '__uri'); } else { - if ($schema === 'https') { - $host = 'ssl://' . $host; + if (isset($dep['channel'])) { + $remotechannel = $dep['channel']; + } else { + $remotechannel = 'pear.php.net'; } - $fp = @fsockopen($host, $port, $errno, $errstr); - if (!$fp) { - return PEAR::raiseError("Connection to `$host:$port' failed: $errstr", $errno); + if (!$this->_registry->channelExists($remotechannel)) { + do { + if ($this->config->get('auto_discover')) { + if ($this->discover($remotechannel)) { + break; + } + } + return PEAR::raiseError('Unknown remote channel: ' . $remotechannel); + } while (false); + } + + $chan = &$this->_registry->getChannel($remotechannel); + if (PEAR::isError($chan)) { + return $chan; } + + $version = $this->_registry->packageInfo($dep['name'], 'version', $remotechannel); + $this->configSet('default_channel', $remotechannel); } - fwrite($fp, $request); + $state = isset($parr['state']) ? $parr['state'] : $this->config->get('preferred_state'); + if (isset($parr['state']) && isset($parr['version'])) { + unset($parr['state']); + } - $headers = array(); - $reply = 0; - while ($line = trim(fgets($fp, 1024))) { - if (preg_match('/^([^:]+):\s+(.*)\s*\\z/', $line, $matches)) { - $headers[strtolower($matches[1])] = trim($matches[2]); - } elseif (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) { - $reply = (int)$matches[1]; - if ($reply == 304 && ($lastmodified || ($lastmodified === false))) { - return false; + if (isset($dep['uri'])) { + $info = &$this->newDownloaderPackage($this); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $err = $info->initialize($dep); + PEAR::staticPopErrorHandling(); + if (!$err) { + // skip parameters that were missed by preferred_state + return PEAR::raiseError('Cannot initialize dependency'); + } + + if (PEAR::isError($err)) { + if (!isset($this->_options['soft'])) { + $this->log(0, $err->getMessage()); } - if (!in_array($reply, array(200, 301, 302, 303, 305, 307))) { - return PEAR::raiseError("File $schema://$host:$port$path not valid (received: $line)"); + if (is_object($info)) { + $param = $info->getChannel() . '/' . $info->getPackage(); } + return PEAR::raiseError('Package "' . $param . '" is not valid'); + } + return $info; + } elseif ($chan->supportsREST($this->config->get('preferred_mirror')) + && $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror')) + ) { + $rest = &$this->config->getREST('1.0', $this->_options); + $url = $rest->getDepDownloadURL($base, $xsdversion, $dep, $parr, + $state, $version, $chan->getName()); + if (PEAR::isError($url)) { + return $url; } - } - if ($reply != 200) { - if (!isset($headers['location'])) { - return PEAR::raiseError("File $schema://$host:$port$path not valid (redirected but no location)"); + if ($parr['channel'] != $curchannel) { + $this->configSet('default_channel', $curchannel); } - if ($wasredirect > 4) { - return PEAR::raiseError("File $schema://$host:$port$path not valid (redirection looped more than 5 times)"); + if (!is_array($url)) { + return $url; } - $redirect = $wasredirect + 1; - return $this->downloadHttp($headers['location'], $lastmodified, $accept, $channel); - } + $url['raw'] = false; // no checking is necessary for REST + if (!is_array($url['info'])) { + return PEAR::raiseError('Invalid remote dependencies retrieved from REST - ' . + 'this should never happen'); + } - $length = isset($headers['content-length']) ? $headers['content-length'] : -1; + if (isset($url['info']['required'])) { + if (!class_exists('PEAR_PackageFile_v2')) { + require_once 'PEAR/PackageFile/v2.php'; + } + $pf = new PEAR_PackageFile_v2; + $pf->setRawChannel($remotechannel); + } else { + if (!class_exists('PEAR_PackageFile_v1')) { + require_once 'PEAR/PackageFile/v1.php'; + } + $pf = new PEAR_PackageFile_v1; - $data = ''; - while ($chunk = @fread($fp, 8192)) { - $data .= $chunk; - } - fclose($fp); + } + $pf->setRawPackage($url['package']); + $pf->setDeps($url['info']); + if ($url['compatible']) { + $pf->setCompatible($url['compatible']); + } - if ($lastmodified === false || $lastmodified) { - if (isset($headers['etag'])) { - $lastmodified = array('ETag' => $headers['etag']); + $pf->setRawState($url['stability']); + $url['info'] = &$pf; + if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) { + $ext = '.tar'; + } else { + $ext = '.tgz'; } - if (isset($headers['last-modified'])) { - if (is_array($lastmodified)) { - $lastmodified['Last-Modified'] = $headers['last-modified']; - } else { - $lastmodified = $headers['last-modified']; - } + if (is_array($url) && isset($url['url'])) { + $url['url'] .= $ext; } - return array($data, $lastmodified, $headers); + return $url; } - return $data; + return $this->raiseError($parr['channel'] . ' is using a unsupported protocol - This should never happen.'); } -}PEAR-1.8.0/PEAR/RunTest.php100664 764 764 104653 100664 10222 - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: RunTest.php,v 1.74 2009/02/24 23:38:22 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.3.3 - */ - -/** - * for error handling - */ -require_once 'PEAR.php'; -require_once 'PEAR/Config.php'; - -define('DETAILED', 1); -putenv("PHP_PEAR_RUNTESTS=1"); - -/** - * Simplified version of PHP's test suite - * - * Try it with: - * - * $ php -r 'include "../PEAR/RunTest.php"; $t=new PEAR_RunTest; $o=$t->run("./pear_system.phpt");print_r($o);' - * - * - * @category pear - * @package PEAR - * @author Tomas V.V.Cox - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.3.3 - */ -class PEAR_RunTest -{ - var $_headers = array(); - var $_logger; - var $_options; - var $_php; - var $tests_count; - var $xdebug_loaded; - /** - * Saved value of php executable, used to reset $_php when we - * have a test that uses cgi - * - * @var unknown_type - */ - var $_savephp; - var $ini_overwrites = array( - 'output_handler=', - 'open_basedir=', - 'safe_mode=0', - 'disable_functions=', - 'output_buffering=Off', - 'display_errors=1', - 'log_errors=0', - 'html_errors=0', - 'track_errors=1', - 'report_memleaks=0', - 'report_zend_debug=0', - 'docref_root=', - 'docref_ext=.html', - 'error_prepend_string=', - 'error_append_string=', - 'auto_prepend_file=', - 'auto_append_file=', - 'magic_quotes_runtime=0', - 'xdebug.default_enable=0', - 'allow_url_fopen=1', - ); /** - * An object that supports the PEAR_Common->log() signature, or null - * @param PEAR_Common|null + * @deprecated in favor of _getPackageDownloadUrl */ - function PEAR_RunTest($logger = null, $options = array()) + function getPackageDownloadUrl($package, $version = null, $channel = false) { - if (!defined('E_DEPRECATED')) { - define('E_DEPRECATED', 0); - } - if (!defined('E_STRICT')) { - define('E_STRICT', 0); - } - $this->ini_overwrites[] = 'error_reporting=' . (E_ALL & ~(E_DEPRECATED | E_STRICT)); - if (is_null($logger)) { - require_once 'PEAR/Common.php'; - $logger = new PEAR_Common; + if ($version) { + $package .= "-$version"; } - $this->_logger = $logger; - $this->_options = $options; - - $conf = &PEAR_Config::singleton(); - $this->_php = $conf->get('php_bin'); - } - - /** - * Taken from php-src/run-tests.php - * - * @param string $commandline command name - * @param array $env - * @param string $stdin standard input to pass to the command - * @return unknown - */ - function system_with_timeout($commandline, $env = null, $stdin = null) - { - $data = ''; - if (version_compare(phpversion(), '5.0.0', '<')) { - $proc = proc_open($commandline, array( - 0 => array('pipe', 'r'), - 1 => array('pipe', 'w'), - 2 => array('pipe', 'w') - ), $pipes); + if ($this === null || $this->_registry === null) { + $package = "http://pear.php.net/get/$package"; } else { - $proc = proc_open($commandline, array( - 0 => array('pipe', 'r'), - 1 => array('pipe', 'w'), - 2 => array('pipe', 'w') - ), $pipes, null, $env, array('suppress_errors' => true)); - } - - if (!$proc) { - return false; - } - - if (is_string($stdin)) { - fwrite($pipes[0], $stdin); - } - fclose($pipes[0]); - - while (true) { - /* hide errors from interrupted syscalls */ - $r = $pipes; - $e = $w = null; - $n = @stream_select($r, $w, $e, 60); - - if ($n === 0) { - /* timed out */ - $data .= "\n ** ERROR: process timed out **\n"; - proc_terminate($proc); - return array(1234567890, $data); - } else if ($n > 0) { - $line = fread($pipes[1], 8192); - if (strlen($line) == 0) { - /* EOF */ - break; - } - $data .= $line; - } - } - if (function_exists('proc_get_status')) { - $stat = proc_get_status($proc); - if ($stat['signaled']) { - $data .= "\nTermsig=".$stat['stopsig']; + $chan = $this->_registry->getChannel($channel); + if (PEAR::isError($chan)) { + return ''; } + $package = "http://" . $chan->getServer() . "/get/$package"; } - $code = proc_close($proc); - if (function_exists('proc_get_status')) { - $code = $stat['exitcode']; + if (!extension_loaded("zlib")) { + $package .= '?uncompress=yes'; } - return array($code, $data); + return $package; } /** - * Turns a PHP INI string into an array - * - * Turns -d "include_path=/foo/bar" into this: - * array( - * 'include_path' => array( - * 'operator' => '-d', - * 'value' => '/foo/bar', - * ) - * ) - * Works both with quotes and without + * Retrieve a list of downloaded packages after a call to {@link download()}. * - * @param string an PHP INI string, -d "include_path=/foo/bar" + * Also resets the list of downloaded packages. * @return array */ - function iniString2array($ini_string) + function getDownloadedPackages() { - if (!$ini_string) { - return array(); - } - $split = preg_split('/[\s]|=/', $ini_string, -1, PREG_SPLIT_NO_EMPTY); - $key = $split[1][0] == '"' ? substr($split[1], 1) : $split[1]; - $value = $split[2][strlen($split[2]) - 1] == '"' ? substr($split[2], 0, -1) : $split[2]; - // FIXME review if this is really the struct to go with - $array = array($key => array('operator' => $split[0], 'value' => $value)); - return $array; + $ret = $this->_downloadedPackages; + $this->_downloadedPackages = array(); + $this->_toDownload = array(); + return $ret; } - function settings2array($settings, $ini_settings) + function _downloadCallback($msg, $params = null) { - foreach ($settings as $setting) { - if (strpos($setting, '=') !== false) { - $setting = explode('=', $setting, 2); - $name = trim(strtolower($setting[0])); - $value = trim($setting[1]); - $ini_settings[$name] = $value; - } + switch ($msg) { + case 'saveas': + $this->log(1, "downloading $params ..."); + break; + case 'done': + $this->log(1, '...done: ' . number_format($params, 0, '', ',') . ' bytes'); + break; + case 'bytesread': + static $bytes; + if (empty($bytes)) { + $bytes = 0; + } + if (!($bytes % 10240)) { + $this->log(1, '.', false); + } + $bytes += $params; + break; + case 'start': + if($params[1] == -1) { + $length = "Unknown size"; + } else { + $length = number_format($params[1], 0, '', ',')." bytes"; + } + $this->log(1, "Starting to download {$params[0]} ($length)"); + break; } - return $ini_settings; + if (method_exists($this->ui, '_downloadCallback')) + $this->ui->_downloadCallback($msg, $params); } - function settings2params($ini_settings) + function _prependPath($path, $prepend) { - $settings = ''; - foreach ($ini_settings as $name => $value) { - if (is_array($value)) { - $operator = $value['operator']; - $value = $value['value']; + if (strlen($prepend) > 0) { + if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) { + if (preg_match('/^[a-z]:/i', $prepend)) { + $prepend = substr($prepend, 2); + } elseif ($prepend{0} != '\\') { + $prepend = "\\$prepend"; + } + $path = substr($path, 0, 2) . $prepend . substr($path, 2); } else { - $operator = '-d'; + $path = $prepend . $path; } - $value = addslashes($value); - $settings .= " $operator \"$name=$value\""; } - return $settings; + return $path; } - function _preparePhpBin($php, $file, $ini_settings) + /** + * @param string + * @param integer + */ + function pushError($errmsg, $code = -1) { - $file = escapeshellarg($file); - // This was fixed in php 5.3 and is not needed after that - if (OS_WINDOWS && version_compare(PHP_VERSION, '5.3', '<')) { - $cmd = '"'.escapeshellarg($php).' '.$ini_settings.' -f ' . $file .'"'; - } else { - $cmd = $php . $ini_settings . ' -f ' . $file; - } - - return $cmd; + array_push($this->_errorStack, array($errmsg, $code)); } - function runPHPUnit($file, $ini_settings = '') + function getErrorMsgs() { - if (!file_exists($file) && file_exists(getcwd() . DIRECTORY_SEPARATOR . $file)) { - $file = realpath(getcwd() . DIRECTORY_SEPARATOR . $file); - break; - } elseif (file_exists($file)) { - $file = realpath($file); - } - - $cmd = $this->_preparePhpBin($this->_php, $file. $ini_settings); - if (isset($this->_logger)) { - $this->_logger->log(2, 'Running command "' . $cmd . '"'); + $msgs = array(); + $errs = $this->_errorStack; + foreach ($errs as $err) { + $msgs[] = $err[0]; } - - $savedir = getcwd(); // in case the test moves us around - chdir(dirname($file)); - echo `$cmd`; - chdir($savedir); - return 'PASSED'; // we have no way of knowing this information so assume passing + $this->_errorStack = array(); + return $msgs; } /** - * Runs an individual test case. + * for BC * - * @param string The filename of the test - * @param array|string INI settings to be applied to the test run - * @param integer Number what the current running test is of the - * whole test suite being runned. + * @deprecated + */ + function sortPkgDeps(&$packages, $uninstall = false) + { + $uninstall ? + $this->sortPackagesForUninstall($packages) : + $this->sortPackagesForInstall($packages); + } + + /** + * Sort a list of arrays of array(downloaded packagefilename) by dependency. * - * @return string|object Returns PASSED, WARNED, FAILED depending on how the - * test came out. - * PEAR Error when the tester it self fails + * This uses the topological sort method from graph theory, and the + * Structures_Graph package to properly sort dependencies for installation. + * @param array an array of downloaded PEAR_Downloader_Packages + * @return array array of array(packagefilename, package.xml contents) */ - function run($file, $ini_settings = array(), $test_number = 1) + function sortPackagesForInstall(&$packages) { - if (isset($this->_savephp)) { - $this->_php = $this->_savephp; - unset($this->_savephp); - } - if (empty($this->_options['cgi'])) { - // try to see if php-cgi is in the path - $res = $this->system_with_timeout('php-cgi -v'); - if (false !== $res && !(is_array($res) && $res === array(127, ''))) { - $this->_options['cgi'] = 'php-cgi'; - } - } - if (1 < $len = strlen($this->tests_count)) { - $test_number = str_pad($test_number, $len, ' ', STR_PAD_LEFT); - $test_nr = "[$test_number/$this->tests_count] "; - } else { - $test_nr = ''; + require_once 'Structures/Graph.php'; + require_once 'Structures/Graph/Node.php'; + require_once 'Structures/Graph/Manipulator/TopologicalSorter.php'; + $depgraph = new Structures_Graph(true); + $nodes = array(); + $reg = &$this->config->getRegistry(); + foreach ($packages as $i => $package) { + $pname = $reg->parsedPackageNameToString( + array( + 'channel' => $package->getChannel(), + 'package' => strtolower($package->getPackage()), + )); + $nodes[$pname] = new Structures_Graph_Node; + $nodes[$pname]->setData($packages[$i]); + $depgraph->addNode($nodes[$pname]); } - $file = realpath($file); - $section_text = $this->_readFile($file); - if (PEAR::isError($section_text)) { - return $section_text; - } + $deplinks = array(); + foreach ($nodes as $package => $node) { + $pf = &$node->getData(); + $pdeps = $pf->getDeps(true); + if (!$pdeps) { + continue; + } - if (isset($section_text['POST_RAW']) && isset($section_text['UPLOAD'])) { - return PEAR::raiseError("Cannot contain both POST_RAW and UPLOAD in test file: $file"); - } + if ($pf->getPackagexmlVersion() == '1.0') { + foreach ($pdeps as $dep) { + if ($dep['type'] != 'pkg' || + (isset($dep['optional']) && $dep['optional'] == 'yes')) { + continue; + } - $cwd = getcwd(); + $dname = $reg->parsedPackageNameToString( + array( + 'channel' => 'pear.php.net', + 'package' => strtolower($dep['name']), + )); - $pass_options = ''; - if (!empty($this->_options['ini'])) { - $pass_options = $this->_options['ini']; - } + if (isset($nodes[$dname])) { + if (!isset($deplinks[$dname])) { + $deplinks[$dname] = array(); + } - if (is_string($ini_settings)) { - $ini_settings = $this->iniString2array($ini_settings); - } + $deplinks[$dname][$package] = 1; + // dependency is in installed packages + continue; + } - $ini_settings = $this->settings2array($this->ini_overwrites, $ini_settings); - if ($section_text['INI']) { - if (strpos($section_text['INI'], '{PWD}') !== false) { - $section_text['INI'] = str_replace('{PWD}', dirname($file), $section_text['INI']); - } - $ini = preg_split( "/[\n\r]+/", $section_text['INI']); - $ini_settings = $this->settings2array($ini, $ini_settings); - } - $ini_settings = $this->settings2params($ini_settings); - $shortname = str_replace($cwd . DIRECTORY_SEPARATOR, '', $file); + $dname = $reg->parsedPackageNameToString( + array( + 'channel' => 'pecl.php.net', + 'package' => strtolower($dep['name']), + )); - $tested = trim($section_text['TEST']); - $tested.= !isset($this->_options['simple']) ? "[$shortname]" : ' '; + if (isset($nodes[$dname])) { + if (!isset($deplinks[$dname])) { + $deplinks[$dname] = array(); + } - if (!empty($section_text['POST']) || !empty($section_text['POST_RAW']) || - !empty($section_text['UPLOAD']) || !empty($section_text['GET']) || - !empty($section_text['COOKIE']) || !empty($section_text['EXPECTHEADERS'])) { - if (empty($this->_options['cgi'])) { - if (!isset($this->_options['quiet'])) { - $this->_logger->log(0, "SKIP $test_nr$tested (reason: --cgi option needed for this test, type 'pear help run-tests')"); + $deplinks[$dname][$package] = 1; + // dependency is in installed packages + continue; + } } - if (isset($this->_options['tapoutput'])) { - return array('ok', ' # skip --cgi option needed for this test, "pear help run-tests" for info'); + } else { + // the only ordering we care about is: + // 1) subpackages must be installed before packages that depend on them + // 2) required deps must be installed before packages that depend on them + if (isset($pdeps['required']['subpackage'])) { + $t = $pdeps['required']['subpackage']; + if (!isset($t[0])) { + $t = array($t); + } + + $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); } - return 'SKIPPED'; - } - $this->_savephp = $this->_php; - $this->_php = $this->_options['cgi']; - } - $temp_dir = realpath(dirname($file)); - $main_file_name = basename($file, 'phpt'); - $diff_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'diff'; - $log_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'log'; - $exp_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'exp'; - $output_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'out'; - $memcheck_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'mem'; - $temp_file = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'php'; - $temp_skipif = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'skip.php'; - $temp_clean = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'clean.php'; - $tmp_post = $temp_dir . DIRECTORY_SEPARATOR . uniqid('phpt.'); + if (isset($pdeps['group'])) { + if (!isset($pdeps['group'][0])) { + $pdeps['group'] = array($pdeps['group']); + } - // unlink old test results - $this->_cleanupOldFiles($file); + foreach ($pdeps['group'] as $group) { + if (isset($group['subpackage'])) { + $t = $group['subpackage']; + if (!isset($t[0])) { + $t = array($t); + } - // Check if test should be skipped. - $res = $this->_runSkipIf($section_text, $temp_skipif, $tested, $ini_settings); - if (count($res) != 2) { - return $res; - } - $info = $res['info']; - $warn = $res['warn']; - - // We've satisfied the preconditions - run the test! - if (isset($this->_options['coverage']) && $this->xdebug_loaded) { - $xdebug_file = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'xdebug'; - $text = '"; + $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); + } + } + } - $len_f = 5; - if (substr($section_text['FILE'], 0, 5) != 'save_text($temp_file, $text); - } else { - $this->save_text($temp_file, $section_text['FILE']); - } + $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); + } - $args = $section_text['ARGS'] ? ' -- '.$section_text['ARGS'] : ''; - $cmd = $this->_preparePhpBin($this->_php, $temp_file, $ini_settings); - $cmd.= "$args 2>&1"; - if (isset($this->_logger)) { - $this->_logger->log(2, 'Running command "' . $cmd . '"'); - } + if (isset($pdeps['required']['package'])) { + $t = $pdeps['required']['package']; + if (!isset($t[0])) { + $t = array($t); + } - // Reset environment from any previous test. - $env = $this->_resetEnv($section_text, $temp_file); + $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); + } - $section_text = $this->_processUpload($section_text, $file); - if (PEAR::isError($section_text)) { - return $section_text; - } + if (isset($pdeps['group'])) { + if (!isset($pdeps['group'][0])) { + $pdeps['group'] = array($pdeps['group']); + } - if (array_key_exists('POST_RAW', $section_text) && !empty($section_text['POST_RAW'])) { - $post = trim($section_text['POST_RAW']); - $raw_lines = explode("\n", $post); + foreach ($pdeps['group'] as $group) { + if (isset($group['package'])) { + $t = $group['package']; + if (!isset($t[0])) { + $t = array($t); + } - $request = ''; - $started = false; - foreach ($raw_lines as $i => $line) { - if (empty($env['CONTENT_TYPE']) && - preg_match('/^Content-Type:(.*)/i', $line, $res)) { - $env['CONTENT_TYPE'] = trim(str_replace("\r", '', $res[1])); - continue; - } - if ($started) { - $request .= "\n"; + $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); + } + } } - $started = true; - $request .= $line; } - - $env['CONTENT_LENGTH'] = strlen($request); - $env['REQUEST_METHOD'] = 'POST'; - - $this->save_text($tmp_post, $request); - $cmd = "$this->_php$pass_options$ini_settings \"$temp_file\" 2>&1 < $tmp_post"; - } elseif (array_key_exists('POST', $section_text) && !empty($section_text['POST'])) { - $post = trim($section_text['POST']); - $this->save_text($tmp_post, $post); - $content_length = strlen($post); - - $env['REQUEST_METHOD'] = 'POST'; - $env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'; - $env['CONTENT_LENGTH'] = $content_length; - - $cmd = "$this->_php$pass_options$ini_settings \"$temp_file\" 2>&1 < $tmp_post"; - } else { - $env['REQUEST_METHOD'] = 'GET'; - $env['CONTENT_TYPE'] = ''; - $env['CONTENT_LENGTH'] = ''; } - if (OS_WINDOWS && isset($section_text['RETURNS'])) { - ob_start(); - system($cmd, $return_value); - $out = ob_get_contents(); - ob_end_clean(); - $section_text['RETURNS'] = (int) trim($section_text['RETURNS']); - $returnfail = ($return_value != $section_text['RETURNS']); - } else { - $returnfail = false; - $stdin = isset($section_text['STDIN']) ? $section_text['STDIN'] : null; - $out = $this->system_with_timeout($cmd, $env, $stdin); - $return_value = $out[0]; - $out = $out[1]; + $this->_detectDepCycle($deplinks); + foreach ($deplinks as $dependent => $parents) { + foreach ($parents as $parent => $unused) { + $nodes[$dependent]->connectTo($nodes[$parent]); + } } - $output = preg_replace('/\r\n/', "\n", trim($out)); - - if (isset($tmp_post) && realpath($tmp_post) && file_exists($tmp_post)) { - @unlink(realpath($tmp_post)); + $installOrder = Structures_Graph_Manipulator_TopologicalSorter::sort($depgraph); + $ret = array(); + for ($i = 0, $count = count($installOrder); $i < $count; $i++) { + foreach ($installOrder[$i] as $index => $sortedpackage) { + $data = &$installOrder[$i][$index]->getData(); + $ret[] = &$nodes[$reg->parsedPackageNameToString( + array( + 'channel' => $data->getChannel(), + 'package' => strtolower($data->getPackage()), + ))]->getData(); + } } - chdir($cwd); // in case the test moves us around - - $this->_testCleanup($section_text, $temp_clean); - /* when using CGI, strip the headers from the output */ - $output = $this->_stripHeadersCGI($output); + $packages = $ret; + return; + } - if (isset($section_text['EXPECTHEADERS'])) { - $testheaders = $this->_processHeaders($section_text['EXPECTHEADERS']); - $missing = array_diff_assoc($testheaders, $this->_headers); - $changed = ''; - foreach ($missing as $header => $value) { - if (isset($this->_headers[$header])) { - $changed .= "-$header: $value\n+$header: "; - $changed .= $this->_headers[$header]; - } else { - $changed .= "-$header: $value\n"; - } - } - if ($missing) { - // tack on failed headers to output: - $output .= "\n====EXPECTHEADERS FAILURE====:\n$changed"; - } - } - // Does the output match what is expected? + /** + * Detect recursive links between dependencies and break the cycles + * + * @param array + * @access private + */ + function _detectDepCycle(&$deplinks) + { do { - if (isset($section_text['EXPECTF']) || isset($section_text['EXPECTREGEX'])) { - if (isset($section_text['EXPECTF'])) { - $wanted = trim($section_text['EXPECTF']); - } else { - $wanted = trim($section_text['EXPECTREGEX']); - } - $wanted_re = preg_replace('/\r\n/', "\n", $wanted); - if (isset($section_text['EXPECTF'])) { - $wanted_re = preg_quote($wanted_re, '/'); - // Stick to basics - $wanted_re = str_replace("%s", ".+?", $wanted_re); //not greedy - $wanted_re = str_replace("%i", "[+\-]?[0-9]+", $wanted_re); - $wanted_re = str_replace("%d", "[0-9]+", $wanted_re); - $wanted_re = str_replace("%x", "[0-9a-fA-F]+", $wanted_re); - $wanted_re = str_replace("%f", "[+\-]?\.?[0-9]+\.?[0-9]*(E-?[0-9]+)?", $wanted_re); - $wanted_re = str_replace("%c", ".", $wanted_re); - // %f allows two points "-.0.0" but that is the best *simple* expression - } + $keepgoing = false; + foreach ($deplinks as $dep => $parents) { + foreach ($parents as $parent => $unused) { + // reset the parent cycle detector + $this->_testCycle(null, null, null); + if ($this->_testCycle($dep, $deplinks, $parent)) { + $keepgoing = true; + unset($deplinks[$dep][$parent]); + if (count($deplinks[$dep]) == 0) { + unset($deplinks[$dep]); + } - /* DEBUG YOUR REGEX HERE - var_dump($wanted_re); - print(str_repeat('=', 80) . "\n"); - var_dump($output); - */ - if (!$returnfail && preg_match("/^$wanted_re\$/s", $output)) { - if (file_exists($temp_file)) { - unlink($temp_file); - } - if (array_key_exists('FAIL', $section_text)) { - break; - } - if (!isset($this->_options['quiet'])) { - $this->_logger->log(0, "PASS $test_nr$tested$info"); - } - if (isset($this->_options['tapoutput'])) { - return array('ok', ' - ' . $tested); - } - return 'PASSED'; - } - } else { - if (isset($section_text['EXPECTFILE'])) { - $f = $temp_dir . '/' . trim($section_text['EXPECTFILE']); - if (!($fp = @fopen($f, 'rb'))) { - return PEAR::raiseError('--EXPECTFILE-- section file ' . - $f . ' not found'); - } - fclose($fp); - $section_text['EXPECT'] = file_get_contents($f); - } - $wanted = preg_replace('/\r\n/', "\n", trim($section_text['EXPECT'])); - // compare and leave on success - if (!$returnfail && 0 == strcmp($output, $wanted)) { - if (file_exists($temp_file)) { - unlink($temp_file); - } - if (array_key_exists('FAIL', $section_text)) { - break; - } - if (!isset($this->_options['quiet'])) { - $this->_logger->log(0, "PASS $test_nr$tested$info"); - } - if (isset($this->_options['tapoutput'])) { - return array('ok', ' - ' . $tested); + continue 3; } - return 'PASSED'; - } - } - } while (false); - - if (array_key_exists('FAIL', $section_text)) { - // we expect a particular failure - // this is only used for testing PEAR_RunTest - $expectf = isset($section_text['EXPECTF']) ? $wanted_re : null; - $faildiff = $this->generate_diff($wanted, $output, null, $expectf); - $faildiff = preg_replace('/\r/', '', $faildiff); - $wanted = preg_replace('/\r/', '', trim($section_text['FAIL'])); - if ($faildiff == $wanted) { - if (!isset($this->_options['quiet'])) { - $this->_logger->log(0, "PASS $test_nr$tested$info"); - } - if (isset($this->_options['tapoutput'])) { - return array('ok', ' - ' . $tested); } - return 'PASSED'; - } - unset($section_text['EXPECTF']); - $output = $faildiff; - if (isset($section_text['RETURNS'])) { - return PEAR::raiseError('Cannot have both RETURNS and FAIL in the same test: ' . - $file); } - } - - // Test failed so we need to report details. - $txt = $warn ? 'WARN ' : 'FAIL '; - $this->_logger->log(0, $txt . $test_nr . $tested . $info); + } while ($keepgoing); + } - // write .exp - $res = $this->_writeLog($exp_filename, $wanted); - if (PEAR::isError($res)) { - return $res; + function _testCycle($test, $deplinks, $dep) + { + static $visited = array(); + if ($test === null) { + $visited = array(); + return; } - // write .out - $res = $this->_writeLog($output_filename, $output); - if (PEAR::isError($res)) { - return $res; + // this happens when a parent has a dep cycle on another dependency + // but the child is not part of the cycle + if (isset($visited[$dep])) { + return false; } - // write .diff - $returns = isset($section_text['RETURNS']) ? - array(trim($section_text['RETURNS']), $return_value) : null; - $expectf = isset($section_text['EXPECTF']) ? $wanted_re : null; - $data = $this->generate_diff($wanted, $output, $returns, $expectf); - $res = $this->_writeLog($diff_filename, $data); - if (PEAR::isError($res)) { - return $res; + $visited[$dep] = 1; + if ($test == $dep) { + return true; } - // write .log - $data = " ----- EXPECTED OUTPUT -$wanted ----- ACTUAL OUTPUT -$output ----- FAILED -"; - - if ($returnfail) { - $data .= " ----- EXPECTED RETURN -$section_text[RETURNS] ----- ACTUAL RETURN -$return_value -"; - } + if (isset($deplinks[$dep])) { + if (in_array($test, array_keys($deplinks[$dep]), true)) { + return true; + } - $res = $this->_writeLog($log_filename, $data); - if (PEAR::isError($res)) { - return $res; + foreach ($deplinks[$dep] as $parent => $unused) { + if ($this->_testCycle($test, $deplinks, $parent)) { + return true; + } + } } - if (isset($this->_options['tapoutput'])) { - $wanted = explode("\n", $wanted); - $wanted = "# Expected output:\n#\n#" . implode("\n#", $wanted); - $output = explode("\n", $output); - $output = "#\n#\n# Actual output:\n#\n#" . implode("\n#", $output); - return array($wanted . $output . 'not ok', ' - ' . $tested); - } - return $warn ? 'WARNED' : 'FAILED'; + return false; } - function generate_diff($wanted, $output, $rvalue, $wanted_re) + /** + * Set up the dependency for installation parsing + * + * @param array $t dependency information + * @param PEAR_Registry $reg + * @param array $deplinks list of dependency links already established + * @param array $nodes all existing package nodes + * @param string $package parent package name + * @access private + */ + function _setupGraph($t, $reg, &$deplinks, &$nodes, $package) { - $w = explode("\n", $wanted); - $o = explode("\n", $output); - $wr = explode("\n", $wanted_re); - $w1 = array_diff_assoc($w, $o); - $o1 = array_diff_assoc($o, $w); - $o2 = $w2 = array(); - foreach ($w1 as $idx => $val) { - if (!$wanted_re || !isset($wr[$idx]) || !isset($o1[$idx]) || - !preg_match('/^' . $wr[$idx] . '\\z/', $o1[$idx])) { - $w2[sprintf("%03d<", $idx)] = sprintf("%03d- ", $idx + 1) . $val; - } - } - foreach ($o1 as $idx => $val) { - if (!$wanted_re || !isset($wr[$idx]) || - !preg_match('/^' . $wr[$idx] . '\\z/', $val)) { - $o2[sprintf("%03d>", $idx)] = sprintf("%03d+ ", $idx + 1) . $val; + foreach ($t as $dep) { + $depchannel = !isset($dep['channel']) ? '__uri': $dep['channel']; + $dname = $reg->parsedPackageNameToString( + array( + 'channel' => $depchannel, + 'package' => strtolower($dep['name']), + )); + + if (isset($nodes[$dname])) { + if (!isset($deplinks[$dname])) { + $deplinks[$dname] = array(); + } + $deplinks[$dname][$package] = 1; } } - $diff = array_merge($w2, $o2); - ksort($diff); - $extra = $rvalue ? "##EXPECTED: $rvalue[0]\r\n##RETURNED: $rvalue[1]" : ''; - return implode("\r\n", $diff) . $extra; } - // Write the given text to a temporary file, and return the filename. - function save_text($filename, $text) + function _dependsOn($a, $b) { - if (!$fp = fopen($filename, 'w')) { - return PEAR::raiseError("Cannot open file '" . $filename . "' (save_text)"); - } - fwrite($fp, $text); - fclose($fp); - if (1 < DETAILED) echo " -FILE $filename {{{ -$text -}}} -"; + return $this->_checkDepTree(strtolower($a->getChannel()), strtolower($a->getPackage()), $b); } - function _cleanupOldFiles($file) + function _checkDepTree($channel, $package, $b, $checked = array()) { - $temp_dir = realpath(dirname($file)); - $mainFileName = basename($file, 'phpt'); - $diff_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'diff'; - $log_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'log'; - $exp_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'exp'; - $output_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'out'; - $memcheck_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'mem'; - $temp_file = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'php'; - $temp_skipif = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'skip.php'; - $temp_clean = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'clean.php'; - $tmp_post = $temp_dir . DIRECTORY_SEPARATOR . uniqid('phpt.'); + $checked[$channel][$package] = true; + if (!isset($this->_depTree[$channel][$package])) { + return false; + } - // unlink old test results - @unlink($diff_filename); - @unlink($log_filename); - @unlink($exp_filename); - @unlink($output_filename); - @unlink($memcheck_filename); - @unlink($temp_file); - @unlink($temp_skipif); - @unlink($tmp_post); - @unlink($temp_clean); - } + if (isset($this->_depTree[$channel][$package][strtolower($b->getChannel())] + [strtolower($b->getPackage())])) { + return true; + } - function _runSkipIf($section_text, $temp_skipif, $tested, $ini_settings) - { - $info = ''; - $warn = false; - if (array_key_exists('SKIPIF', $section_text) && trim($section_text['SKIPIF'])) { - $this->save_text($temp_skipif, $section_text['SKIPIF']); - $output = $this->system_with_timeout("$this->_php$ini_settings -f \"$temp_skipif\""); - $output = $output[1]; - $loutput = ltrim($output); - unlink($temp_skipif); - if (!strncasecmp('skip', $loutput, 4)) { - $skipreason = "SKIP $tested"; - if (preg_match('/^\s*skip\s*(.+)\s*/i', $output, $m)) { - $skipreason .= '(reason: ' . $m[1] . ')'; - } - if (!isset($this->_options['quiet'])) { - $this->_logger->log(0, $skipreason); - } - if (isset($this->_options['tapoutput'])) { - return array('ok', ' # skip ' . $reason); + foreach ($this->_depTree[$channel][$package] as $ch => $packages) { + foreach ($packages as $pa => $true) { + if ($this->_checkDepTree($ch, $pa, $b, $checked)) { + return true; } - return 'SKIPPED'; - } - - if (!strncasecmp('info', $loutput, 4) - && preg_match('/^\s*info\s*(.+)\s*/i', $output, $m)) { - $info = " (info: $m[1])"; - } - - if (!strncasecmp('warn', $loutput, 4) - && preg_match('/^\s*warn\s*(.+)\s*/i', $output, $m)) { - $warn = true; /* only if there is a reason */ - $info = " (warn: $m[1])"; } } - return array('warn' => $warn, 'info' => $info); + return false; } - function _stripHeadersCGI($output) + function _sortInstall($a, $b) { - $this->headers = array(); - if (!empty($this->_options['cgi']) && - $this->_php == $this->_options['cgi'] && - preg_match("/^(.*?)(?:\n\n(.*)|\\z)/s", $output, $match)) { - $output = isset($match[2]) ? trim($match[2]) : ''; - $this->_headers = $this->_processHeaders($match[1]); + if (!$a->getDeps() && !$b->getDeps()) { + return 0; // neither package has dependencies, order is insignificant } - - return $output; + if ($a->getDeps() && !$b->getDeps()) { + return 1; // $a must be installed after $b because $a has dependencies + } + if (!$a->getDeps() && $b->getDeps()) { + return -1; // $b must be installed after $a because $b has dependencies + } + // both packages have dependencies + if ($this->_dependsOn($a, $b)) { + return 1; + } + if ($this->_dependsOn($b, $a)) { + return -1; + } + return 0; } /** - * Return an array that can be used with array_diff() to compare headers + * Download a file through HTTP. Considers suggested file name in + * Content-disposition: header and can run a callback function for + * different events. The callback will be called with two + * parameters: the callback type, and parameters. The implemented + * callback types are: * - * @param string $text + * 'setup' called at the very beginning, parameter is a UI object + * that should be used for all output + * 'message' the parameter is a string with an informational message + * 'saveas' may be used to save with a different file name, the + * parameter is the filename that is about to be used. + * If a 'saveas' callback returns a non-empty string, + * that file name will be used as the filename instead. + * Note that $save_dir will not be affected by this, only + * the basename of the file. + * 'start' download is starting, parameter is number of bytes + * that are expected, or -1 if unknown + * 'bytesread' parameter is the number of bytes read so far + * 'done' download is complete, parameter is the total number + * of bytes read + * 'connfailed' if the TCP/SSL connection fails, this callback is called + * with array(host,port,errno,errmsg) + * 'writefailed' if writing to disk fails, this callback is called + * with array(destfile,errmsg) + * + * If an HTTP proxy has been configured (http_proxy PEAR_Config + * setting), the proxy will be used. + * + * @param string $url the URL to download + * @param object $ui PEAR_Frontend_* instance + * @param object $config PEAR_Config instance + * @param string $save_dir directory to save file in + * @param mixed $callback function/method to call for status + * updates + * @param false|string|array $lastmodified header values to check against for caching + * use false to return the header values from this download + * @param false|array $accept Accept headers to send + * @param false|string $channel Channel to use for retrieving authentication + * @return string|array Returns the full path of the downloaded file or a PEAR + * error on failure. If the error is caused by + * socket-related errors, the error object will + * have the fsockopen error code available through + * getCode(). If caching is requested, then return the header + * values. + * + * @access public */ - function _processHeaders($text) + function downloadHttp($url, &$ui, $save_dir = '.', $callback = null, $lastmodified = null, + $accept = false, $channel = false) { - $headers = array(); - $rh = preg_split("/[\n\r]+/", $text); - foreach ($rh as $line) { - if (strpos($line, ':')!== false) { - $line = explode(':', $line, 2); - $headers[trim($line[0])] = trim($line[1]); - } + static $redirect = 0; + // always reset , so we are clean case of error + $wasredirect = $redirect; + $redirect = 0; + if ($callback) { + call_user_func($callback, 'setup', array(&$ui)); } - return $headers; - } - function _readFile($file) - { - // Load the sections of the test file. - $section_text = array( - 'TEST' => '(unnamed test)', - 'SKIPIF' => '', - 'GET' => '', - 'COOKIE' => '', - 'POST' => '', - 'ARGS' => '', - 'INI' => '', - 'CLEAN' => '', - ); + $info = parse_url($url); + if (!isset($info['scheme']) || !in_array($info['scheme'], array('http', 'https'))) { + return PEAR::raiseError('Cannot download non-http URL "' . $url . '"'); + } - if (!is_file($file) || !$fp = fopen($file, "r")) { - return PEAR::raiseError("Cannot open test file: $file"); + if (!isset($info['host'])) { + return PEAR::raiseError('Cannot download from non-URL "' . $url . '"'); } - $section = ''; - while (!feof($fp)) { - $line = fgets($fp); + $host = isset($info['host']) ? $info['host'] : null; + $port = isset($info['port']) ? $info['port'] : null; + $path = isset($info['path']) ? $info['path'] : null; - // Match the beginning of a section. - if (preg_match('/^--([_A-Z]+)--/', $line, $r)) { - $section = $r[1]; - $section_text[$section] = ''; - continue; - } elseif (empty($section)) { - fclose($fp); - return PEAR::raiseError("Invalid sections formats in test file: $file"); + if (isset($this)) { + $config = &$this->config; + } else { + $config = &PEAR_Config::singleton(); + } + + $proxy_host = $proxy_port = $proxy_user = $proxy_pass = ''; + if ($config->get('http_proxy') && + $proxy = parse_url($config->get('http_proxy'))) { + $proxy_host = isset($proxy['host']) ? $proxy['host'] : null; + if (isset($proxy['scheme']) && $proxy['scheme'] == 'https') { + $proxy_host = 'ssl://' . $proxy_host; } + $proxy_port = isset($proxy['port']) ? $proxy['port'] : 8080; + $proxy_user = isset($proxy['user']) ? urldecode($proxy['user']) : null; + $proxy_pass = isset($proxy['pass']) ? urldecode($proxy['pass']) : null; - // Add to the section text. - $section_text[$section] .= $line; + if ($callback) { + call_user_func($callback, 'message', "Using HTTP proxy $host:$port"); + } } - fclose($fp); - - return $section_text; - } - function _writeLog($logname, $data) - { - if (!$log = fopen($logname, 'w')) { - return PEAR::raiseError("Cannot create test log - $logname"); + if (empty($port)) { + $port = (isset($info['scheme']) && $info['scheme'] == 'https') ? 443 : 80; } - fwrite($log, $data); - fclose($log); - } - function _resetEnv($section_text, $temp_file) - { - $env = $_ENV; - $env['REDIRECT_STATUS'] = ''; - $env['QUERY_STRING'] = ''; - $env['PATH_TRANSLATED'] = ''; - $env['SCRIPT_FILENAME'] = ''; - $env['REQUEST_METHOD'] = ''; - $env['CONTENT_TYPE'] = ''; - $env['CONTENT_LENGTH'] = ''; - if (!empty($section_text['ENV'])) { - if (strpos($section_text['ENV'], '{PWD}') !== false) { - $section_text['ENV'] = str_replace('{PWD}', dirname($temp_file), $section_text['ENV']); + $scheme = (isset($info['scheme']) && $info['scheme'] == 'https') ? 'https' : 'http'; + + if ($proxy_host != '') { + $fp = @fsockopen($proxy_host, $proxy_port, $errno, $errstr); + if (!$fp) { + if ($callback) { + call_user_func($callback, 'connfailed', array($proxy_host, $proxy_port, + $errno, $errstr)); + } + return PEAR::raiseError("Connection to `$proxy_host:$proxy_port' failed: $errstr", $errno); } - foreach (explode("\n", trim($section_text['ENV'])) as $e) { - $e = explode('=', trim($e), 2); - if (!empty($e[0]) && isset($e[1])) { - $env[$e[0]] = $e[1]; + + if ($lastmodified === false || $lastmodified) { + $request = "GET $url HTTP/1.1\r\n"; + $request .= "Host: $host:$port\r\n"; + } else { + $request = "GET $url HTTP/1.0\r\n"; + $request .= "Host: $host\r\n"; + } + } else { + $network_host = $host; + if (isset($info['scheme']) && $info['scheme'] == 'https') { + $network_host = 'ssl://' . $host; + } + + $fp = @fsockopen($network_host, $port, $errno, $errstr); + if (!$fp) { + if ($callback) { + call_user_func($callback, 'connfailed', array($host, $port, + $errno, $errstr)); } + return PEAR::raiseError("Connection to `$host:$port' failed: $errstr", $errno); + } + + if ($lastmodified === false || $lastmodified) { + $request = "GET $path HTTP/1.1\r\n"; + $request .= "Host: $host:$port\r\n"; + } else { + $request = "GET $path HTTP/1.0\r\n"; + $request .= "Host: $host\r\n"; } } - if (array_key_exists('GET', $section_text)) { - $env['QUERY_STRING'] = trim($section_text['GET']); + + $ifmodifiedsince = ''; + if (is_array($lastmodified)) { + if (isset($lastmodified['Last-Modified'])) { + $ifmodifiedsince = 'If-Modified-Since: ' . $lastmodified['Last-Modified'] . "\r\n"; + } + + if (isset($lastmodified['ETag'])) { + $ifmodifiedsince .= "If-None-Match: $lastmodified[ETag]\r\n"; + } } else { - $env['QUERY_STRING'] = ''; + $ifmodifiedsince = ($lastmodified ? "If-Modified-Since: $lastmodified\r\n" : ''); } - if (array_key_exists('COOKIE', $section_text)) { - $env['HTTP_COOKIE'] = trim($section_text['COOKIE']); - } else { - $env['HTTP_COOKIE'] = ''; + + $request .= $ifmodifiedsince . + "User-Agent: PEAR/1.9.0/PHP/" . PHP_VERSION . "\r\n"; + + if (isset($this)) { // only pass in authentication for non-static calls + $username = $config->get('username', null, $channel); + $password = $config->get('password', null, $channel); + if ($username && $password) { + $tmp = base64_encode("$username:$password"); + $request .= "Authorization: Basic $tmp\r\n"; + } } - $env['REDIRECT_STATUS'] = '1'; - $env['PATH_TRANSLATED'] = $temp_file; - $env['SCRIPT_FILENAME'] = $temp_file; - return $env; - } + if ($proxy_host != '' && $proxy_user != '') { + $request .= 'Proxy-Authorization: Basic ' . + base64_encode($proxy_user . ':' . $proxy_pass) . "\r\n"; + } - function _processUpload($section_text, $file) - { - if (array_key_exists('UPLOAD', $section_text) && !empty($section_text['UPLOAD'])) { - $upload_files = trim($section_text['UPLOAD']); - $upload_files = explode("\n", $upload_files); + if ($accept) { + $request .= 'Accept: ' . implode(', ', $accept) . "\r\n"; + } - $request = "Content-Type: multipart/form-data; boundary=---------------------------20896060251896012921717172737\n" . - "-----------------------------20896060251896012921717172737\n"; - foreach ($upload_files as $fileinfo) { - $fileinfo = explode('=', $fileinfo); - if (count($fileinfo) != 2) { - return PEAR::raiseError("Invalid UPLOAD section in test file: $file"); + $request .= "Connection: close\r\n"; + $request .= "\r\n"; + fwrite($fp, $request); + $headers = array(); + $reply = 0; + while (trim($line = fgets($fp, 1024))) { + if (preg_match('/^([^:]+):\s+(.*)\s*\\z/', $line, $matches)) { + $headers[strtolower($matches[1])] = trim($matches[2]); + } elseif (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) { + $reply = (int)$matches[1]; + if ($reply == 304 && ($lastmodified || ($lastmodified === false))) { + return false; } - if (!realpath(dirname($file) . '/' . $fileinfo[1])) { - return PEAR::raiseError("File for upload does not exist: $fileinfo[1] " . - "in test file: $file"); + + if (!in_array($reply, array(200, 301, 302, 303, 305, 307))) { + return PEAR::raiseError("File $scheme://$host:$port$path not valid (received: $line)"); } - $file_contents = file_get_contents(dirname($file) . '/' . $fileinfo[1]); - $fileinfo[1] = basename($fileinfo[1]); - $request .= "Content-Disposition: form-data; name=\"$fileinfo[0]\"; filename=\"$fileinfo[1]\"\n"; - $request .= "Content-Type: text/plain\n\n"; - $request .= $file_contents . "\n" . - "-----------------------------20896060251896012921717172737\n"; } + } - if (array_key_exists('POST', $section_text) && !empty($section_text['POST'])) { - // encode POST raw - $post = trim($section_text['POST']); - $post = explode('&', $post); - foreach ($post as $i => $post_info) { - $post_info = explode('=', $post_info); - if (count($post_info) != 2) { - return PEAR::raiseError("Invalid POST data in test file: $file"); - } - $post_info[0] = rawurldecode($post_info[0]); - $post_info[1] = rawurldecode($post_info[1]); - $post[$i] = $post_info; - } - foreach ($post as $post_info) { - $request .= "Content-Disposition: form-data; name=\"$post_info[0]\"\n\n"; - $request .= $post_info[1] . "\n" . - "-----------------------------20896060251896012921717172737\n"; + if ($reply != 200) { + if (!isset($headers['location'])) { + return PEAR::raiseError("File $scheme://$host:$port$path not valid (redirected but no location)"); + } + + if ($wasredirect > 4) { + return PEAR::raiseError("File $scheme://$host:$port$path not valid (redirection looped more than 5 times)"); + } + + $redirect = $wasredirect + 1; + return $this->downloadHttp($headers['location'], + $ui, $save_dir, $callback, $lastmodified, $accept); + } + + if (isset($headers['content-disposition']) && + preg_match('/\sfilename=\"([^;]*\S)\"\s*(;|\\z)/', $headers['content-disposition'], $matches)) { + $save_as = basename($matches[1]); + } else { + $save_as = basename($url); + } + + if ($callback) { + $tmp = call_user_func($callback, 'saveas', $save_as); + if ($tmp) { + $save_as = $tmp; + } + } + + $dest_file = $save_dir . DIRECTORY_SEPARATOR . $save_as; + if (!$wp = @fopen($dest_file, 'wb')) { + fclose($fp); + if ($callback) { + call_user_func($callback, 'writefailed', array($dest_file, $php_errormsg)); + } + return PEAR::raiseError("could not open $dest_file for writing"); + } + + $length = isset($headers['content-length']) ? $headers['content-length'] : -1; + + $bytes = 0; + if ($callback) { + call_user_func($callback, 'start', array(basename($dest_file), $length)); + } + + while ($data = fread($fp, 1024)) { + $bytes += strlen($data); + if ($callback) { + call_user_func($callback, 'bytesread', $bytes); + } + if (!@fwrite($wp, $data)) { + fclose($fp); + if ($callback) { + call_user_func($callback, 'writefailed', array($dest_file, $php_errormsg)); } - unset($section_text['POST']); + return PEAR::raiseError("$dest_file: write failed ($php_errormsg)"); } - $section_text['POST_RAW'] = $request; } - return $section_text; - } + fclose($fp); + fclose($wp); + if ($callback) { + call_user_func($callback, 'done', $bytes); + } - function _testCleanup($section_text, $temp_clean) - { - if ($section_text['CLEAN']) { - // perform test cleanup - $this->save_text($temp_clean, $section_text['CLEAN']); - $this->system_with_timeout("$this->_php $temp_clean"); - if (file_exists($temp_clean)) { - unlink($temp_clean); + if ($lastmodified === false || $lastmodified) { + if (isset($headers['etag'])) { + $lastmodified = array('ETag' => $headers['etag']); + } + + if (isset($headers['last-modified'])) { + if (is_array($lastmodified)) { + $lastmodified['Last-Modified'] = $headers['last-modified']; + } else { + $lastmodified = $headers['last-modified']; + } } + return array($dest_file, $lastmodified, $headers); } + return $dest_file; } -}PEAR-1.8.0/PEAR/Validate.php100664 764 764 53060 100664 10322 - * @copyright 1997-2009 The Authors + * @copyright 2004-2008 Greg Beaver * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Validate.php,v 1.54 2009/02/24 23:38:23 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 + * @version CVS: $Id: ErrorStack.php 276383 2009-02-24 23:39:37Z dufuz $ + * @link http://pear.php.net/package/PEAR_ErrorStack + */ + +/** + * Singleton storage + * + * Format: + *
+ * array(
+ *  'package1' => PEAR_ErrorStack object,
+ *  'package2' => PEAR_ErrorStack object,
+ *  ...
+ * )
+ * 
+ * @access private + * @global array $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] + */ +$GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] = array(); + +/** + * Global error callback (default) + * + * This is only used if set to non-false. * is the default callback for + * all packages, whereas specific packages may set a default callback + * for all instances, regardless of whether they are a singleton or not. + * + * To exclude non-singletons, only set the local callback for the singleton + * @see PEAR_ErrorStack::setDefaultCallback() + * @access private + * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] + */ +$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] = array( + '*' => false, +); + +/** + * Global Log object (default) + * + * This is only used if set to non-false. Use to set a default log object for + * all stacks, regardless of instantiation order or location + * @see PEAR_ErrorStack::setDefaultLogger() + * @access private + * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] + */ +$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = false; + +/** + * Global Overriding Callback + * + * This callback will override any error callbacks that specific loggers have set. + * Use with EXTREME caution + * @see PEAR_ErrorStack::staticPushCallback() + * @access private + * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] */ +$GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array(); + /**#@+ - * Constants for install stage + * One of four possible return values from the error Callback + * @see PEAR_ErrorStack::_errorCallback() */ -define('PEAR_VALIDATE_INSTALLING', 1); -define('PEAR_VALIDATE_UNINSTALLING', 2); // this is not bit-mapped like the others -define('PEAR_VALIDATE_NORMAL', 3); -define('PEAR_VALIDATE_DOWNLOADING', 4); // this is not bit-mapped like the others -define('PEAR_VALIDATE_PACKAGING', 7); +/** + * If this is returned, then the error will be both pushed onto the stack + * and logged. + */ +define('PEAR_ERRORSTACK_PUSHANDLOG', 1); +/** + * If this is returned, then the error will only be pushed onto the stack, + * and not logged. + */ +define('PEAR_ERRORSTACK_PUSH', 2); +/** + * If this is returned, then the error will only be logged, but not pushed + * onto the error stack. + */ +define('PEAR_ERRORSTACK_LOG', 3); +/** + * If this is returned, then the error is completely ignored. + */ +define('PEAR_ERRORSTACK_IGNORE', 4); +/** + * If this is returned, then the error is logged and die() is called. + */ +define('PEAR_ERRORSTACK_DIE', 5); /**#@-*/ -require_once 'PEAR/Common.php'; -require_once 'PEAR/Validator/PECL.php'; /** - * Validation class for package.xml - channel-level advanced validation - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 + * Error code for an attempt to instantiate a non-class as a PEAR_ErrorStack in + * the singleton method. */ -class PEAR_Validate -{ - var $packageregex = _PEAR_COMMON_PACKAGE_NAME_PREG; +define('PEAR_ERRORSTACK_ERR_NONCLASS', 1); + +/** + * Error code for an attempt to pass an object into {@link PEAR_ErrorStack::getMessage()} + * that has no __toString() method + */ +define('PEAR_ERRORSTACK_ERR_OBJTOSTRING', 2); +/** + * Error Stack Implementation + * + * Usage: + * + * // global error stack + * $global_stack = &PEAR_ErrorStack::singleton('MyPackage'); + * // local error stack + * $local_stack = new PEAR_ErrorStack('MyPackage'); + * + * @author Greg Beaver + * @version 1.9.0 + * @package PEAR_ErrorStack + * @category Debugging + * @copyright 2004-2008 Greg Beaver + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: ErrorStack.php 276383 2009-02-24 23:39:37Z dufuz $ + * @link http://pear.php.net/package/PEAR_ErrorStack + */ +class PEAR_ErrorStack { + /** + * Errors are stored in the order that they are pushed on the stack. + * @since 0.4alpha Errors are no longer organized by error level. + * This renders pop() nearly unusable, and levels could be more easily + * handled in a callback anyway + * @var array + * @access private + */ + var $_errors = array(); + /** - * @var PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * Storage of errors by level. + * + * Allows easy retrieval and deletion of only errors from a particular level + * @since PEAR 1.4.0dev + * @var array + * @access private */ - var $_packagexml; + var $_errorsByLevel = array(); + /** - * @var int one of the PEAR_VALIDATE_* constants + * Package name this error stack represents + * @var string + * @access protected */ - var $_state = PEAR_VALIDATE_NORMAL; + var $_package; + /** - * Format: ('error' => array('field' => name, 'reason' => reason), 'warning' => same) - * @var array + * Determines whether a PEAR_Error is thrown upon every error addition + * @var boolean * @access private */ - var $_failures = array('error' => array(), 'warning' => array()); - + var $_compat = false; + /** - * Override this method to handle validation of normal package names - * @param string - * @return bool + * If set to a valid callback, this will be used to generate the error + * message from the error code, otherwise the message passed in will be + * used + * @var false|string|array + * @access private + */ + var $_msgCallback = false; + + /** + * If set to a valid callback, this will be used to generate the error + * context for an error. For PHP-related errors, this will be a file + * and line number as retrieved from debug_backtrace(), but can be + * customized for other purposes. The error might actually be in a separate + * configuration file, or in a database query. + * @var false|string|array * @access protected */ - function _validPackageName($name) - { - return (bool) preg_match('/^' . $this->packageregex . '\\z/', $name); + var $_contextCallback = false; + + /** + * If set to a valid callback, this will be called every time an error + * is pushed onto the stack. The return value will be used to determine + * whether to allow an error to be pushed or logged. + * + * The return value must be one an PEAR_ERRORSTACK_* constant + * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG + * @var false|string|array + * @access protected + */ + var $_errorCallback = array(); + + /** + * PEAR::Log object for logging errors + * @var false|Log + * @access protected + */ + var $_logger = false; + + /** + * Error messages - designed to be overridden + * @var array + * @abstract + */ + var $_errorMsgs = array(); + + /** + * Set up a new error stack + * + * @param string $package name of the package this error stack represents + * @param callback $msgCallback callback used for error message generation + * @param callback $contextCallback callback used for context generation, + * defaults to {@link getFileLine()} + * @param boolean $throwPEAR_Error + */ + function PEAR_ErrorStack($package, $msgCallback = false, $contextCallback = false, + $throwPEAR_Error = false) + { + $this->_package = $package; + $this->setMessageCallback($msgCallback); + $this->setContextCallback($contextCallback); + $this->_compat = $throwPEAR_Error; } - + /** - * @param string package name to validate - * @param string name of channel-specific validation package - * @final + * Return a single error stack for this package. + * + * Note that all parameters are ignored if the stack for package $package + * has already been instantiated + * @param string $package name of the package this error stack represents + * @param callback $msgCallback callback used for error message generation + * @param callback $contextCallback callback used for context generation, + * defaults to {@link getFileLine()} + * @param boolean $throwPEAR_Error + * @param string $stackClass class to instantiate + * @static + * @return PEAR_ErrorStack */ - function validPackageName($name, $validatepackagename = false) + function &singleton($package, $msgCallback = false, $contextCallback = false, + $throwPEAR_Error = false, $stackClass = 'PEAR_ErrorStack') { - if ($validatepackagename) { - if (strtolower($name) == strtolower($validatepackagename)) { - return (bool) preg_match('/^[a-zA-Z0-9_]+(?:\.[a-zA-Z0-9_]+)*\\z/', $name); + if (isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { + return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]; + } + if (!class_exists($stackClass)) { + if (function_exists('debug_backtrace')) { + $trace = debug_backtrace(); } + PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_NONCLASS, + 'exception', array('stackclass' => $stackClass), + 'stack class "%stackclass%" is not a valid class name (should be like PEAR_ErrorStack)', + false, $trace); } - return $this->_validPackageName($name); + $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package] = + new $stackClass($package, $msgCallback, $contextCallback, $throwPEAR_Error); + + return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]; } /** - * This validates a bundle name, and bundle names must conform - * to the PEAR naming convention, so the method is final and static. - * @param string - * @final - * @static + * Internal error handler for PEAR_ErrorStack class + * + * Dies if the error is an exception (and would have died anyway) + * @access private */ - function validGroupName($name) + function _handleError($err) { - return (bool) preg_match('/^' . _PEAR_COMMON_PACKAGE_NAME_PREG . '\\z/', $name); + if ($err['level'] == 'exception') { + $message = $err['message']; + if (isset($_SERVER['REQUEST_URI'])) { + echo '
'; + } else { + echo "\n"; + } + var_dump($err['context']); + die($message); + } } - + /** - * Determine whether $state represents a valid stability level - * @param string - * @return bool + * Set up a PEAR::Log object for all error stacks that don't have one + * @param Log $log * @static - * @final */ - function validState($state) + function setDefaultLogger(&$log) { - return in_array($state, array('snapshot', 'devel', 'alpha', 'beta', 'stable')); + if (is_object($log) && method_exists($log, 'log') ) { + $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log; + } elseif (is_callable($log)) { + $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log; + } } - + /** - * Get a list of valid stability levels - * @return array - * @static - * @final + * Set up a PEAR::Log object for this error stack + * @param Log $log */ - function getValidStates() + function setLogger(&$log) { - return array('snapshot', 'devel', 'alpha', 'beta', 'stable'); + if (is_object($log) && method_exists($log, 'log') ) { + $this->_logger = &$log; + } elseif (is_callable($log)) { + $this->_logger = &$log; + } } - + /** - * Determine whether a version is a properly formatted version number that can be used - * by version_compare - * @param string - * @return bool + * Set an error code => error message mapping callback + * + * This method sets the callback that can be used to generate error + * messages for any instance + * @param array|string Callback function/method + */ + function setMessageCallback($msgCallback) + { + if (!$msgCallback) { + $this->_msgCallback = array(&$this, 'getErrorMessage'); + } else { + if (is_callable($msgCallback)) { + $this->_msgCallback = $msgCallback; + } + } + } + + /** + * Get an error code => error message mapping callback + * + * This method returns the current callback that can be used to generate error + * messages + * @return array|string|false Callback function/method or false if none + */ + function getMessageCallback() + { + return $this->_msgCallback; + } + + /** + * Sets a default callback to be used by all error stacks + * + * This method sets the callback that can be used to generate error + * messages for a singleton + * @param array|string Callback function/method + * @param string Package name, or false for all packages * @static - * @final */ - function validVersion($ver) + function setDefaultCallback($callback = false, $package = false) { - return (bool) preg_match(PEAR_COMMON_PACKAGE_VERSION_PREG, $ver); + if (!is_callable($callback)) { + $callback = false; + } + $package = $package ? $package : '*'; + $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$package] = $callback; } - + /** - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * Set a callback that generates context information (location of error) for an error stack + * + * This method sets the callback that can be used to generate context + * information for an error. Passing in NULL will disable context generation + * and remove the expensive call to debug_backtrace() + * @param array|string|null Callback function/method + */ + function setContextCallback($contextCallback) + { + if ($contextCallback === null) { + return $this->_contextCallback = false; + } + if (!$contextCallback) { + $this->_contextCallback = array(&$this, 'getFileLine'); + } else { + if (is_callable($contextCallback)) { + $this->_contextCallback = $contextCallback; + } + } + } + + /** + * Set an error Callback + * If set to a valid callback, this will be called every time an error + * is pushed onto the stack. The return value will be used to determine + * whether to allow an error to be pushed or logged. + * + * The return value must be one of the ERRORSTACK_* constants. + * + * This functionality can be used to emulate PEAR's pushErrorHandling, and + * the PEAR_ERROR_CALLBACK mode, without affecting the integrity of + * the error stack or logging + * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG + * @see popCallback() + * @param string|array $cb */ - function setPackageFile(&$pf) + function pushCallback($cb) { - $this->_packagexml = &$pf; + array_push($this->_errorCallback, $cb); } - + /** - * @access private + * Remove a callback from the error callback stack + * @see pushCallback() + * @return array|string|false */ - function _addFailure($field, $reason) + function popCallback() { - $this->_failures['errors'][] = array('field' => $field, 'reason' => $reason); + if (!count($this->_errorCallback)) { + return false; + } + return array_pop($this->_errorCallback); } - + /** - * @access private + * Set a temporary overriding error callback for every package error stack + * + * Use this to temporarily disable all existing callbacks (can be used + * to emulate the @ operator, for instance) + * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG + * @see staticPopCallback(), pushCallback() + * @param string|array $cb + * @static */ - function _addWarning($field, $reason) + function staticPushCallback($cb) { - $this->_failures['warnings'][] = array('field' => $field, 'reason' => $reason); + array_push($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'], $cb); } - - function getFailures() + + /** + * Remove a temporary overriding error callback + * @see staticPushCallback() + * @return array|string|false + * @static + */ + function staticPopCallback() { - $failures = $this->_failures; - $this->_failures = array('warnings' => array(), 'errors' => array()); - return $failures; + $ret = array_pop($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK']); + if (!is_array($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'])) { + $GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array(); + } + return $ret; } - + /** - * @param int one of the PEAR_VALIDATE_* constants + * Add an error to the stack + * + * If the message generator exists, it is called with 2 parameters. + * - the current Error Stack object + * - an array that is in the same format as an error. Available indices + * are 'code', 'package', 'time', 'params', 'level', and 'context' + * + * Next, if the error should contain context information, this is + * handled by the context grabbing method. + * Finally, the error is pushed onto the proper error stack + * @param int $code Package-specific error code + * @param string $level Error level. This is NOT spell-checked + * @param array $params associative array of error parameters + * @param string $msg Error message, or a portion of it if the message + * is to be generated + * @param array $repackage If this error re-packages an error pushed by + * another package, place the array returned from + * {@link pop()} in this parameter + * @param array $backtrace Protected parameter: use this to pass in the + * {@link debug_backtrace()} that should be used + * to find error context + * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also + * thrown. If a PEAR_Error is returned, the userinfo + * property is set to the following array: + * + * + * array( + * 'code' => $code, + * 'params' => $params, + * 'package' => $this->_package, + * 'level' => $level, + * 'time' => time(), + * 'context' => $context, + * 'message' => $msg, + * //['repackage' => $err] repackaged error array/Exception class + * ); + * + * + * Normally, the previous array is returned. */ - function validate($state = null) + function push($code, $level = 'error', $params = array(), $msg = false, + $repackage = false, $backtrace = false) { - if (!isset($this->_packagexml)) { - return false; + $context = false; + // grab error context + if ($this->_contextCallback) { + if (!$backtrace) { + $backtrace = debug_backtrace(); + } + $context = call_user_func($this->_contextCallback, $code, $params, $backtrace); } - if ($state !== null) { - $this->_state = $state; + + // save error + $time = explode(' ', microtime()); + $time = $time[1] + $time[0]; + $err = array( + 'code' => $code, + 'params' => $params, + 'package' => $this->_package, + 'level' => $level, + 'time' => $time, + 'context' => $context, + 'message' => $msg, + ); + + if ($repackage) { + $err['repackage'] = $repackage; + } + + // set up the error message, if necessary + if ($this->_msgCallback) { + $msg = call_user_func_array($this->_msgCallback, + array(&$this, $err)); + $err['message'] = $msg; + } + $push = $log = true; + $die = false; + // try the overriding callback first + $callback = $this->staticPopCallback(); + if ($callback) { + $this->staticPushCallback($callback); } - $this->_failures = array('warnings' => array(), 'errors' => array()); - $this->validatePackageName(); - $this->validateVersion(); - $this->validateMaintainers(); - $this->validateDate(); - $this->validateSummary(); - $this->validateDescription(); - $this->validateLicense(); - $this->validateNotes(); - if ($this->_packagexml->getPackagexmlVersion() == '1.0') { - $this->validateState(); - $this->validateFilelist(); - } elseif ($this->_packagexml->getPackagexmlVersion() == '2.0' || - $this->_packagexml->getPackagexmlVersion() == '2.1') { - $this->validateTime(); - $this->validateStability(); - $this->validateDeps(); - $this->validateMainFilelist(); - $this->validateReleaseFilelist(); - //$this->validateGlobalTasks(); - $this->validateChangelog(); + if (!is_callable($callback)) { + // try the local callback next + $callback = $this->popCallback(); + if (is_callable($callback)) { + $this->pushCallback($callback); + } else { + // try the default callback + $callback = isset($GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package]) ? + $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package] : + $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']['*']; + } + } + if (is_callable($callback)) { + switch(call_user_func($callback, $err)){ + case PEAR_ERRORSTACK_IGNORE: + return $err; + break; + case PEAR_ERRORSTACK_PUSH: + $log = false; + break; + case PEAR_ERRORSTACK_LOG: + $push = false; + break; + case PEAR_ERRORSTACK_DIE: + $die = true; + break; + // anything else returned has the same effect as pushandlog + } + } + if ($push) { + array_unshift($this->_errors, $err); + if (!isset($this->_errorsByLevel[$err['level']])) { + $this->_errorsByLevel[$err['level']] = array(); + } + $this->_errorsByLevel[$err['level']][] = &$this->_errors[0]; + } + if ($log) { + if ($this->_logger || $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']) { + $this->_log($err); + } } - return !((bool) count($this->_failures['errors'])); + if ($die) { + die(); + } + if ($this->_compat && $push) { + return $this->raiseError($msg, $code, null, null, $err); + } + return $err; } - + /** - * @access protected + * Static version of {@link push()} + * + * @param string $package Package name this error belongs to + * @param int $code Package-specific error code + * @param string $level Error level. This is NOT spell-checked + * @param array $params associative array of error parameters + * @param string $msg Error message, or a portion of it if the message + * is to be generated + * @param array $repackage If this error re-packages an error pushed by + * another package, place the array returned from + * {@link pop()} in this parameter + * @param array $backtrace Protected parameter: use this to pass in the + * {@link debug_backtrace()} that should be used + * to find error context + * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also + * thrown. see docs for {@link push()} + * @static */ - function validatePackageName() + function staticPush($package, $code, $level = 'error', $params = array(), + $msg = false, $repackage = false, $backtrace = false) { - if ($this->_state == PEAR_VALIDATE_PACKAGING || - $this->_state == PEAR_VALIDATE_NORMAL) { - if (($this->_packagexml->getPackagexmlVersion() == '2.0' || - $this->_packagexml->getPackagexmlVersion() == '2.1') && - $this->_packagexml->getExtends()) { - $version = $this->_packagexml->getVersion() . ''; - $name = $this->_packagexml->getPackage(); - $test = array_shift($a = explode('.', $version)); - if ($test == '0') { - return true; - } - $vlen = strlen($test); - $majver = substr($name, strlen($name) - $vlen); - while ($majver && !is_numeric($majver{0})) { - $majver = substr($majver, 1); - } - if ($majver != $test) { - $this->_addWarning('package', "package $name extends package " . - $this->_packagexml->getExtends() . ' and so the name should ' . - 'have a postfix equal to the major version like "' . - $this->_packagexml->getExtends() . $test . '"'); - return true; - } elseif (substr($name, 0, strlen($name) - $vlen) != - $this->_packagexml->getExtends()) { - $this->_addWarning('package', "package $name extends package " . - $this->_packagexml->getExtends() . ' and so the name must ' . - 'be an extension like "' . $this->_packagexml->getExtends() . - $test . '"'); - return true; + $s = &PEAR_ErrorStack::singleton($package); + if ($s->_contextCallback) { + if (!$backtrace) { + if (function_exists('debug_backtrace')) { + $backtrace = debug_backtrace(); } } } - if (!$this->validPackageName($this->_packagexml->getPackage())) { - $this->_addFailure('name', 'package name "' . - $this->_packagexml->getPackage() . '" is invalid'); - return false; - } + return $s->push($code, $level, $params, $msg, $repackage, $backtrace); } - + /** + * Log an error using PEAR::Log + * @param array $err Error array + * @param array $levels Error level => Log constant map * @access protected */ - function validateVersion() + function _log($err) { - if ($this->_state != PEAR_VALIDATE_PACKAGING) { - if (!$this->validVersion($this->_packagexml->getVersion())) { - $this->_addFailure('version', - 'Invalid version number "' . $this->_packagexml->getVersion() . '"'); - } - return false; - } - $version = $this->_packagexml->getVersion(); - $versioncomponents = explode('.', $version); - if (count($versioncomponents) != 3) { - $this->_addWarning('version', - 'A version number should have 3 decimals (x.y.z)'); - return true; + if ($this->_logger) { + $logger = &$this->_logger; + } else { + $logger = &$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']; } - $name = $this->_packagexml->getPackage(); - // version must be based upon state - switch ($this->_packagexml->getState()) { - case 'snapshot' : - return true; - case 'devel' : - if ($versioncomponents[0] . 'a' == '0a') { - return true; - } - if ($versioncomponents[0] == 0) { - $versioncomponents[0] = '0'; - $this->_addWarning('version', - 'version "' . $version . '" should be "' . - implode('.' ,$versioncomponents) . '"'); - } else { - $this->_addWarning('version', - 'packages with devel stability must be < version 1.0.0'); - } - return true; - break; - case 'alpha' : - case 'beta' : - // check for a package that extends a package, - // like Foo and Foo2 - if ($this->_state == PEAR_VALIDATE_PACKAGING) { - if (substr($versioncomponents[2], 1, 2) == 'rc') { - $this->_addFailure('version', 'Release Candidate versions ' . - 'must have capital RC, not lower-case rc'); - return false; - } - } - if (!$this->_packagexml->getExtends()) { - if ($versioncomponents[0] == '1') { - if ($versioncomponents[2]{0} == '0') { - if ($versioncomponents[2] == '0') { - // version 1.*.0000 - $this->_addWarning('version', - 'version 1.' . $versioncomponents[1] . - '.0 probably should not be alpha or beta'); - return true; - } elseif (strlen($versioncomponents[2]) > 1) { - // version 1.*.0RC1 or 1.*.0beta24 etc. - return true; - } else { - // version 1.*.0 - $this->_addWarning('version', - 'version 1.' . $versioncomponents[1] . - '.0 probably should not be alpha or beta'); - return true; - } - } else { - $this->_addWarning('version', - 'bugfix versions (1.3.x where x > 0) probably should ' . - 'not be alpha or beta'); - return true; - } - } elseif ($versioncomponents[0] != '0') { - $this->_addWarning('version', - 'major versions greater than 1 are not allowed for packages ' . - 'without an tag or an identical postfix (foo2 v2.0.0)'); - return true; - } - if ($versioncomponents[0] . 'a' == '0a') { - return true; - } - if ($versioncomponents[0] == 0) { - $versioncomponents[0] = '0'; - $this->_addWarning('version', - 'version "' . $version . '" should be "' . - implode('.' ,$versioncomponents) . '"'); - } - } else { - $vlen = strlen($versioncomponents[0] . ''); - $majver = substr($name, strlen($name) - $vlen); - while ($majver && !is_numeric($majver{0})) { - $majver = substr($majver, 1); - } - if (($versioncomponents[0] != 0) && $majver != $versioncomponents[0]) { - $this->_addWarning('version', 'first version number "' . - $versioncomponents[0] . '" must match the postfix of ' . - 'package name "' . $name . '" (' . - $majver . ')'); - return true; - } - if ($versioncomponents[0] == $majver) { - if ($versioncomponents[2]{0} == '0') { - if ($versioncomponents[2] == '0') { - // version 2.*.0000 - $this->_addWarning('version', - "version $majver." . $versioncomponents[1] . - '.0 probably should not be alpha or beta'); - return false; - } elseif (strlen($versioncomponents[2]) > 1) { - // version 2.*.0RC1 or 2.*.0beta24 etc. - return true; - } else { - // version 2.*.0 - $this->_addWarning('version', - "version $majver." . $versioncomponents[1] . - '.0 cannot be alpha or beta'); - return true; - } - } else { - $this->_addWarning('version', - "bugfix versions ($majver.x.y where y > 0) should " . - 'not be alpha or beta'); - return true; - } - } elseif ($versioncomponents[0] != '0') { - $this->_addWarning('version', - "only versions 0.x.y and $majver.x.y are allowed for alpha/beta releases"); - return true; - } - if ($versioncomponents[0] . 'a' == '0a') { - return true; - } - if ($versioncomponents[0] == 0) { - $versioncomponents[0] = '0'; - $this->_addWarning('version', - 'version "' . $version . '" should be "' . - implode('.' ,$versioncomponents) . '"'); - } - } - return true; - break; - case 'stable' : - if ($versioncomponents[0] == '0') { - $this->_addWarning('version', 'versions less than 1.0.0 cannot ' . - 'be stable'); - return true; - } - if (!is_numeric($versioncomponents[2])) { - if (preg_match('/\d+(rc|a|alpha|b|beta)\d*/i', - $versioncomponents[2])) { - $this->_addWarning('version', 'version "' . $version . '" or any ' . - 'RC/beta/alpha version cannot be stable'); - return true; - } - } - // check for a package that extends a package, - // like Foo and Foo2 - if ($this->_packagexml->getExtends()) { - $vlen = strlen($versioncomponents[0] . ''); - $majver = substr($name, strlen($name) - $vlen); - while ($majver && !is_numeric($majver{0})) { - $majver = substr($majver, 1); - } - if (($versioncomponents[0] != 0) && $majver != $versioncomponents[0]) { - $this->_addWarning('version', 'first version number "' . - $versioncomponents[0] . '" must match the postfix of ' . - 'package name "' . $name . '" (' . - $majver . ')'); - return true; - } - } elseif ($versioncomponents[0] > 1) { - $this->_addWarning('version', 'major version x in x.y.z may not be greater than ' . - '1 for any package that does not have an tag'); - } - return true; - break; - default : - return false; - break; + if (is_a($logger, 'Log')) { + $levels = array( + 'exception' => PEAR_LOG_CRIT, + 'alert' => PEAR_LOG_ALERT, + 'critical' => PEAR_LOG_CRIT, + 'error' => PEAR_LOG_ERR, + 'warning' => PEAR_LOG_WARNING, + 'notice' => PEAR_LOG_NOTICE, + 'info' => PEAR_LOG_INFO, + 'debug' => PEAR_LOG_DEBUG); + if (isset($levels[$err['level']])) { + $level = $levels[$err['level']]; + } else { + $level = PEAR_LOG_INFO; + } + $logger->log($err['message'], $level, $err); + } else { // support non-standard logs + call_user_func($logger, $err); } } + /** - * @access protected + * Pop an error off of the error stack + * + * @return false|array + * @since 0.4alpha it is no longer possible to specify a specific error + * level to return - the last error pushed will be returned, instead */ - function validateMaintainers() + function pop() { - // maintainers can only be truly validated server-side for most channels - // but allow this customization for those who wish it - return true; + $err = @array_shift($this->_errors); + if (!is_null($err)) { + @array_pop($this->_errorsByLevel[$err['level']]); + if (!count($this->_errorsByLevel[$err['level']])) { + unset($this->_errorsByLevel[$err['level']]); + } + } + return $err; } /** - * @access protected + * Pop an error off of the error stack, static method + * + * @param string package name + * @return boolean + * @since PEAR1.5.0a1 */ - function validateDate() + function staticPop($package) { - if ($this->_state == PEAR_VALIDATE_NORMAL || - $this->_state == PEAR_VALIDATE_PACKAGING) { - - if (!preg_match('/(\d\d\d\d)\-(\d\d)\-(\d\d)/', - $this->_packagexml->getDate(), $res) || - count($res) < 4 - || !checkdate($res[2], $res[3], $res[1]) - ) { - $this->_addFailure('date', 'invalid release date "' . - $this->_packagexml->getDate() . '"'); + if ($package) { + if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { return false; } - - if ($this->_state == PEAR_VALIDATE_PACKAGING && - $this->_packagexml->getDate() != date('Y-m-d')) { - $this->_addWarning('date', 'Release Date "' . - $this->_packagexml->getDate() . '" is not today'); - } + return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->pop(); } - return true; } /** - * @access protected + * Determine whether there are any errors on the stack + * @param string|array Level name. Use to determine if any errors + * of level (string), or levels (array) have been pushed + * @return boolean */ - function validateTime() + function hasErrors($level = false) { - if (!$this->_packagexml->getTime()) { - // default of no time value set - return true; + if ($level) { + return isset($this->_errorsByLevel[$level]); } - - // packager automatically sets time, so only validate if pear validate is called - if ($this->_state = PEAR_VALIDATE_NORMAL) { - if (!preg_match('/\d\d:\d\d:\d\d/', - $this->_packagexml->getTime())) { - $this->_addFailure('time', 'invalid release time "' . - $this->_packagexml->getTime() . '"'); - return false; + return count($this->_errors); + } + + /** + * Retrieve all errors since last purge + * + * @param boolean set in order to empty the error stack + * @param string level name, to return only errors of a particular severity + * @return array + */ + function getErrors($purge = false, $level = false) + { + if (!$purge) { + if ($level) { + if (!isset($this->_errorsByLevel[$level])) { + return array(); + } else { + return $this->_errorsByLevel[$level]; + } + } else { + return $this->_errors; } - - $result = preg_match('|\d{2}\:\d{2}\:\d{2}|', $this->_packagexml->getTime(), $matches); - if ($result === false || empty($matches)) { - $this->_addFailure('time', 'invalid release time "' . - $this->_packagexml->getTime() . '"'); - return false; + } + if ($level) { + $ret = $this->_errorsByLevel[$level]; + foreach ($this->_errorsByLevel[$level] as $i => $unused) { + // entries are references to the $_errors array + $this->_errorsByLevel[$level][$i] = false; } + // array_filter removes all entries === false + $this->_errors = array_filter($this->_errors); + unset($this->_errorsByLevel[$level]); + return $ret; } - - return true; + $ret = $this->_errors; + $this->_errors = array(); + $this->_errorsByLevel = array(); + return $ret; } - + /** - * @access protected + * Determine whether there are any errors on a single error stack, or on any error stack + * + * The optional parameter can be used to test the existence of any errors without the need of + * singleton instantiation + * @param string|false Package name to check for errors + * @param string Level name to check for a particular severity + * @return boolean + * @static */ - function validateState() + function staticHasErrors($package = false, $level = false) { - // this is the closest to "final" php4 can get - if (!PEAR_Validate::validState($this->_packagexml->getState())) { - if (strtolower($this->_packagexml->getState() == 'rc')) { - $this->_addFailure('state', 'RC is not a state, it is a version ' . - 'postfix, use ' . $this->_packagexml->getVersion() . 'RC1, state beta'); + if ($package) { + if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { + return false; } - $this->_addFailure('state', 'invalid release state "' . - $this->_packagexml->getState() . '", must be one of: ' . - implode(', ', PEAR_Validate::getValidStates())); - return false; + return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->hasErrors($level); } - return true; + foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) { + if ($obj->hasErrors($level)) { + return true; + } + } + return false; } - + /** - * @access protected + * Get a list of all errors since last purge, organized by package + * @since PEAR 1.4.0dev BC break! $level is now in the place $merge used to be + * @param boolean $purge Set to purge the error stack of existing errors + * @param string $level Set to a level name in order to retrieve only errors of a particular level + * @param boolean $merge Set to return a flat array, not organized by package + * @param array $sortfunc Function used to sort a merged array - default + * sorts by time, and should be good for most cases + * @static + * @return array */ - function validateStability() + function staticGetErrors($purge = false, $level = false, $merge = false, + $sortfunc = array('PEAR_ErrorStack', '_sortErrors')) { - $ret = true; - $packagestability = $this->_packagexml->getState(); - $apistability = $this->_packagexml->getState('api'); - if (!PEAR_Validate::validState($packagestability)) { - $this->_addFailure('state', 'invalid release stability "' . - $this->_packagexml->getState() . '", must be one of: ' . - implode(', ', PEAR_Validate::getValidStates())); - $ret = false; + $ret = array(); + if (!is_callable($sortfunc)) { + $sortfunc = array('PEAR_ErrorStack', '_sortErrors'); } - $apistates = PEAR_Validate::getValidStates(); - array_shift($apistates); // snapshot is not allowed - if (!in_array($apistability, $apistates)) { - $this->_addFailure('state', 'invalid API stability "' . - $this->_packagexml->getState('api') . '", must be one of: ' . - implode(', ', $apistates)); - $ret = false; + foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) { + $test = $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->getErrors($purge, $level); + if ($test) { + if ($merge) { + $ret = array_merge($ret, $test); + } else { + $ret[$package] = $test; + } + } + } + if ($merge) { + usort($ret, $sortfunc); } return $ret; } - + /** - * @access protected + * Error sorting function, sorts by time + * @access private */ - function validateSummary() + function _sortErrors($a, $b) { - return true; + if ($a['time'] == $b['time']) { + return 0; + } + if ($a['time'] < $b['time']) { + return 1; + } + return -1; } /** - * @access protected + * Standard file/line number/function/class context callback + * + * This function uses a backtrace generated from {@link debug_backtrace()} + * and so will not work at all in PHP < 4.3.0. The frame should + * reference the frame that contains the source of the error. + * @return array|false either array('file' => file, 'line' => line, + * 'function' => function name, 'class' => class name) or + * if this doesn't work, then false + * @param unused + * @param integer backtrace frame. + * @param array Results of debug_backtrace() + * @static */ - function validateDescription() + function getFileLine($code, $params, $backtrace = null) { - return true; + if ($backtrace === null) { + return false; + } + $frame = 0; + $functionframe = 1; + if (!isset($backtrace[1])) { + $functionframe = 0; + } else { + while (isset($backtrace[$functionframe]['function']) && + $backtrace[$functionframe]['function'] == 'eval' && + isset($backtrace[$functionframe + 1])) { + $functionframe++; + } + } + if (isset($backtrace[$frame])) { + if (!isset($backtrace[$frame]['file'])) { + $frame++; + } + $funcbacktrace = $backtrace[$functionframe]; + $filebacktrace = $backtrace[$frame]; + $ret = array('file' => $filebacktrace['file'], + 'line' => $filebacktrace['line']); + // rearrange for eval'd code or create function errors + if (strpos($filebacktrace['file'], '(') && + preg_match(';^(.*?)\((\d+)\) : (.*?)\\z;', $filebacktrace['file'], + $matches)) { + $ret['file'] = $matches[1]; + $ret['line'] = $matches[2] + 0; + } + if (isset($funcbacktrace['function']) && isset($backtrace[1])) { + if ($funcbacktrace['function'] != 'eval') { + if ($funcbacktrace['function'] == '__lambda_func') { + $ret['function'] = 'create_function() code'; + } else { + $ret['function'] = $funcbacktrace['function']; + } + } + } + if (isset($funcbacktrace['class']) && isset($backtrace[1])) { + $ret['class'] = $funcbacktrace['class']; + } + return $ret; + } + return false; } - + /** - * @access protected + * Standard error message generation callback + * + * This method may also be called by a custom error message generator + * to fill in template values from the params array, simply + * set the third parameter to the error message template string to use + * + * The special variable %__msg% is reserved: use it only to specify + * where a message passed in by the user should be placed in the template, + * like so: + * + * Error message: %msg% - internal error + * + * If the message passed like so: + * + * + * $stack->push(ERROR_CODE, 'error', array(), 'server error 500'); + * + * + * The returned error message will be "Error message: server error 500 - + * internal error" + * @param PEAR_ErrorStack + * @param array + * @param string|false Pre-generated error message template + * @static + * @return string */ - function validateLicense() + function getErrorMessage(&$stack, $err, $template = false) { - return true; + if ($template) { + $mainmsg = $template; + } else { + $mainmsg = $stack->getErrorMessageTemplate($err['code']); + } + $mainmsg = str_replace('%__msg%', $err['message'], $mainmsg); + if (is_array($err['params']) && count($err['params'])) { + foreach ($err['params'] as $name => $val) { + if (is_array($val)) { + // @ is needed in case $val is a multi-dimensional array + $val = @implode(', ', $val); + } + if (is_object($val)) { + if (method_exists($val, '__toString')) { + $val = $val->__toString(); + } else { + PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_OBJTOSTRING, + 'warning', array('obj' => get_class($val)), + 'object %obj% passed into getErrorMessage, but has no __toString() method'); + $val = 'Object'; + } + } + $mainmsg = str_replace('%' . $name . '%', $val, $mainmsg); + } + } + return $mainmsg; } - + /** - * @access protected + * Standard Error Message Template generator from code + * @return string */ - function validateNotes() + function getErrorMessageTemplate($code) { - return true; + if (!isset($this->_errorMsgs[$code])) { + return '%__msg%'; + } + return $this->_errorMsgs[$code]; } - + /** - * for package.xml 2.0 only - channels can't use package.xml 1.0 - * @access protected + * Set the Error Message Template array + * + * The array format must be: + *
+     * array(error code => 'message template',...)
+     * 
+ * + * Error message parameters passed into {@link push()} will be used as input + * for the error message. If the template is 'message %foo% was %bar%', and the + * parameters are array('foo' => 'one', 'bar' => 'six'), the error message returned will + * be 'message one was six' + * @return string */ - function validateDependencies() + function setErrorMessageTemplate($template) { - return true; + $this->_errorMsgs = $template; } - + + /** - * for package.xml 1.0 only - * @access private + * emulate PEAR::raiseError() + * + * @return PEAR_Error */ - function _validateFilelist() + function raiseError() { - return true; // placeholder for now + require_once 'PEAR.php'; + $args = func_get_args(); + return call_user_func_array(array('PEAR', 'raiseError'), $args); } - - /** - * for package.xml 2.0 only - * @access protected +} +$stack = &PEAR_ErrorStack::singleton('PEAR_ErrorStack'); +$stack->pushCallback(array('PEAR_ErrorStack', '_handleError')); +?> +PEAR-1.9.0/PEAR/Exception.php100664 764 764 33031 100664 10524 + * @author Hans Lellelid + * @author Bertrand Mansion + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Exception.php 276383 2009-02-24 23:39:37Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.3.3 + */ + + +/** + * Base PEAR_Exception Class + * + * 1) Features: + * + * - Nestable exceptions (throw new PEAR_Exception($msg, $prev_exception)) + * - Definable triggers, shot when exceptions occur + * - Pretty and informative error messages + * - Added more context info available (like class, method or cause) + * - cause can be a PEAR_Exception or an array of mixed + * PEAR_Exceptions/PEAR_ErrorStack warnings + * - callbacks for specific exception classes and their children + * + * 2) Ideas: + * + * - Maybe a way to define a 'template' for the output + * + * 3) Inherited properties from PHP Exception Class: + * + * protected $message + * protected $code + * protected $line + * protected $file + * private $trace + * + * 4) Inherited methods from PHP Exception Class: + * + * __clone + * __construct + * getMessage + * getCode + * getFile + * getLine + * getTraceSafe + * getTraceSafeAsString + * __toString + * + * 5) Usage example + * + * + * require_once 'PEAR/Exception.php'; + * + * class Test { + * function foo() { + * throw new PEAR_Exception('Error Message', ERROR_CODE); + * } + * } + * + * function myLogger($pear_exception) { + * echo $pear_exception->getMessage(); + * } + * // each time a exception is thrown the 'myLogger' will be called + * // (its use is completely optional) + * PEAR_Exception::addObserver('myLogger'); + * $test = new Test; + * try { + * $test->foo(); + * } catch (PEAR_Exception $e) { + * print $e; + * } + * + * + * @category pear + * @package PEAR + * @author Tomas V.V.Cox + * @author Hans Lellelid + * @author Bertrand Mansion + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.3.3 + * + */ +class PEAR_Exception extends Exception +{ + const OBSERVER_PRINT = -2; + const OBSERVER_TRIGGER = -4; + const OBSERVER_DIE = -8; + protected $cause; + private static $_observers = array(); + private static $_uniqueid = 0; + private $_trace; + + /** + * Supported signatures: + * - PEAR_Exception(string $message); + * - PEAR_Exception(string $message, int $code); + * - PEAR_Exception(string $message, Exception $cause); + * - PEAR_Exception(string $message, Exception $cause, int $code); + * - PEAR_Exception(string $message, PEAR_Error $cause); + * - PEAR_Exception(string $message, PEAR_Error $cause, int $code); + * - PEAR_Exception(string $message, array $causes); + * - PEAR_Exception(string $message, array $causes, int $code); + * @param string exception message + * @param int|Exception|PEAR_Error|array|null exception cause + * @param int|null exception code or null */ - function validateMainFilelist() + public function __construct($message, $p2 = null, $p3 = null) { - return true; // placeholder for now + if (is_int($p2)) { + $code = $p2; + $this->cause = null; + } elseif (is_object($p2) || is_array($p2)) { + // using is_object allows both Exception and PEAR_Error + if (is_object($p2) && !($p2 instanceof Exception)) { + if (!class_exists('PEAR_Error') || !($p2 instanceof PEAR_Error)) { + throw new PEAR_Exception('exception cause must be Exception, ' . + 'array, or PEAR_Error'); + } + } + $code = $p3; + if (is_array($p2) && isset($p2['message'])) { + // fix potential problem of passing in a single warning + $p2 = array($p2); + } + $this->cause = $p2; + } else { + $code = null; + $this->cause = null; + } + parent::__construct($message, $code); + $this->signal(); } /** - * for package.xml 2.0 only - * @access protected + * @param mixed $callback - A valid php callback, see php func is_callable() + * - A PEAR_Exception::OBSERVER_* constant + * - An array(const PEAR_Exception::OBSERVER_*, + * mixed $options) + * @param string $label The name of the observer. Use this if you want + * to remove it later with removeObserver() */ - function validateReleaseFilelist() + public static function addObserver($callback, $label = 'default') { - return true; // placeholder for now + self::$_observers[$label] = $callback; + } + + public static function removeObserver($label = 'default') + { + unset(self::$_observers[$label]); } /** - * @access protected + * @return int unique identifier for an observer */ - function validateChangelog() + public static function getUniqueId() { - return true; + return self::$_uniqueid++; + } + + private function signal() + { + foreach (self::$_observers as $func) { + if (is_callable($func)) { + call_user_func($func, $this); + continue; + } + settype($func, 'array'); + switch ($func[0]) { + case self::OBSERVER_PRINT : + $f = (isset($func[1])) ? $func[1] : '%s'; + printf($f, $this->getMessage()); + break; + case self::OBSERVER_TRIGGER : + $f = (isset($func[1])) ? $func[1] : E_USER_NOTICE; + trigger_error($this->getMessage(), $f); + break; + case self::OBSERVER_DIE : + $f = (isset($func[1])) ? $func[1] : '%s'; + die(printf($f, $this->getMessage())); + break; + default: + trigger_error('invalid observer type', E_USER_WARNING); + } + } } /** - * @access protected + * Return specific error information that can be used for more detailed + * error messages or translation. + * + * This method may be overridden in child exception classes in order + * to add functionality not present in PEAR_Exception and is a placeholder + * to define API + * + * The returned array must be an associative array of parameter => value like so: + *
+     * array('name' => $name, 'context' => array(...))
+     * 
+ * @return array */ - function validateFilelist() + public function getErrorData() { - return true; + return array(); } /** - * @access protected + * Returns the exception that caused this exception to be thrown + * @access public + * @return Exception|array The context of the exception */ - function validateDeps() + public function getCause() { - return true; + return $this->cause; + } + + /** + * Function must be public to call on caused exceptions + * @param array + */ + public function getCauseMessage(&$causes) + { + $trace = $this->getTraceSafe(); + $cause = array('class' => get_class($this), + 'message' => $this->message, + 'file' => 'unknown', + 'line' => 'unknown'); + if (isset($trace[0])) { + if (isset($trace[0]['file'])) { + $cause['file'] = $trace[0]['file']; + $cause['line'] = $trace[0]['line']; + } + } + $causes[] = $cause; + if ($this->cause instanceof PEAR_Exception) { + $this->cause->getCauseMessage($causes); + } elseif ($this->cause instanceof Exception) { + $causes[] = array('class' => get_class($this->cause), + 'message' => $this->cause->getMessage(), + 'file' => $this->cause->getFile(), + 'line' => $this->cause->getLine()); + } elseif (class_exists('PEAR_Error') && $this->cause instanceof PEAR_Error) { + $causes[] = array('class' => get_class($this->cause), + 'message' => $this->cause->getMessage(), + 'file' => 'unknown', + 'line' => 'unknown'); + } elseif (is_array($this->cause)) { + foreach ($this->cause as $cause) { + if ($cause instanceof PEAR_Exception) { + $cause->getCauseMessage($causes); + } elseif ($cause instanceof Exception) { + $causes[] = array('class' => get_class($cause), + 'message' => $cause->getMessage(), + 'file' => $cause->getFile(), + 'line' => $cause->getLine()); + } elseif (class_exists('PEAR_Error') && $cause instanceof PEAR_Error) { + $causes[] = array('class' => get_class($cause), + 'message' => $cause->getMessage(), + 'file' => 'unknown', + 'line' => 'unknown'); + } elseif (is_array($cause) && isset($cause['message'])) { + // PEAR_ErrorStack warning + $causes[] = array( + 'class' => $cause['package'], + 'message' => $cause['message'], + 'file' => isset($cause['context']['file']) ? + $cause['context']['file'] : + 'unknown', + 'line' => isset($cause['context']['line']) ? + $cause['context']['line'] : + 'unknown', + ); + } + } + } + } + + public function getTraceSafe() + { + if (!isset($this->_trace)) { + $this->_trace = $this->getTrace(); + if (empty($this->_trace)) { + $backtrace = debug_backtrace(); + $this->_trace = array($backtrace[count($backtrace)-1]); + } + } + return $this->_trace; + } + + public function getErrorClass() + { + $trace = $this->getTraceSafe(); + return $trace[0]['class']; + } + + public function getErrorMethod() + { + $trace = $this->getTraceSafe(); + return $trace[0]['function']; + } + + public function __toString() + { + if (isset($_SERVER['REQUEST_URI'])) { + return $this->toHtml(); + } + return $this->toText(); + } + + public function toHtml() + { + $trace = $this->getTraceSafe(); + $causes = array(); + $this->getCauseMessage($causes); + $html = '' . "\n"; + foreach ($causes as $i => $cause) { + $html .= '\n"; + } + $html .= '' . "\n" + . '' + . '' + . '' . "\n"; + + foreach ($trace as $k => $v) { + $html .= '' + . '' + . '' . "\n"; + } + $html .= '' + . '' + . '' . "\n" + . '
' + . str_repeat('-', $i) . ' ' . $cause['class'] . ': ' + . htmlspecialchars($cause['message']) . ' in ' . $cause['file'] . ' ' + . 'on line ' . $cause['line'] . '' + . "
Exception trace
#FunctionLocation
' . $k . ''; + if (!empty($v['class'])) { + $html .= $v['class'] . $v['type']; + } + $html .= $v['function']; + $args = array(); + if (!empty($v['args'])) { + foreach ($v['args'] as $arg) { + if (is_null($arg)) $args[] = 'null'; + elseif (is_array($arg)) $args[] = 'Array'; + elseif (is_object($arg)) $args[] = 'Object('.get_class($arg).')'; + elseif (is_bool($arg)) $args[] = $arg ? 'true' : 'false'; + elseif (is_int($arg) || is_double($arg)) $args[] = $arg; + else { + $arg = (string)$arg; + $str = htmlspecialchars(substr($arg, 0, 16)); + if (strlen($arg) > 16) $str .= '…'; + $args[] = "'" . $str . "'"; + } + } + } + $html .= '(' . implode(', ',$args) . ')' + . '' . (isset($v['file']) ? $v['file'] : 'unknown') + . ':' . (isset($v['line']) ? $v['line'] : 'unknown') + . '
' . ($k+1) . '{main} 
'; + return $html; + } + + public function toText() + { + $causes = array(); + $this->getCauseMessage($causes); + $causeMsg = ''; + foreach ($causes as $i => $cause) { + $causeMsg .= str_repeat(' ', $i) . $cause['class'] . ': ' + . $cause['message'] . ' in ' . $cause['file'] + . ' on line ' . $cause['line'] . "\n"; + } + return $causeMsg . $this->getTraceAsString(); } -}PEAR-1.8.0/PEAR/XMLParser.php100664 764 764 16252 100664 10410 PEAR-1.9.0/PEAR/FixPHP5PEARWarnings.php100664 764 764 231 100664 12066 PEAR-1.9.0/PEAR/Frontend.php100664 764 764 15077 100664 10357 - * @author Stephan Schmidt (original XML_Unserializer code) * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license New BSD License - * @version CVS: $Id: XMLParser.php,v 1.22 2009/03/08 00:45:39 dufuz Exp $ + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Frontend.php 276383 2009-02-24 23:39:37Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since Release 1.4.0a1 */ /** - * Parser for any xml file - * @category pear - * @package PEAR - * @author Greg Beaver - * @author Stephan Schmidt (original XML_Unserializer code) - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 + * Include error handling */ -class PEAR_XMLParser +//require_once 'PEAR.php'; + +/** + * Which user interface class is being used. + * @var string class name + */ +$GLOBALS['_PEAR_FRONTEND_CLASS'] = 'PEAR_Frontend_CLI'; + +/** + * Instance of $_PEAR_Command_uiclass. + * @var object + */ +$GLOBALS['_PEAR_FRONTEND_SINGLETON'] = null; + +/** + * Singleton-based frontend for PEAR user input/output + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Frontend extends PEAR { /** - * unserilialized data - * @var string $_serializedData + * Retrieve the frontend object + * @return PEAR_Frontend_CLI|PEAR_Frontend_Web|PEAR_Frontend_Gtk + * @static */ - var $_unserializedData = null; + function &singleton($type = null) + { + if ($type === null) { + if (!isset($GLOBALS['_PEAR_FRONTEND_SINGLETON'])) { + $a = false; + return $a; + } + return $GLOBALS['_PEAR_FRONTEND_SINGLETON']; + } + + $a = PEAR_Frontend::setFrontendClass($type); + return $a; + } /** - * name of the root tag - * @var string $_root + * Set the frontend class that will be used by calls to {@link singleton()} + * + * Frontends are expected to conform to the PEAR naming standard of + * _ => DIRECTORY_SEPARATOR (PEAR_Frontend_CLI is in PEAR/Frontend/CLI.php) + * @param string $uiclass full class name + * @return PEAR_Frontend + * @static */ - var $_root = null; + function &setFrontendClass($uiclass) + { + if (is_object($GLOBALS['_PEAR_FRONTEND_SINGLETON']) && + is_a($GLOBALS['_PEAR_FRONTEND_SINGLETON'], $uiclass)) { + return $GLOBALS['_PEAR_FRONTEND_SINGLETON']; + } + + if (!class_exists($uiclass)) { + $file = str_replace('_', '/', $uiclass) . '.php'; + if (PEAR_Frontend::isIncludeable($file)) { + include_once $file; + } + } + + if (class_exists($uiclass)) { + $obj = &new $uiclass; + // quick test to see if this class implements a few of the most + // important frontend methods + if (is_a($obj, 'PEAR_Frontend')) { + $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = &$obj; + $GLOBALS['_PEAR_FRONTEND_CLASS'] = $uiclass; + return $obj; + } + + $err = PEAR::raiseError("not a frontend class: $uiclass"); + return $err; + } + + $err = PEAR::raiseError("no such class: $uiclass"); + return $err; + } /** - * stack for all data that is found - * @var array $_dataStack + * Set the frontend class that will be used by calls to {@link singleton()} + * + * Frontends are expected to be a descendant of PEAR_Frontend + * @param PEAR_Frontend + * @return PEAR_Frontend + * @static */ - var $_dataStack = array(); + function &setFrontendObject($uiobject) + { + if (is_object($GLOBALS['_PEAR_FRONTEND_SINGLETON']) && + is_a($GLOBALS['_PEAR_FRONTEND_SINGLETON'], get_class($uiobject))) { + return $GLOBALS['_PEAR_FRONTEND_SINGLETON']; + } + + if (!is_a($uiobject, 'PEAR_Frontend')) { + $err = PEAR::raiseError('not a valid frontend class: (' . + get_class($uiobject) . ')'); + return $err; + } + + $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = &$uiobject; + $GLOBALS['_PEAR_FRONTEND_CLASS'] = get_class($uiobject); + return $uiobject; + } /** - * stack for all values that are generated - * @var array $_valStack + * @param string $path relative or absolute include path + * @return boolean + * @static */ - var $_valStack = array(); + function isIncludeable($path) + { + if (file_exists($path) && is_readable($path)) { + return true; + } + + $fp = @fopen($path, 'r', true); + if ($fp) { + fclose($fp); + return true; + } + + return false; + } /** - * current tag depth - * @var int $_depth + * @param PEAR_Config */ - var $_depth = 0; + function setConfig(&$config) + { + } /** - * The XML encoding to use - * @var string $encoding + * This can be overridden to allow session-based temporary file management + * + * By default, all files are deleted at the end of a session. The web installer + * needs to be able to sustain a list over many sessions in order to support + * user interaction with install scripts */ - var $encoding = 'ISO-8859-1'; + function addTempFile($file) + { + $GLOBALS['_PEAR_Common_tempfiles'][] = $file; + } /** - * @return array + * Log an action + * + * @param string $msg the message to log + * @param boolean $append_crlf + * @return boolean true + * @abstract */ - function getData() + function log($msg, $append_crlf = true) { - return $this->_unserializedData; } /** - * @param string xml content - * @return true|PEAR_Error + * Run a post-installation script + * + * @param array $scripts array of post-install scripts + * @abstract */ - function parse($data) + function runPostinstallScripts(&$scripts) { - if (!extension_loaded('xml')) { - include_once 'PEAR.php'; - return PEAR::raiseError("XML Extension not found", 1); - } - $this->_valStack = array(); - $this->_dataStack = array(); - $this->_depth = 0; - - if ( - strpos($data, 'encoding="UTF-8"') - || strpos($data, 'encoding="utf-8"') - || strpos($data, "encoding='UTF-8'") - || strpos($data, "encoding='utf-8'") - ) { - $this->encoding = 'UTF-8'; - } - - if (version_compare(phpversion(), '5.0.0', 'lt') && $this->encoding == 'UTF-8') { - $data = utf8_decode($data); - } + } - $xp = xml_parser_create($this->encoding); - xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, 0); - xml_set_object($xp, $this); - xml_set_element_handler($xp, 'startHandler', 'endHandler'); - xml_set_character_data_handler($xp, 'cdataHandler'); - if (!xml_parse($xp, $data)) { - $msg = xml_error_string(xml_get_error_code($xp)); - $line = xml_get_current_line_number($xp); - xml_parser_free($xp); - include_once 'PEAR.php'; - return PEAR::raiseError("XML Error: '$msg' on line '$line'", 2); - } - xml_parser_free($xp); - return true; + /** + * Display human-friendly output formatted depending on the + * $command parameter. + * + * This should be able to handle basic output data with no command + * @param mixed $data data structure containing the information to display + * @param string $command command from which this method was called + * @abstract + */ + function outputData($data, $command = '_default') + { } /** - * Start element handler for XML parser + * Display a modal form dialog and return the given input * - * @access private - * @param object $parser XML parser object - * @param string $element XML element - * @param array $attribs attributes of XML tag - * @return void + * A frontend that requires multiple requests to retrieve and process + * data must take these needs into account, and implement the request + * handling code. + * @param string $command command from which this method was called + * @param array $prompts associative array. keys are the input field names + * and values are the description + * @param array $types array of input field types (text, password, + * etc.) keys have to be the same like in $prompts + * @param array $defaults array of default values. again keys have + * to be the same like in $prompts. Do not depend + * on a default value being set. + * @return array input sent by the user + * @abstract */ - function startHandler($parser, $element, $attribs) + function userDialog($command, $prompts, $types = array(), $defaults = array()) { - $type = 'string'; + } +}PEAR-1.9.0/PEAR/Installer.php100664 764 764 210603 100664 10545 + * @author Tomas V.V. Cox + * @author Martin Jansen + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Installer.php 287446 2009-08-18 11:45:05Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ - $this->_depth++; - $this->_dataStack[$this->_depth] = null; +/** + * Used for installation groups in package.xml 2.0 and platform exceptions + */ +require_once 'OS/Guess.php'; +require_once 'PEAR/Downloader.php'; - $val = array( - 'name' => $element, - 'value' => null, - 'type' => $type, - 'childrenKeys' => array(), - 'aggregKeys' => array() - ); +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 + * @author Tomas V.V. Cox + * @author Martin Jansen + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Installer extends PEAR_Downloader +{ + // {{{ properties - if (count($attribs) > 0) { - $val['children'] = array(); - $val['type'] = 'array'; + /** name of the package directory, for example Foo-1.0 + * @var string + */ + var $pkgdir; - $val['children']['attribs'] = $attribs; + /** directory where PHP code files go + * @var string + */ + var $phpdir; - } + /** directory where PHP extension files go + * @var string + */ + var $extdir; - array_push($this->_valStack, $val); - } + /** 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; /** - * post-process data - * - * @param string $data - * @param string $element element name + * PEAR_Registry object used by the installer + * @var PEAR_Registry */ - function postProcess($data, $element) - { - return trim($data); - } + var $registry; /** - * End element handler for XML parser + * array of PEAR_Downloader_Packages + * @var array + */ + var $_downloadedPackages; + + /** List of file transactions queued for an install/upgrade/uninstall. * - * @access private - * @param object XML parser object - * @param string - * @return void + * Format: + * array( + * 0 => array("rename => array("from-file", "to-file")), + * 1 => array("delete" => array("file-to-delete")), + * ... + * ) + * + * @var array */ - function endHandler($parser, $element) - { - $value = array_pop($this->_valStack); - $data = $this->postProcess($this->_dataStack[$this->_depth], $element); + var $file_operations = array(); - // adjust type of the value - switch(strtolower($value['type'])) { + // }}} - // unserialize an array - case 'array': - if ($data !== '') { - $value['children']['_content'] = $data; - } - if (isset($value['children'])) { - $value['value'] = $value['children']; - } else { - $value['value'] = array(); - } - break; + // {{{ constructor - /* - * unserialize a null value - */ - case 'null': - $data = null; - break; + /** + * PEAR_Installer constructor. + * + * @param object $ui user interface object (instance of PEAR_Frontend_*) + * + * @access public + */ + function PEAR_Installer(&$ui) + { + parent::PEAR_Common(); + $this->setFrontendObject($ui); + $this->debug = $this->config->get('verbose'); + } - /* - * unserialize any scalar value - */ - default: - settype($data, $value['type']); - $value['value'] = $data; - break; - } + function setOptions($options) + { + $this->_options = $options; + } - $parent = array_pop($this->_valStack); - if ($parent === null) { - $this->_unserializedData = &$value['value']; - $this->_root = &$value['name']; - return true; - } + function setConfig(&$config) + { + $this->config = &$config; + $this->_registry = &$config->getRegistry(); + } - // parent has to be an array - if (!isset($parent['children']) || !is_array($parent['children'])) { - $parent['children'] = array(); - if ($parent['type'] != 'array') { - $parent['type'] = 'array'; - } - } + // }}} - if (!empty($value['name'])) { - // there already has been a tag with this name - if (in_array($value['name'], $parent['childrenKeys'])) { - // no aggregate has been created for this tag - if (!in_array($value['name'], $parent['aggregKeys'])) { - if (isset($parent['children'][$value['name']])) { - $parent['children'][$value['name']] = array($parent['children'][$value['name']]); - } else { - $parent['children'][$value['name']] = array(); - } - array_push($parent['aggregKeys'], $value['name']); - } - array_push($parent['children'][$value['name']], $value['value']); - } else { - $parent['children'][$value['name']] = &$value['value']; - array_push($parent['childrenKeys'], $value['name']); - } - } else { - array_push($parent['children'],$value['value']); + function _removeBackups($files) + { + foreach ($files as $path) { + $this->addFileOperation('removebackup', array($path)); } - array_push($this->_valStack, $parent); - - $this->_depth--; } + // {{{ _deletePackageFiles() + /** - * Handler for character data + * Delete a package's installed files, does not remove empty directories. * - * @access private - * @param object XML parser object - * @param string CDATA - * @return void + * @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 cdataHandler($parser, $cdata) + function _deletePackageFiles($package, $channel = false, $backup = false) { - $this->_dataStack[$this->_depth] .= $cdata; - } -}PEAR-1.8.0/scripts/pear.bat100777 764 764 11102 100777 10440 @ECHO OFF - -REM ---------------------------------------------------------------------- -REM PHP version 5 -REM ---------------------------------------------------------------------- -REM Copyright (c) 1997-2004 The PHP Group -REM ---------------------------------------------------------------------- -REM This source file is subject to version 3.0 of the PHP license, -REM that is bundled with this package in the file LICENSE, and is -REM available at through the world-wide-web at -REM http://www.php.net/license/3_0.txt. -REM If you did not receive a copy of the PHP license and are unable to -REM obtain it through the world-wide-web, please send a note to -REM license@php.net so we can mail you a copy immediately. -REM ---------------------------------------------------------------------- -REM Authors: Alexander Merz (alexmerz@php.net) -REM ---------------------------------------------------------------------- -REM -REM Last updated 12/29/2004 ($Id$ is not replaced if the file is binary) - -REM change this lines to match the paths of your system -REM ------------------- - - -REM Test to see if this is a raw pear.bat (uninstalled version) -SET TMPTMPTMPTMPT=@includ -SET PMTPMTPMT=%TMPTMPTMPTMPT%e_path@ -FOR %%x IN ("@include_path@") DO (if %%x=="%PMTPMTPMT%" GOTO :NOTINSTALLED) - -REM Check PEAR global ENV, set them if they do not exist -IF "%PHP_PEAR_INSTALL_DIR%"=="" SET "PHP_PEAR_INSTALL_DIR=@include_path@" -IF "%PHP_PEAR_BIN_DIR%"=="" SET "PHP_PEAR_BIN_DIR=@bin_dir@" -IF "%PHP_PEAR_PHP_BIN%"=="" SET "PHP_PEAR_PHP_BIN=@php_bin@" -GOTO :INSTALLED - -:NOTINSTALLED -ECHO WARNING: This is a raw, uninstalled pear.bat - -REM Check to see if we can grab the directory of this file (Windows NT+) -IF %~n0 == pear ( -FOR %%x IN (cli\php.exe php.exe) DO (if "%%~$PATH:x" NEQ "" ( -SET "PHP_PEAR_PHP_BIN=%%~$PATH:x" -echo Using PHP Executable "%PHP_PEAR_PHP_BIN%" -"%PHP_PEAR_PHP_BIN%" -v -GOTO :NEXTTEST -)) -GOTO :FAILAUTODETECT -:NEXTTEST -IF "%PHP_PEAR_PHP_BIN%" NEQ "" ( - -REM We can use this PHP to run a temporary php file to get the dirname of pear - -echo ^ > ~~getloc.php -"%PHP_PEAR_PHP_BIN%" ~~getloc.php -set /p PHP_PEAR_BIN_DIR=fakeprompt < ~a.a -DEL ~a.a -DEL ~~getloc.php -set "PHP_PEAR_INSTALL_DIR=%PHP_PEAR_BIN_DIR%pear" - -REM Make sure there is a pearcmd.php at our disposal - -IF NOT EXIST %PHP_PEAR_INSTALL_DIR%\pearcmd.php ( -IF EXIST %PHP_PEAR_INSTALL_DIR%\scripts\pearcmd.php COPY %PHP_PEAR_INSTALL_DIR%\scripts\pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php -IF EXIST pearcmd.php COPY pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php -IF EXIST %~dp0\scripts\pearcmd.php COPY %~dp0\scripts\pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php -) -) -GOTO :INSTALLED -) ELSE ( -REM Windows Me/98 cannot succeed, so allow the batch to fail -) -:FAILAUTODETECT -echo WARNING: failed to auto-detect pear information -:INSTALLED - -REM Check Folders and files -IF NOT EXIST "%PHP_PEAR_INSTALL_DIR%" GOTO PEAR_INSTALL_ERROR -IF NOT EXIST "%PHP_PEAR_INSTALL_DIR%\pearcmd.php" GOTO PEAR_INSTALL_ERROR2 -IF NOT EXIST "%PHP_PEAR_BIN_DIR%" GOTO PEAR_BIN_ERROR -IF NOT EXIST "%PHP_PEAR_PHP_BIN%" GOTO PEAR_PHPBIN_ERROR -REM launch pearcmd -GOTO RUN -:PEAR_INSTALL_ERROR -ECHO PHP_PEAR_INSTALL_DIR is not set correctly. -ECHO Please fix it using your environment variable or modify -ECHO the default value in pear.bat -ECHO The current value is: -ECHO %PHP_PEAR_INSTALL_DIR% -GOTO END -:PEAR_INSTALL_ERROR2 -ECHO PHP_PEAR_INSTALL_DIR is not set correctly. -ECHO pearcmd.php could not be found there. -ECHO Please fix it using your environment variable or modify -ECHO the default value in pear.bat -ECHO The current value is: -ECHO %PHP_PEAR_INSTALL_DIR% -GOTO END -:PEAR_BIN_ERROR -ECHO PHP_PEAR_BIN_DIR is not set correctly. -ECHO Please fix it using your environment variable or modify -ECHO the default value in pear.bat -ECHO The current value is: -ECHO %PHP_PEAR_BIN_DIR% -GOTO END -:PEAR_PHPBIN_ERROR -ECHO PHP_PEAR_PHP_BIN is not set correctly. -ECHO Please fix it using your environment variable or modify -ECHO the default value in pear.bat -ECHO The current value is: -ECHO %PHP_PEAR_PHP_BIN% -GOTO END -:RUN -"%PHP_PEAR_PHP_BIN%" -C -d output_buffering=1 -d safe_mode=0 -d open_basedir="" -d auto_prepend_file="" -d auto_append_file="" -d variables_order=EGPCS -d register_argc_argv="On" -d include_path="%PHP_PEAR_INSTALL_DIR%" -f "%PHP_PEAR_INSTALL_DIR%\pearcmd.php" -- %1 %2 %3 %4 %5 %6 %7 %8 %9 -:END -@ECHO ONPEAR-1.8.0/scripts/peardev.bat100777 764 764 11112 100777 11140 @ECHO OFF - -REM ---------------------------------------------------------------------- -REM PHP version 5 -REM ---------------------------------------------------------------------- -REM Copyright (c) 1997-2004 The PHP Group -REM ---------------------------------------------------------------------- -REM This source file is subject to version 3.0 of the PHP license, -REM that is bundled with this package in the file LICENSE, and is -REM available at through the world-wide-web at -REM http://www.php.net/license/3_0.txt. -REM If you did not receive a copy of the PHP license and are unable to -REM obtain it through the world-wide-web, please send a note to -REM license@php.net so we can mail you a copy immediately. -REM ---------------------------------------------------------------------- -REM Authors: Alexander Merz (alexmerz@php.net) -REM ---------------------------------------------------------------------- -REM -REM $Id: peardev.bat,v 1.6 2007/09/03 03:00:17 cellog Exp $ - -REM change this lines to match the paths of your system -REM ------------------- - - -REM Test to see if this is a raw pear.bat (uninstalled version) -SET TMPTMPTMPTMPT=@includ -SET PMTPMTPMT=%TMPTMPTMPTMPT%e_path@ -FOR %%x IN ("@include_path@") DO (if %%x=="%PMTPMTPMT%" GOTO :NOTINSTALLED) - -REM Check PEAR global ENV, set them if they do not exist -IF "%PHP_PEAR_INSTALL_DIR%"=="" SET "PHP_PEAR_INSTALL_DIR=@include_path@" -IF "%PHP_PEAR_BIN_DIR%"=="" SET "PHP_PEAR_BIN_DIR=@bin_dir@" -IF "%PHP_PEAR_PHP_BIN%"=="" SET "PHP_PEAR_PHP_BIN=@php_bin@" -GOTO :INSTALLED - -:NOTINSTALLED -ECHO WARNING: This is a raw, uninstalled pear.bat - -REM Check to see if we can grab the directory of this file (Windows NT+) -IF %~n0 == pear ( -FOR %%x IN (cli\php.exe php.exe) DO (if "%%~$PATH:x" NEQ "" ( -SET "PHP_PEAR_PHP_BIN=%%~$PATH:x" -echo Using PHP Executable "%PHP_PEAR_PHP_BIN%" -"%PHP_PEAR_PHP_BIN%" -v -GOTO :NEXTTEST -)) -GOTO :FAILAUTODETECT -:NEXTTEST -IF "%PHP_PEAR_PHP_BIN%" NEQ "" ( - -REM We can use this PHP to run a temporary php file to get the dirname of pear - -echo ^ > ~~getloc.php -"%PHP_PEAR_PHP_BIN%" ~~getloc.php -set /p PHP_PEAR_BIN_DIR=fakeprompt < ~a.a -DEL ~a.a -DEL ~~getloc.php -set "PHP_PEAR_INSTALL_DIR=%PHP_PEAR_BIN_DIR%pear" - -REM Make sure there is a pearcmd.php at our disposal - -IF NOT EXIST %PHP_PEAR_INSTALL_DIR%\pearcmd.php ( -IF EXIST %PHP_PEAR_INSTALL_DIR%\scripts\pearcmd.php COPY %PHP_PEAR_INSTALL_DIR%\scripts\pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php -IF EXIST pearcmd.php COPY pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php -IF EXIST %~dp0\scripts\pearcmd.php COPY %~dp0\scripts\pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php -) -) -GOTO :INSTALLED -) ELSE ( -REM Windows Me/98 cannot succeed, so allow the batch to fail -) -:FAILAUTODETECT -echo WARNING: failed to auto-detect pear information -:INSTALLED - -REM Check Folders and files -IF NOT EXIST "%PHP_PEAR_INSTALL_DIR%" GOTO PEAR_INSTALL_ERROR -IF NOT EXIST "%PHP_PEAR_INSTALL_DIR%\pearcmd.php" GOTO PEAR_INSTALL_ERROR2 -IF NOT EXIST "%PHP_PEAR_BIN_DIR%" GOTO PEAR_BIN_ERROR -IF NOT EXIST "%PHP_PEAR_PHP_BIN%" GOTO PEAR_PHPBIN_ERROR -REM launch pearcmd -GOTO RUN -:PEAR_INSTALL_ERROR -ECHO PHP_PEAR_INSTALL_DIR is not set correctly. -ECHO Please fix it using your environment variable or modify -ECHO the default value in pear.bat -ECHO The current value is: -ECHO %PHP_PEAR_INSTALL_DIR% -GOTO END -:PEAR_INSTALL_ERROR2 -ECHO PHP_PEAR_INSTALL_DIR is not set correctly. -ECHO pearcmd.php could not be found there. -ECHO Please fix it using your environment variable or modify -ECHO the default value in pear.bat -ECHO The current value is: -ECHO %PHP_PEAR_INSTALL_DIR% -GOTO END -:PEAR_BIN_ERROR -ECHO PHP_PEAR_BIN_DIR is not set correctly. -ECHO Please fix it using your environment variable or modify -ECHO the default value in pear.bat -ECHO The current value is: -ECHO %PHP_PEAR_BIN_DIR% -GOTO END -:PEAR_PHPBIN_ERROR -ECHO PHP_PEAR_PHP_BIN is not set correctly. -ECHO Please fix it using your environment variable or modify -ECHO the default value in pear.bat -ECHO The current value is: -ECHO %PHP_PEAR_PHP_BIN% -GOTO END -:RUN -"%PHP_PEAR_PHP_BIN%" -C -d memory_limit="-1" -d safe_mode=0 -d register_argc_argv="On" -d auto_prepend_file="" -d auto_append_file="" -d variables_order=EGPCS -d open_basedir="" -d output_buffering=1 -d include_path="%PHP_PEAR_INSTALL_DIR%" -f "%PHP_PEAR_INSTALL_DIR%\pearcmd.php" -- %1 %2 %3 %4 %5 %6 %7 %8 %9 -:END -@ECHO ONPEAR-1.8.0/scripts/pecl.bat100777 764 764 11003 100777 10434 @ECHO OFF - -REM ---------------------------------------------------------------------- -REM PHP version 5 -REM ---------------------------------------------------------------------- -REM Copyright (c) 1997-2004 The PHP Group -REM ---------------------------------------------------------------------- -REM This source file is subject to version 3.0 of the PHP license, -REM that is bundled with this package in the file LICENSE, and is -REM available at through the world-wide-web at -REM http://www.php.net/license/3_0.txt. -REM If you did not receive a copy of the PHP license and are unable to -REM obtain it through the world-wide-web, please send a note to -REM license@php.net so we can mail you a copy immediately. -REM ---------------------------------------------------------------------- -REM Authors: Alexander Merz (alexmerz@php.net) -REM ---------------------------------------------------------------------- -REM -REM Last updated 02/08/2004 ($Id$ is not replaced if the file is binary) - -REM change this lines to match the paths of your system -REM ------------------- - - -REM Test to see if this is a raw pear.bat (uninstalled version) -SET TMPTMPTMPTMPT=@includ -SET PMTPMTPMT=%TMPTMPTMPTMPT%e_path@ -FOR %%x IN ("@include_path@") DO (if %%x=="%PMTPMTPMT%" GOTO :NOTINSTALLED) - -REM Check PEAR global ENV, set them if they do not exist -IF "%PHP_PEAR_INSTALL_DIR%"=="" SET "PHP_PEAR_INSTALL_DIR=@include_path@" -IF "%PHP_PEAR_BIN_DIR%"=="" SET "PHP_PEAR_BIN_DIR=@bin_dir@" -IF "%PHP_PEAR_PHP_BIN%"=="" SET "PHP_PEAR_PHP_BIN=@php_bin@" -GOTO :INSTALLED - -:NOTINSTALLED -ECHO WARNING: This is a raw, uninstalled pear.bat - -REM Check to see if we can grab the directory of this file (Windows NT+) -IF %~n0 == pear ( -FOR %%x IN (cli\php.exe php.exe) DO (if "%%~$PATH:x" NEQ "" ( -SET "PHP_PEAR_PHP_BIN=%%~$PATH:x" -echo Using PHP Executable "%PHP_PEAR_PHP_BIN%" -"%PHP_PEAR_PHP_BIN%" -v -GOTO :NEXTTEST -)) -GOTO :FAILAUTODETECT -:NEXTTEST -IF "%PHP_PEAR_PHP_BIN%" NEQ "" ( - -REM We can use this PHP to run a temporary php file to get the dirname of pear - -echo ^ > ~~getloc.php -"%PHP_PEAR_PHP_BIN%" ~~getloc.php -set /p PHP_PEAR_BIN_DIR=fakeprompt < ~a.a -DEL ~a.a -DEL ~~getloc.php -set "PHP_PEAR_INSTALL_DIR=%PHP_PEAR_BIN_DIR%pear" - -REM Make sure there is a pearcmd.php at our disposal - -IF NOT EXIST %PHP_PEAR_INSTALL_DIR%\pearcmd.php ( -IF EXIST %PHP_PEAR_INSTALL_DIR%\scripts\pearcmd.php COPY %PHP_PEAR_INSTALL_DIR%\scripts\pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php -IF EXIST pearcmd.php COPY pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php -IF EXIST %~dp0\scripts\pearcmd.php COPY %~dp0\scripts\pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php -) -) -GOTO :INSTALLED -) ELSE ( -REM Windows Me/98 cannot succeed, so allow the batch to fail -) -:FAILAUTODETECT -echo WARNING: failed to auto-detect pear information -:INSTALLED - -REM Check Folders and files -IF NOT EXIST "%PHP_PEAR_INSTALL_DIR%" GOTO PEAR_INSTALL_ERROR -IF NOT EXIST "%PHP_PEAR_INSTALL_DIR%\pearcmd.php" GOTO PEAR_INSTALL_ERROR2 -IF NOT EXIST "%PHP_PEAR_BIN_DIR%" GOTO PEAR_BIN_ERROR -IF NOT EXIST "%PHP_PEAR_PHP_BIN%" GOTO PEAR_PHPBIN_ERROR -REM launch pearcmd -GOTO RUN -:PEAR_INSTALL_ERROR -ECHO PHP_PEAR_INSTALL_DIR is not set correctly. -ECHO Please fix it using your environment variable or modify -ECHO the default value in pear.bat -ECHO The current value is: -ECHO %PHP_PEAR_INSTALL_DIR% -GOTO END -:PEAR_INSTALL_ERROR2 -ECHO PHP_PEAR_INSTALL_DIR is not set correctly. -ECHO pearcmd.php could not be found there. -ECHO Please fix it using your environment variable or modify -ECHO the default value in pear.bat -ECHO The current value is: -ECHO %PHP_PEAR_INSTALL_DIR% -GOTO END -:PEAR_BIN_ERROR -ECHO PHP_PEAR_BIN_DIR is not set correctly. -ECHO Please fix it using your environment variable or modify -ECHO the default value in pear.bat -ECHO The current value is: -ECHO %PHP_PEAR_BIN_DIR% -GOTO END -:PEAR_PHPBIN_ERROR -ECHO PHP_PEAR_PHP_BIN is not set correctly. -ECHO Please fix it using your environment variable or modify -ECHO the default value in pear.bat -ECHO The current value is: -ECHO %PHP_PEAR_PHP_BIN% -GOTO END -:RUN -"%PHP_PEAR_PHP_BIN%" -C -n -d output_buffering=1 -d safe_mode=0 -d include_path="%PHP_PEAR_INSTALL_DIR%" -d register_argc_argv="On" -d variables_order=EGPCS -f "%PHP_PEAR_INSTALL_DIR%\peclcmd.php" -- %1 %2 %3 %4 %5 %6 %7 %8 %9 -:END -@ECHO ONPEAR-1.8.0/scripts/pear.sh100777 764 764 1362 100777 10273 #!/bin/sh - -# first find which PHP binary to use -if test "x$PHP_PEAR_PHP_BIN" != "x"; then - PHP="$PHP_PEAR_PHP_BIN" -else - if test "@php_bin@" = '@'php_bin'@'; then - PHP=php - else - PHP="@php_bin@" - fi -fi + if (!$channel) { + $channel = 'pear.php.net'; + } -# then look for the right pear include dir -if test "x$PHP_PEAR_INSTALL_DIR" != "x"; then - INCDIR=$PHP_PEAR_INSTALL_DIR - INCARG="-d include_path=$PHP_PEAR_INSTALL_DIR" -else - if test "@php_dir@" = '@'php_dir'@'; then - INCDIR=`dirname $0` - INCARG="" - else - INCDIR="@php_dir@" - INCARG="-d include_path=@php_dir@" - fi -fi + if (!strlen($package)) { + return $this->raiseError("No package to uninstall given"); + } -exec $PHP -C -q $INCARG -d output_buffering=1 -d variables_order=EGPCS -d open_basedir="" -d safe_mode=0 -d register_argc_argv="On" -d auto_prepend_file="" -d auto_append_file="" $INCDIR/pearcmd.php "$@" -PEAR-1.8.0/scripts/peardev.sh100777 764 764 1407 100777 10772 #!/bin/sh + 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'; + } -# first find which PHP binary to use -if test "x$PHP_PEAR_PHP_BIN" != "x"; then - PHP="$PHP_PEAR_PHP_BIN" -else - if test "@php_bin@" = '@'php_bin'@'; then - PHP=php - else - PHP="@php_bin@" - fi -fi + $filelist = $this->_registry->packageInfo($package, 'filelist', $channel); + if ($filelist == null) { + return $this->raiseError("$channel/$package not installed"); + } -# then look for the right pear include dir -if test "x$PHP_PEAR_INSTALL_DIR" != "x"; then - INCDIR=$PHP_PEAR_INSTALL_DIR - INCARG="-d include_path=$PHP_PEAR_INSTALL_DIR" -else - if test "@php_dir@" = '@'php_dir'@'; then - INCDIR=`dirname $0` - INCARG="" - else - INCDIR="@php_dir@" - INCARG="-d include_path=@php_dir@" - fi -fi + $ret = array(); + foreach ($filelist as $file => $props) { + if (empty($props['installed_as'])) { + continue; + } -exec $PHP -d memory_limit="-1" -C -q $INCARG -d output_buffering=1 -d open_basedir="" -d safe_mode=0 -d register_argc_argv="On" -d auto_prepend_file="" -d variables_order=EGPCS -d auto_append_file="" $INCDIR/pearcmd.php "$@" -PEAR-1.8.0/scripts/pecl.sh100777 764 764 1263 100777 10267 #!/bin/sh + $path = $props['installed_as']; + if ($backup) { + $this->addFileOperation('backup', array($path)); + $ret[] = $path; + } -# first find which PHP binary to use -if test "x$PHP_PEAR_PHP_BIN" != "x"; then - PHP="$PHP_PEAR_PHP_BIN" -else - if test "@php_bin@" = '@'php_bin'@'; then - PHP=php - else - PHP="@php_bin@" - fi -fi + $this->addFileOperation('delete', array($path)); + } -# then look for the right pear include dir -if test "x$PHP_PEAR_INSTALL_DIR" != "x"; then - INCDIR=$PHP_PEAR_INSTALL_DIR - INCARG="-d include_path=$PHP_PEAR_INSTALL_DIR" -else - if test "@php_dir@" = '@'php_dir'@'; then - INCDIR=`dirname $0` - INCARG="" - else - INCDIR="@php_dir@" - INCARG="-d include_path=@php_dir@" - fi -fi + if ($backup) { + return $ret; + } -exec $PHP -C -n -q $INCARG -d output_buffering=1 -d variables_order=EGPCS -d safe_mode=0 -d register_argc_argv="On" $INCDIR/peclcmd.php "$@" -PEAR-1.8.0/scripts/pearcmd.php100664 764 764 34617 100664 11153 - * @author Tomas V.V.Cox - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: pearcmd.php,v 1.41 2009/03/04 20:05:56 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - */ + return true; + } -ob_end_clean(); -if (!defined('PEAR_RUNTYPE')) { - // this is defined in peclcmd.php as 'pecl' - define('PEAR_RUNTYPE', 'pear'); -} -define('PEAR_IGNORE_BACKTRACE', 1); -/** - * @nodep Gtk - */ -if ('@include_path@' != '@'.'include_path'.'@') { - ini_set('include_path', '@include_path@'); - $raw = false; -} else { - // this is a raw, uninstalled pear, either a cvs checkout, or php distro - $raw = true; -} -@ini_set('allow_url_fopen', true); -if (!ini_get('safe_mode')) { - @set_time_limit(0); -} -ob_implicit_flush(true); -@ini_set('track_errors', true); -@ini_set('html_errors', false); -@ini_set('magic_quotes_runtime', false); -$_PEAR_PHPDIR = '#$%^&*'; -set_error_handler('error_handler'); + // }}} + // {{{ _installFile() -$pear_package_version = "@pear_version@"; + /** + * @param string filename + * @param array attributes from 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(); + } -require_once 'PEAR.php'; -require_once 'PEAR/Frontend.php'; -require_once 'PEAR/Config.php'; -require_once 'PEAR/Command.php'; -require_once 'Console/Getopt.php'; + 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']; + } -PEAR_Command::setFrontendType('CLI'); -$all_commands = PEAR_Command::getCommands(); + if ((bool) $os->matchSignature($platform) === $negate) { + $this->log(3, "skipped $file (meant for $atts[platform], we are ".$os->getSignature().")"); + return PEAR_INSTALLER_SKIPPED; + } + } + // }}} -// remove this next part when we stop supporting that crap-ass PHP 4.2 -if (!isset($_SERVER['argv']) && !isset($argv) && !isset($HTTP_SERVER_VARS['argv'])) { - echo 'ERROR: either use the CLI php executable, or set register_argc_argv=On in php.ini'; - exit(1); -} -$argv = Console_Getopt::readPHPArgv(); -// fix CGI sapi oddity - the -- in pear.bat/pear is not removed -if (php_sapi_name() != 'cli' && isset($argv[1]) && $argv[1] == '--') { - unset($argv[1]); - $argv = array_values($argv); -} -$progname = PEAR_RUNTYPE; -if (in_array('getopt2', get_class_methods('Console_Getopt'))) { - array_shift($argv); - $options = Console_Getopt::getopt2($argv, "c:C:d:D:Gh?sSqu:vV"); -} else { - $options = Console_Getopt::getopt($argv, "c:C:d:D:Gh?sSqu:vV"); -} -if (PEAR::isError($options)) { - usage($options); -} + $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"); + } -$opts = $options[0]; + $save_destdir = $dest_dir; + if (!empty($atts['baseinstalldir'])) { + $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir']; + } -$fetype = 'CLI'; -if ($progname == 'gpear' || $progname == 'pear-gtk') { - $fetype = 'Gtk'; -} else { - foreach ($opts as $opt) { - if ($opt[0] == 'G') { - $fetype = 'Gtk'; + if (dirname($file) != '.' && empty($atts['install-as'])) { + $dest_dir .= DIRECTORY_SEPARATOR . dirname($file); } - } -} -//Check if Gtk and PHP >= 5.1.0 -if ($fetype == 'Gtk' && version_compare(phpversion(), '5.1.0', '>=')) { - $fetype = 'Gtk2'; -} -$pear_user_config = ''; -$pear_system_config = ''; -$store_user_config = false; -$store_system_config = false; -$verbose = 1; + 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; -foreach ($opts as $opt) { - switch ($opt[0]) { - case 'c': - $pear_user_config = $opt[1]; - break; - case 'C': - $pear_system_config = $opt[1]; - break; - } -} + // 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); + } -PEAR_Command::setFrontendType($fetype); -$ui = &PEAR_Command::getFrontendObject(); -$config = &PEAR_Config::singleton($pear_user_config, $pear_system_config); + $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 (PEAR::isError($config)) { - $_file = ''; - if ($pear_user_config !== false) { - $_file .= $pear_user_config; - } - if ($pear_system_config !== false) { - $_file .= '/' . $pear_system_config; - } - if ($_file == '/') { - $_file = 'The default config file'; - } - $config->getMessage(); - $ui->outputData("ERROR: $_file is not a valid config file or is corrupted."); - // We stop, we have no idea where we are :) - exit(1); -} + 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"); + } -// this is used in the error handler to retrieve a relative path -$_PEAR_PHPDIR = $config->get('php_dir'); -$ui->setConfig($config); -PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, array($ui, "displayFatalError")); -if (ini_get('safe_mode')) { - $ui->outputData('WARNING: running in safe mode requires that all files created ' . - 'be the same uid as the current script. PHP reports this script is uid: ' . - @getmyuid() . ', and current user is: ' . @get_current_user()); -} + // 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); + } -$verbose = $config->get("verbose"); -$cmdopts = array(); + if (!@copy($orig_file, $dest_file)) { + return $this->raiseError("failed to write $dest_file: $php_errormsg", + PEAR_INSTALLER_FAILED); + } -if ($raw) { - if (!$config->isDefinedLayer('user') && !$config->isDefinedLayer('system')) { - $found = false; - foreach ($opts as $opt) { - if ($opt[0] == 'd' || $opt[0] == 'D') { - $found = true; // the user knows what they are doing, and are setting config values - } - } - if (!$found) { - // no prior runs, try to install PEAR - if (strpos(dirname(__FILE__), 'scripts')) { - $packagexml = dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'package2.xml'; - $pearbase = dirname(dirname(__FILE__)); + $this->log(3, "+ cp $orig_file $dest_file"); + if (isset($atts['md5sum'])) { + $md5sum = md5_file($dest_file); + } } else { - $packagexml = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'package2.xml'; - $pearbase = dirname(__FILE__); - } - if (file_exists($packagexml)) { - $options[1] = array( - 'install', - $packagexml - ); - $config->set('php_dir', $pearbase . DIRECTORY_SEPARATOR . 'php'); - $config->set('data_dir', $pearbase . DIRECTORY_SEPARATOR . 'data'); - $config->set('doc_dir', $pearbase . DIRECTORY_SEPARATOR . 'docs'); - $config->set('test_dir', $pearbase . DIRECTORY_SEPARATOR . 'tests'); - $config->set('ext_dir', $pearbase . DIRECTORY_SEPARATOR . 'extensions'); - $config->set('bin_dir', $pearbase); - $config->mergeConfigFile($pearbase . 'pear.ini', false); - $config->store(); - $config->set('auto_discover', 1); - } - } - } -} -foreach ($opts as $opt) { - $param = !empty($opt[1]) ? $opt[1] : true; - switch ($opt[0]) { - case 'd': - if ($param === true) { - die('Invalid usage of "-d" option, expected -d config_value=value, ' . - 'received "-d"' . "\n"); - } - $possible = explode('=', $param); - if (count($possible) != 2) { - die('Invalid usage of "-d" option, expected -d config_value=value, received "' . - $param . '"' . "\n"); - } - list($key, $value) = explode('=', $param); - $config->set($key, $value, 'user'); - break; - case 'D': - if ($param === true) { - die('Invalid usage of "-d" option, expected -d config_value=value, ' . - 'received "-d"' . "\n"); - } - $possible = explode('=', $param); - if (count($possible) != 2) { - die('Invalid usage of "-d" option, expected -d config_value=value, received "' . - $param . '"' . "\n"); - } - list($key, $value) = explode('=', $param); - $config->set($key, $value, 'system'); - break; - case 's': - $store_user_config = true; - break; - case 'S': - $store_system_config = true; - break; - case 'u': - $config->remove($param, 'user'); - break; - case 'v': - $config->set('verbose', $config->get('verbose') + 1); - break; - case 'q': - $config->set('verbose', $config->get('verbose') - 1); - break; - case 'V': - usage(null, 'version'); - case 'c': - case 'C': - break; - default: - // all non pear params goes to the command - $cmdopts[$opt[0]] = $param; - break; - } -} + // {{{ file with replacements + if (!file_exists($orig_file)) { + return $this->raiseError("file does not exist", + PEAR_INSTALLER_FAILED); + } -if ($store_system_config) { - $config->store('system'); -} + $contents = file_get_contents($orig_file); + if ($contents === false) { + $contents = ''; + } -if ($store_user_config) { - $config->store('user'); -} + if (isset($atts['md5sum'])) { + $md5sum = md5($contents); + } -$command = (isset($options[1][0])) ? $options[1][0] : null; + $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; + } + } -if (empty($command) && ($store_user_config || $store_system_config)) { - exit; -} + $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); + } -if ($fetype == 'Gtk' || $fetype == 'Gtk2') { - if (!$config->validConfiguration()) { - PEAR::raiseError('CRITICAL ERROR: no existing valid configuration files found in files ' . - "'$pear_user_config' or '$pear_system_config', please copy an existing configuration" . - 'file to one of these locations, or use the -c and -s options to create one'); - } - Gtk::main(); -} else do { - if ($command == 'help') { - usage(null, @$options[1][1]); - } - if (!$config->validConfiguration()) { - PEAR::raiseError('CRITICAL ERROR: no existing valid configuration files found in files ' . - "'$pear_user_config' or '$pear_system_config', please copy an existing configuration" . - 'file to one of these locations, or use the -c and -s options to create one'); - } + $wp = @fopen($dest_file, "wb"); + if (!is_resource($wp)) { + return $this->raiseError("failed to create $dest_file: $php_errormsg", + PEAR_INSTALLER_FAILED); + } - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $cmd = PEAR_Command::factory($command, $config); - PEAR::popErrorHandling(); - if (PEAR::isError($cmd)) { - usage(null, @$options[1][0]); - } + if (@fwrite($wp, $contents) === false) { + return $this->raiseError("failed writing to $dest_file: $php_errormsg", + PEAR_INSTALLER_FAILED); + } - $short_args = $long_args = null; - PEAR_Command::getGetoptArgs($command, $short_args, $long_args); - if (in_array('getopt2', get_class_methods('Console_Getopt'))) { - array_shift($options[1]); - $tmp = Console_Getopt::getopt2($options[1], $short_args, $long_args); - } else { - $tmp = Console_Getopt::getopt($options[1], $short_args, $long_args); - } - if (PEAR::isError($tmp)) { - break; - } - list($tmpopt, $params) = $tmp; - $opts = array(); - foreach ($tmpopt as $foo => $tmp2) { - list($opt, $value) = $tmp2; - if ($value === null) { - $value = true; // options without args - } - if (strlen($opt) == 1) { - $cmdoptions = $cmd->getOptions($command); - foreach ($cmdoptions as $o => $d) { - if (isset($d['shortopt']) && $d['shortopt'] == $opt) { - $opts[$o] = $value; + 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); + } + + 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 { - if (substr($opt, 0, 2) == '--') { - $opts[substr($opt, 2)] = $value; + // }}} + // {{{ 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')); } } - } - $ok = $cmd->run($command, $opts, $params); - if ($ok === false) { - PEAR::raiseError("unknown command `$command'"); - } - if (PEAR::isError($ok)) { - PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, array($ui, "displayFatalError")); - PEAR::raiseError($ok); - } -} while (false); -// {{{ usage() + // 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'); + } -function usage($error = null, $helpsubject = null) -{ - global $progname, $all_commands; - $stderr = fopen('php://stderr', 'w'); - if (PEAR::isError($error)) { - fputs($stderr, $error->getMessage() . "\n"); - } elseif ($error !== null) { - fputs($stderr, "$error\n"); - } - if ($helpsubject != null) { - $put = cmdHelp($helpsubject); - } else { - $put = - "Commands:\n"; - $maxlen = max(array_map("strlen", $all_commands)); - $formatstr = "%-{$maxlen}s %s\n"; - ksort($all_commands); - foreach ($all_commands as $cmd => $class) { - $put .= sprintf($formatstr, $cmd, PEAR_Command::getDescription($cmd)); + if ($atts['role'] != 'src') { + $this->addFileOperation("installed_as", array($file, $installed_as, + $loc, + dirname(substr($installedas_dest_file, strlen($loc))))); } - $put .= - "Usage: $progname [options] command [command-options] \n". - "Type \"$progname help options\" to list all options.\n". - "Type \"$progname help shortcuts\" to list all command shortcuts.\n". - "Type \"$progname help \" to get the help for the specified command."; + + //$this->log(2, "installed: $dest_file"); + return PEAR_INSTALLER_OK; } - fputs($stderr, "$put\n"); - fclose($stderr); - exit(1); -} -function cmdHelp($command) -{ - global $progname, $all_commands, $config; - if ($command == "options") { - return - "Options:\n". - " -v increase verbosity level (default 1)\n". - " -q be quiet, decrease verbosity level\n". - " -c file find user configuration in `file'\n". - " -C file find system configuration in `file'\n". - " -d foo=bar set user config variable `foo' to `bar'\n". - " -D foo=bar set system config variable `foo' to `bar'\n". - " -G start in graphical (Gtk) mode\n". - " -s store user configuration\n". - " -S store system configuration\n". - " -u foo unset `foo' in the user configuration\n". - " -h, -? display help/usage (this message)\n". - " -V version information\n"; - } elseif ($command == "shortcuts") { - $sc = PEAR_Command::getShortcuts(); - $ret = "Shortcuts:\n"; - foreach ($sc as $s => $c) { - $ret .= sprintf(" %-8s %s\n", $s, $c); - } - return $ret; + // }}} + // {{{ _installFile2() - } elseif ($command == "version") { - return "PEAR Version: ".$GLOBALS['pear_package_version']. - "\nPHP Version: ".phpversion(). - "\nZend Engine Version: ".zend_version(). - "\nRunning on: ".php_uname(); + /** + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @param string filename + * @param array attributes from 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(); + } - } elseif ($help = PEAR_Command::getHelp($command)) { - if (is_string($help)) { - return "$progname $command [options] $help\n"; + $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"); } - if ($help[1] === null) { - return "$progname $command $help[0]"; - } else { - return "$progname $command [options] $help[0]\n$help[1]"; + + $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; } - } - return "Command '$command' is not valid, try '$progname help'"; -} -// }}} + if (!$role->isInstallable()) { + return; + } -function error_handler($errno, $errmsg, $file, $line, $vars) { - if ((defined('E_STRICT') && $errno & E_STRICT) || (defined('E_DEPRECATED') && - $errno & E_DEPRECATED) || !error_reporting()) { - if (defined('E_STRICT') && $errno & E_STRICT) { - return; // E_STRICT + $info = $role->processInstallation($pkg, $atts['attribs'], $file, $tmp_path); + if (PEAR::isError($info)) { + return $info; } - if (defined('E_DEPRECATED') && $errno & E_DEPRECATED) { - return; // E_DEPRECATED + + 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); } - if ($GLOBALS['config']->get('verbose') < 4) { - return false; // @silenced error, show all if debug is high enough + + $final_dest_file = $installed_as = $dest_file; + if (isset($this->_options['packagingroot'])) { + $final_dest_file = $this->_prependPath($final_dest_file, + $this->_options['packagingroot']); } - } - $errortype = array ( - E_ERROR => "Error", - E_WARNING => "Warning", - E_PARSE => "Parsing Error", - E_NOTICE => "Notice", - E_CORE_ERROR => "Core Error", - E_CORE_WARNING => "Core Warning", - E_COMPILE_ERROR => "Compile Error", - E_COMPILE_WARNING => "Compile Warning", - E_USER_ERROR => "User Error", - E_USER_WARNING => "User Warning", - E_USER_NOTICE => "User Notice" - ); - $prefix = $errortype[$errno]; - global $_PEAR_PHPDIR; - if (stristr($file, $_PEAR_PHPDIR)) { - $file = substr($file, strlen($_PEAR_PHPDIR) + 1); - } else { - $file = basename($file); - } - print "\n$prefix: $errmsg in $file on line $line\n"; - return false; -} + $dest_dir = dirname($final_dest_file); + $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); + // }}} -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * indent-tabs-mode: nil - * mode: php - * End: - */ -// vim600:syn=phpPEAR-1.8.0/scripts/peclcmd.php100664 764 764 1640 100664 11115 - * @author Tomas V.V.Cox - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: peclcmd.php,v 1.2 2009/02/25 00:06:23 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - */ + 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"); + } + } -/** - * @nodep Gtk - */ -if ('@include_path@' != '@'.'include_path'.'@') { - ini_set('include_path', '@include_path@'); - $raw = false; -} else { - // this is a raw, uninstalled pear, either a cvs checkout, or php distro - $raw = true; -} -define('PEAR_RUNTYPE', 'pecl'); -require_once 'pearcmd.php'; -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * indent-tabs-mode: nil - * mode: php - * End: - */ -// vim600:syn=php + $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); + } -?> -PEAR-1.8.0/LICENSE100664 764 764 2705 100664 6316 Copyright (c) 1997-2009, - Stig Bakken , - Gregory Beaver , - Helgi Þormar Þorbjörnsson , - Tomas V.V.Cox , - Martin Jansen . -All rights reserved. + if (!@copy($orig_file, $dest_file)) { + return $this->raiseError("failed to write $dest_file: $php_errormsg", + PEAR_INSTALLER_FAILED); + } -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: + $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); + } - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. + $contents = file_get_contents($orig_file); + if ($contents === false) { + $contents = ''; + } -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -PEAR-1.8.0/INSTALL100777 764 764 3643 100777 6356 PEAR - The PEAR Installer -========================= -Installing the PEAR Installer. + if (isset($attribs['md5sum'])) { + $md5sum = md5($contents); + } -You should install PEAR on a local development machine first. Installing -PEAR on a remote production machine should only be done after you are -familiar with PEAR and have tested code using PEAR on your development -machine. + 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 + } -There are two methods of installing PEAR - - PEAR bundled in PHP - - go-pear + if (PEAR::isError($res)) { + return $res; + } -We will first examine how to install PEAR that is bundled with PHP. + $contents = $res; // save changes + } -Microsoft Windows -================= -If you are running PHP 5.2.0 or newer, simply download and -run the windows installer (.msi) and PEAR can be automatically -installed. + $wp = @fopen($dest_file, "wb"); + if (!is_resource($wp)) { + return $this->raiseError("failed to create $dest_file: $php_errormsg", + PEAR_INSTALLER_FAILED); + } -Otherwise, for older PHP versions, download the .zip of windows, -there is a script included with your PHP distribution that is called -"go-pear". You must open a command box in order to run it. Click -"start" then click "Run..." and type "cmd.exe" to open a command box. -Use "cd" to change directory to the location of PHP where you unzipped it, -and run the go-pear command. + if (fwrite($wp, $contents) === false) { + return $this->raiseError("failed writing to $dest_file: $php_errormsg", + PEAR_INSTALLER_FAILED); + } -Unix -==== -make sure you have enabled default extensions, and if you want faster -downloads, enable the zlib extension. You must also enable the CLI -SAPI with the --enable-cli extension directive. After this, simply run: + fclose($wp); + } + } -make install-pear + // {{{ check the md5 + if (isset($md5sum)) { + // Make sure the original md5 sum matches with expected + if (strtolower($md5sum) === strtolower($attribs['md5sum'])) { + $this->log(2, "md5sum ok: $final_dest_file"); -and PEAR will be automatically configured for you. + if (isset($contents)) { + // set md5 sum based on $content in case any tasks were run. + $real_atts['attribs']['md5sum'] = md5($contents); + } + } else { + if (empty($options['force'])) { + // delete the file + if (file_exists($dest_file)) { + unlink($dest_file); + } -go-pear -======= -For users who cannot perform the above steps, or who wish to obtain the -latest PEAR with a slightly higher risk of failure, use go-pear. go-pear -is obtained by downloading http://go-pear.org and saving it as go-pear.php. -After downloading, simply run "php go-pear.php" or open it in a web browser -(windows only) to download and install PEAR. + if (!isset($options['ignore-errors'])) { + return $this->raiseError("bad md5sum for file $final_dest_file", + PEAR_INSTALLER_FAILED); + } -You can always ask general installation questions on pear-general@lists.php.net, -a public mailing list devoted to support for PEAR packages and installation- -related issues. + 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); + } -Happy PHPing, we hope PEAR will be a great tool for your development work! + // }}} + // {{{ 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')); + } -$Id: INSTALL,v 1.1 2006/09/22 03:31:36 cellog Exp $PEAR-1.8.0/package.dtd100777 764 764 6477 100777 7425 - - - + 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 = count($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': + $test = file_exists($data[1]) ? @unlink($data[1]) : null; + if (!$test && file_exists($data[1])) { + if ($data[2]) { + $extra = ', this extension must be installed manually. Rename to "' . + basename($data[1]) . '"'; + } else { + $extra = ''; + } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PEAR-1.8.0/PEAR.php100664 764 764 105707 100664 6617 - * @author Stig Bakken - * @author Tomas V.V.Cox - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: PEAR.php,v 1.111 2009/04/08 23:32:04 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/**#@+ - * ERROR constants - */ -define('PEAR_ERROR_RETURN', 1); -define('PEAR_ERROR_PRINT', 2); -define('PEAR_ERROR_TRIGGER', 4); -define('PEAR_ERROR_DIE', 8); -define('PEAR_ERROR_CALLBACK', 16); -/** - * WARNING: obsolete - * @deprecated - */ -define('PEAR_ERROR_EXCEPTION', 32); -/**#@-*/ -define('PEAR_ZE2', (function_exists('version_compare') && - version_compare(zend_version(), "2-dev", "ge"))); - -if (substr(PHP_OS, 0, 3) == 'WIN') { - define('OS_WINDOWS', true); - define('OS_UNIX', false); - define('PEAR_OS', 'Windows'); -} else { - define('OS_WINDOWS', false); - define('OS_UNIX', true); - define('PEAR_OS', 'Unix'); // blatant assumption -} - -$GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_RETURN; -$GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE; -$GLOBALS['_PEAR_destructor_object_list'] = array(); -$GLOBALS['_PEAR_shutdown_funcs'] = array(); -$GLOBALS['_PEAR_error_handler_stack'] = array(); - -@ini_set('track_errors', true); - -/** - * Base class for other PEAR classes. Provides rudimentary - * emulation of destructors. - * - * If you want a destructor in your class, inherit PEAR and make a - * destructor method called _yourclassname (same name as the - * constructor, but with a "_" prefix). Also, in your constructor you - * have to call the PEAR constructor: $this->PEAR();. - * The destructor method will be called without parameters. Note that - * at in some SAPI implementations (such as Apache), any output during - * the request shutdown (in which destructors are called) seems to be - * discarded. If you need to get any debug information from your - * destructor, use error_log(), syslog() or something similar. - * - * IMPORTANT! To use the emulated destructors you need to create the - * objects by reference: $obj =& new PEAR_child; - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Tomas V.V. Cox - * @author Greg Beaver - * @copyright 1997-2006 The PHP Group - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @see PEAR_Error - * @since Class available since PHP 4.0.2 - * @link http://pear.php.net/manual/en/core.pear.php#core.pear.pear - */ -class PEAR -{ - // {{{ properties + if (!isset($this->_options['soft'])) { + $this->log(1, 'Could not delete ' . $data[1] . ', cannot rename ' . + $data[0] . $extra); + } - /** - * Whether to enable internal debug messages. - * - * @var bool - * @access private - */ - var $_debug = false; + if (!isset($this->_options['ignore-errors'])) { + return false; + } + } - /** - * Default error mode for this object. - * - * @var int - * @access private - */ - var $_default_error_mode = null; + // 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; + } - /** - * Default error options used for this object when error mode - * is PEAR_ERROR_TRIGGER. - * - * @var int - * @access private - */ - var $_default_error_options = null; + // 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; + } - /** - * Default error handler (callback) for this object, if error mode is - * PEAR_ERROR_CALLBACK. - * - * @var string - * @access private - */ - var $_default_error_handler = ''; + $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 + } - /** - * Which class to use for error objects. - * - * @var string - * @access private - */ - var $_error_class = 'PEAR_Error'; + 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])); - /** - * An array of expected errors. - * - * @var array - * @access private - */ - var $_expected_errors = array(); + 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() - // {{{ constructor - - /** - * Constructor. Registers this object in - * $_PEAR_destructor_object_list for destructor emulation if a - * destructor object exists. - * - * @param string $error_class (optional) which class to use for - * error objects, defaults to PEAR_Error. - * @access public - * @return void - */ - function PEAR($error_class = null) + function rollbackFileTransaction() { - $classname = strtolower(get_class($this)); - if ($this->_debug) { - print "PEAR constructor called, class=$classname\n"; - } - if ($error_class !== null) { - $this->_error_class = $error_class; - } - while ($classname && strcasecmp($classname, "pear")) { - $destructor = "_$classname"; - if (method_exists($this, $destructor)) { - global $_PEAR_destructor_object_list; - $_PEAR_destructor_object_list[] = &$this; - if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { - register_shutdown_function("_PEAR_call_destructors"); - $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; - } - break; - } else { - $classname = get_parent_class($classname); + $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(); } // }}} - // {{{ destructor + // {{{ mkDirHier($dir) + + function mkDirHier($dir) + { + $this->addFileOperation('mkdir', array($dir)); + return parent::mkDirHier($dir); + } + + // }}} + // {{{ download() /** - * Destructor (the emulated type of...). Does nothing right now, - * but is included for forward compatibility, so subclass - * destructors should always call it. + * Download any files and their dependencies, if necessary * - * See the note in the class desciption about output from - * destructors. + * @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: * - * @access public - * @return void + * + * array('pkg' => 'package_name', 'file' => '/path/to/local/file', + * 'info' => array() // parsed package.xml + * ); + * + * @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 _PEAR() { - if ($this->_debug) { - printf("PEAR destructor called, class=%s\n", strtolower(get_class($this))); - } + 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; } // }}} - // {{{ getStaticProperty() + // {{{ _parsePackageXml() - /** - * If you have a class that's mostly/entirely static, and you need static - * properties, you can use this method to simulate them. Eg. in your method(s) - * do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar'); - * You MUST use a reference, or they will not persist! - * - * @access public - * @param string $class The calling classname, to prevent clashes - * @param string $var The variable to retrieve. - * @return mixed A reference to the variable. If not set it will be - * auto initialised to NULL. - */ - function &getStaticProperty($class, $var) + function _parsePackageXml(&$descfile, &$tmpdir) { - static $properties; - if (!isset($properties[$class])) { - $properties[$class] = array(); + 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); + // }}} } - if (!array_key_exists($var, $properties[$class])) { - $properties[$class][$var] = null; + // 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'); } - return $properties[$class][$var]; + $descfile = $p->getPackageFile(); + return $p; } // }}} - // {{{ registerShutdownFunc() - /** - * Use this function to register a shutdown method for static - * classes. - * - * @access public - * @param mixed $func The function name (or array of class/method) to call - * @param mixed $args The arguments to pass to the function - * @return void - */ - function registerShutdownFunc($func, $args = array()) + * Set the list of PEAR_Downloader_Package objects to allow more sane + * dependency validation + * @param array + */ + function setDownloadedPackages(&$pkgs) { - // if we are called statically, there is a potential - // that no shutdown func is registered. Bug #6445 - if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { - register_shutdown_function("_PEAR_call_destructors"); - $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $err = $this->analyzeDependencies($pkgs); + PEAR::popErrorHandling(); + if (PEAR::isError($err)) { + return $err; } - $GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args); + $this->_downloadedPackages = &$pkgs; } - // }}} - // {{{ isError() - /** - * Tell whether a value is a PEAR error. - * - * @param mixed $data the value to test - * @param int $code if $data is an error object, return true - * only if $code is a string and - * $obj->getMessage() == $code or - * $code is an integer and $obj->getCode() == $code - * @access public - * @return bool true if parameter is an error + * Set the list of PEAR_Downloader_Package objects to allow more sane + * dependency validation + * @param array */ - function isError($data, $code = null) + function setUninstallPackages(&$pkgs) { - if (!is_a($data, 'PEAR_Error')) { - return false; - } - - if (is_null($code)) { - return true; - } elseif (is_string($code)) { - return $data->getMessage() == $code; - } + $this->_downloadedPackages = &$pkgs; + } - return $data->getCode() == $code; + function getInstallPackages() + { + return $this->_downloadedPackages; } - // }}} - // {{{ setErrorHandling() + // {{{ install() /** - * Sets how errors generated by this object should be handled. - * Can be invoked both in objects and statically. If called - * statically, setErrorHandling sets the default behaviour for all - * PEAR objects. If called in an object, setErrorHandling sets - * the default behaviour for that object. - * - * @param int $mode - * One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, - * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, - * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION. + * Installs the files within the package file specified. * - * @param mixed $options - * When $mode is PEAR_ERROR_TRIGGER, this is the error level (one - * of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). - * - * When $mode is PEAR_ERROR_CALLBACK, this parameter is expected - * to be the callback function or method. A callback - * function is a string with the name of the function, a - * callback method is an array of two elements: the element - * at index 0 is the object, and the element at index 1 is - * the name of the method to call in the object. - * - * When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is - * a printf format string used when printing the error - * message. - * - * @access public - * @return void - * @see PEAR_ERROR_RETURN - * @see PEAR_ERROR_PRINT - * @see PEAR_ERROR_TRIGGER - * @see PEAR_ERROR_DIE - * @see PEAR_ERROR_CALLBACK - * @see PEAR_ERROR_EXCEPTION + * @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 * - * @since PHP 4.0.5 + * @return array|PEAR_Error package info if successful */ - - function setErrorHandling($mode = null, $options = null) + function install($pkgfile, $options = array()) { - if (isset($this) && is_a($this, 'PEAR')) { - $setmode = &$this->_default_error_mode; - $setoptions = &$this->_default_error_options; + $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 { - $setmode = &$GLOBALS['_PEAR_default_error_mode']; - $setoptions = &$GLOBALS['_PEAR_default_error_options']; + $descfile = $pkgfile; + $tmpdir = ''; + $pkg = $this->_parsePackageXml($descfile, $tmpdir); + if (PEAR::isError($pkg)) { + return $pkg; + } } - switch ($mode) { - case PEAR_ERROR_EXCEPTION: - case PEAR_ERROR_RETURN: - case PEAR_ERROR_PRINT: - case PEAR_ERROR_TRIGGER: - case PEAR_ERROR_DIE: - case null: - $setmode = $mode; - $setoptions = $options; - break; + if (realpath($descfile) != realpath($pkgfile)) { + $tar = new Archive_Tar($pkgfile); + if (!$tar->extract($tmpdir)) { + return $this->raiseError("unable to unpack $pkgfile"); + } + } - case PEAR_ERROR_CALLBACK: - $setmode = $mode; - // class/object method callback - if (is_callable($options)) { - $setoptions = $options; - } else { - trigger_error("invalid error callback", E_USER_WARNING); - } - break; + $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']); - default: - trigger_error("invalid error mode", E_USER_WARNING); - break; + $packrootphp_dir = $this->_prependPath( + $this->config->get('php_dir', null, $channel), + $this->_options['packagingroot']); } - } - - // }}} - // {{{ expectError() - /** - * This method is used to tell which errors you expect to get. - * Expected errors are always returned with error mode - * PEAR_ERROR_RETURN. Expected error codes are stored in a stack, - * and this method pushes a new element onto it. The list of - * expected errors are in effect until they are popped off the - * stack with the popExpect() method. - * - * Note that this method can not be called statically - * - * @param mixed $code a single error code or an array of error codes to expect - * - * @return int the new depth of the "expected errors" stack - * @access public - */ - function expectError($code = '*') - { - if (is_array($code)) { - array_push($this->_expected_errors, $code); + 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 { - array_push($this->_expected_errors, array($code)); + $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 = ''; } - return sizeof($this->_expected_errors); - } - // }}} - // {{{ popExpect() + // {{{ 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; + } - /** - * This method pops one element off the expected error codes - * stack. - * - * @return array the list of error codes that were popped - */ - function popExpect() - { - return array_pop($this->_expected_errors); - } + // ensure we have the most accurate registry + $installregistry->flushFileMap(); + $test = $installregistry->checkFileMap($instfilelist, $testp, '1.1'); + if (PEAR::isError($test)) { + return $test; + } - // }}} - // {{{ _checkDelExpect() + if (sizeof($test)) { + $pkgs = $this->getInstallPackages(); + $found = false; + foreach ($pkgs as $param) { + if ($pkg->isSubpackageOf($param)) { + $found = true; + break; + } + } - /** - * This method checks unsets an error code if available - * - * @param mixed error code - * @return bool true if the error code was unset, false otherwise - * @access private - * @since PHP 4.3.0 - */ - function _checkDelExpect($error_code) - { - $deleted = false; + if ($found) { + // subpackages can conflict with earlier versions of parent packages + $parentreg = $installregistry->packageInfo($param->getPackage(), null, $param->getChannel()); + $tmp = $test; + foreach ($tmp as $file => $info) { + if (is_array($info)) { + if (strtolower($info[1]) == strtolower($param->getPackage()) && + strtolower($info[0]) == strtolower($param->getChannel()) + ) { + if (isset($parentreg['filelist'][$file])) { + unset($parentreg['filelist'][$file]); + } else{ + $pos = strpos($file, '/'); + $basedir = substr($file, 0, $pos); + $file2 = substr($file, $pos + 1); + if (isset($parentreg['filelist'][$file2]['baseinstalldir']) + && $parentreg['filelist'][$file2]['baseinstalldir'] === $basedir + ) { + unset($parentreg['filelist'][$file2]); + } + } - foreach ($this->_expected_errors AS $key => $error_array) { - if (in_array($error_code, $error_array)) { - unset($this->_expected_errors[$key][array_search($error_code, $error_array)]); - $deleted = true; - } + unset($test[$file]); + } + } else { + if (strtolower($param->getChannel()) != 'pear.php.net') { + continue; + } - // clean up empty arrays - if (0 == count($this->_expected_errors[$key])) { - unset($this->_expected_errors[$key]); + if (strtolower($info) == strtolower($param->getPackage())) { + if (isset($parentreg['filelist'][$file])) { + unset($parentreg['filelist'][$file]); + } else{ + $pos = strpos($file, '/'); + $basedir = substr($file, 0, $pos); + $file2 = substr($file, $pos + 1); + if (isset($parentreg['filelist'][$file2]['baseinstalldir']) + && $parentreg['filelist'][$file2]['baseinstalldir'] === $basedir + ) { + unset($parentreg['filelist'][$file2]); + } + } + + unset($test[$file]); + } + } + } + + $pfk = &new PEAR_PackageFile($this->config); + $parentpkg = &$pfk->fromArray($parentreg); + $installregistry->updatePackage2($parentpkg); + } + + if ($param->getChannel() == 'pecl.php.net' && isset($options['upgrade'])) { + $tmp = $test; + foreach ($tmp as $file => $info) { + if (is_string($info)) { + // pear.php.net packages are always stored as strings + if (strtolower($info) == strtolower($param->getPackage())) { + // upgrading existing package + unset($test[$file]); + } + } + } + } + + if (count($test)) { + $msg = "$channel/$pkgname: conflicting files found:\n"; + $longest = max(array_map("strlen", array_keys($test))); + $fmt = "%${longest}s (%s)\n"; + foreach ($test as $file => $info) { + if (!is_array($info)) { + $info = array('pear.php.net', $info); + } + $info = $info[0] . '/' . $info[1]; + $msg .= sprintf($fmt, $file, $info); + } + + if (!isset($options['ignore-errors'])) { + return $this->raiseError($msg); + } + + if (!isset($options['soft'])) { + $this->log(0, "WARNING: $msg"); + } + } } } - return $deleted; - } + // }}} - // }}} - // {{{ delExpect() + $this->startFileTransaction(); - /** - * This method deletes all occurences of the specified element from - * the expected error codes stack. - * - * @param mixed $error_code error code that should be deleted - * @return mixed list of error codes that were deleted or error - * @access public - * @since PHP 4.3.0 - */ - function delExpect($error_code) - { - $deleted = false; - if ((is_array($error_code) && (0 != count($error_code)))) { - // $error_code is a non-empty array here; - // we walk through it trying to unset all - // values - foreach($error_code as $key => $error) { - if ($this->_checkDelExpect($error)) { - $deleted = true; - } else { - $deleted = false; + if (empty($options['upgrade']) && empty($options['soft'])) { + // checks to do only when installing new packages + if ($channel == 'pecl.php.net') { + $test = $installregistry->packageExists($pkgname, $channel); + if (!$test) { + $test = $installregistry->packageExists($pkgname, 'pear.php.net'); } - } - return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME - } elseif (!empty($error_code)) { - // $error_code comes alone, trying to unset it - if ($this->_checkDelExpect($error_code)) { - return true; } else { - return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME + $test = $installregistry->packageExists($pkgname, $channel); } - } - // $error_code is empty - return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME - } + if (empty($options['force']) && $test) { + return $this->raiseError("$channel/$pkgname is already installed"); + } + } else { + $usechannel = $channel; + if ($channel == 'pecl.php.net') { + $test = $installregistry->packageExists($pkgname, $channel); + if (!$test) { + $test = $installregistry->packageExists($pkgname, 'pear.php.net'); + $usechannel = 'pear.php.net'; + } + } else { + $test = $installregistry->packageExists($pkgname, $channel); + } - // }}} - // {{{ raiseError() + if ($test) { + $v1 = $installregistry->packageInfo($pkgname, 'version', $usechannel); + $v2 = $pkg->getVersion(); + $cmp = version_compare("$v1", "$v2", 'gt'); + if (empty($options['force']) && !version_compare("$v2", "$v1", 'gt')) { + return $this->raiseError("upgrade to a newer version ($v2 is not newer than $v1)"); + } - /** - * This method is a wrapper that returns an instance of the - * configured error class with this object's default error - * handling applied. If the $mode and $options parameters are not - * specified, the object's defaults are used. - * - * @param mixed $message a text error message or a PEAR error object - * - * @param int $code a numeric error code (it is up to your class - * to define these if you want to use codes) - * - * @param int $mode One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, - * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, - * PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION. - * - * @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter - * specifies the PHP-internal error level (one of - * E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). - * If $mode is PEAR_ERROR_CALLBACK, this - * parameter specifies the callback function or - * method. In other error modes this parameter - * is ignored. - * - * @param string $userinfo If you need to pass along for example debug - * information, this parameter is meant for that. - * - * @param string $error_class The returned error object will be - * instantiated from this class, if specified. - * - * @param bool $skipmsg If true, raiseError will only pass error codes, - * the error message parameter will be dropped. - * - * @access public - * @return object a PEAR error object - * @see PEAR::setErrorHandling - * @since PHP 4.0.5 - */ - function &raiseError($message = null, - $code = null, - $mode = null, - $options = null, - $userinfo = null, - $error_class = null, - $skipmsg = false) - { - // The error is yet a PEAR error object - if (is_object($message)) { - $code = $message->getCode(); - $userinfo = $message->getUserInfo(); - $error_class = $message->getType(); - $message->error_message_prefix = ''; - $message = $message->getMessage(); - } + if (empty($options['register-only'])) { + // when upgrading, remove old release's files first: + if (PEAR::isError($err = $this->_deletePackageFiles($pkgname, $usechannel, + true))) { + if (!isset($options['ignore-errors'])) { + return $this->raiseError($err); + } - if (isset($this) && isset($this->_expected_errors) && sizeof($this->_expected_errors) > 0 && sizeof($exp = end($this->_expected_errors))) { - if ($exp[0] == "*" || - (is_int(reset($exp)) && in_array($code, $exp)) || - (is_string(reset($exp)) && in_array($message, $exp))) { - $mode = PEAR_ERROR_RETURN; + if (!isset($options['soft'])) { + $this->log(0, 'WARNING: ' . $err->getMessage()); + } + } else { + $backedup = $err; + } + } } } - // No mode given, try global ones - if ($mode === null) { - // Class error handler - if (isset($this) && isset($this->_default_error_mode)) { - $mode = $this->_default_error_mode; - $options = $this->_default_error_options; - // Global error handler - } elseif (isset($GLOBALS['_PEAR_default_error_mode'])) { - $mode = $GLOBALS['_PEAR_default_error_mode']; - $options = $GLOBALS['_PEAR_default_error_options']; + // {{{ Copy files to dest dir --------------------------------------- + + // info from the package it self we want to access from _installFile + $this->pkginfo = &$pkg; + // used to determine whether we should build any C code + $this->source_files = 0; + + $savechannel = $this->config->get('default_channel'); + if (empty($options['register-only']) && !is_dir($php_dir)) { + if (PEAR::isError(System::mkdir(array('-p'), $php_dir))) { + return $this->raiseError("no installation destination directory '$php_dir'\n"); } } - if ($error_class !== null) { - $ec = $error_class; - } elseif (isset($this) && isset($this->_error_class)) { - $ec = $this->_error_class; - } else { - $ec = 'PEAR_Error'; + $tmp_path = dirname($descfile); + if (substr($pkgfile, -4) != '.xml') { + $tmp_path .= DIRECTORY_SEPARATOR . $pkgname . '-' . $pkg->getVersion(); } - if (intval(PHP_VERSION) < 5) { - // little non-eval hack to fix bug #12147 - include 'PEAR/FixPHP5PEARWarnings.php'; - return $a; - } + $this->configSet('default_channel', $channel); + // {{{ install files - if ($skipmsg) { - $a = new $ec($code, $mode, $options, $userinfo); + $ver = $pkg->getPackagexmlVersion(); + if (version_compare($ver, '2.0', '>=')) { + $filelist = $pkg->getInstallationFilelist(); } else { - $a = new $ec($message, $code, $mode, $options, $userinfo); + $filelist = $pkg->getFileList(); } - return $a; - } + if (PEAR::isError($filelist)) { + return $filelist; + } - // }}} - // {{{ throwError() + $p = &$installregistry->getPackage($pkgname, $channel); + $dirtree = (empty($options['register-only']) && $p) ? $p->getDirTree() : false; - /** - * Simpler form of raiseError with fewer options. In most cases - * message, code and userinfo are enough. - * - * @param string $message - * - */ - function &throwError($message = null, - $code = null, - $userinfo = null) - { - if (isset($this) && is_a($this, 'PEAR')) { - $a = &$this->raiseError($message, $code, null, null, $userinfo); - return $a; - } + $pkg->resetFilelist(); + $pkg->setLastInstalledVersion($installregistry->packageInfo($pkg->getPackage(), + 'version', $pkg->getChannel())); + foreach ($filelist as $file => $atts) { + $this->expectError(PEAR_INSTALLER_FAILED); + if ($pkg->getPackagexmlVersion() == '1.0') { + $res = $this->_installFile($file, $atts, $tmp_path, $options); + } else { + $res = $this->_installFile2($pkg, $file, $atts, $tmp_path, $options); + } + $this->popExpect(); - $a = &PEAR::raiseError($message, $code, null, null, $userinfo); - return $a; - } + if (PEAR::isError($res)) { + if (empty($options['ignore-errors'])) { + $this->rollbackFileTransaction(); + if ($res->getMessage() == "file does not exist") { + $this->raiseError("file $file in package.xml does not exist"); + } - // }}} - function staticPushErrorHandling($mode, $options = null) - { - $stack = &$GLOBALS['_PEAR_error_handler_stack']; - $def_mode = &$GLOBALS['_PEAR_default_error_mode']; - $def_options = &$GLOBALS['_PEAR_default_error_options']; - $stack[] = array($def_mode, $def_options); - switch ($mode) { - case PEAR_ERROR_EXCEPTION: - case PEAR_ERROR_RETURN: - case PEAR_ERROR_PRINT: - case PEAR_ERROR_TRIGGER: - case PEAR_ERROR_DIE: - case null: - $def_mode = $mode; - $def_options = $options; - break; - - case PEAR_ERROR_CALLBACK: - $def_mode = $mode; - // class/object method callback - if (is_callable($options)) { - $def_options = $options; - } else { - trigger_error("invalid error callback", E_USER_WARNING); + return $this->raiseError($res); } - break; - - default: - trigger_error("invalid error mode", E_USER_WARNING); - break; - } - $stack[] = array($mode, $options); - return true; - } - function staticPopErrorHandling() - { - $stack = &$GLOBALS['_PEAR_error_handler_stack']; - $setmode = &$GLOBALS['_PEAR_default_error_mode']; - $setoptions = &$GLOBALS['_PEAR_default_error_options']; - array_pop($stack); - list($mode, $options) = $stack[sizeof($stack) - 1]; - array_pop($stack); - switch ($mode) { - case PEAR_ERROR_EXCEPTION: - case PEAR_ERROR_RETURN: - case PEAR_ERROR_PRINT: - case PEAR_ERROR_TRIGGER: - case PEAR_ERROR_DIE: - case null: - $setmode = $mode; - $setoptions = $options; - break; - - case PEAR_ERROR_CALLBACK: - $setmode = $mode; - // class/object method callback - if (is_callable($options)) { - $setoptions = $options; - } else { - trigger_error("invalid error callback", E_USER_WARNING); + if (!isset($options['soft'])) { + $this->log(0, "Warning: " . $res->getMessage()); } - break; + } - default: - trigger_error("invalid error mode", E_USER_WARNING); - break; + $real = isset($atts['attribs']) ? $atts['attribs'] : $atts; + if ($res == PEAR_INSTALLER_OK && $real['role'] != 'src') { + // Register files that were installed + $pkg->installedFile($file, $atts); + } } - return true; - } + // }}} - // {{{ pushErrorHandling() + // {{{ compile and install source files + if ($this->source_files > 0 && empty($options['nobuild'])) { + if (PEAR::isError($err = + $this->_compileSourceFiles($savechannel, $pkg))) { + return $err; + } + } + // }}} - /** - * Push a new error handler on top of the error handler options stack. With this - * you can easily override the actual error handler for some code and restore - * it later with popErrorHandling. - * - * @param mixed $mode (same as setErrorHandling) - * @param mixed $options (same as setErrorHandling) - * - * @return bool Always true - * - * @see PEAR::setErrorHandling - */ - function pushErrorHandling($mode, $options = null) - { - $stack = &$GLOBALS['_PEAR_error_handler_stack']; - if (isset($this) && is_a($this, 'PEAR')) { - $def_mode = &$this->_default_error_mode; - $def_options = &$this->_default_error_options; - } else { - $def_mode = &$GLOBALS['_PEAR_default_error_mode']; - $def_options = &$GLOBALS['_PEAR_default_error_options']; + if (isset($backedup)) { + $this->_removeBackups($backedup); } - $stack[] = array($def_mode, $def_options); - if (isset($this) && is_a($this, 'PEAR')) { - $this->setErrorHandling($mode, $options); - } else { - PEAR::setErrorHandling($mode, $options); + if (!$this->commitFileTransaction()) { + $this->rollbackFileTransaction(); + $this->configSet('default_channel', $savechannel); + return $this->raiseError("commit failed", PEAR_INSTALLER_FAILED); } - $stack[] = array($mode, $options); - return true; - } + // }}} - // }}} - // {{{ popErrorHandling() + $ret = false; + $installphase = 'install'; + $oldversion = false; + // {{{ Register that the package is installed ----------------------- + if (empty($options['upgrade'])) { + // if 'force' is used, replace the info in registry + $usechannel = $channel; + if ($channel == 'pecl.php.net') { + $test = $installregistry->packageExists($pkgname, $channel); + if (!$test) { + $test = $installregistry->packageExists($pkgname, 'pear.php.net'); + $usechannel = 'pear.php.net'; + } + } else { + $test = $installregistry->packageExists($pkgname, $channel); + } - /** - * Pop the last error handler used - * - * @return bool Always true - * - * @see PEAR::pushErrorHandling - */ - function popErrorHandling() - { - $stack = &$GLOBALS['_PEAR_error_handler_stack']; - array_pop($stack); - list($mode, $options) = $stack[sizeof($stack) - 1]; - array_pop($stack); - if (isset($this) && is_a($this, 'PEAR')) { - $this->setErrorHandling($mode, $options); + if (!empty($options['force']) && $test) { + $oldversion = $installregistry->packageInfo($pkgname, 'version', $usechannel); + $installregistry->deletePackage($pkgname, $usechannel); + } + $ret = $installregistry->addPackage2($pkg); } else { - PEAR::setErrorHandling($mode, $options); - } - return true; - } - - // }}} - // {{{ loadExtension() + if ($dirtree) { + $this->startFileTransaction(); + // attempt to delete empty directories + uksort($dirtree, array($this, '_sortDirs')); + foreach($dirtree as $dir => $notused) { + $this->addFileOperation('rmdir', array($dir)); + } + $this->commitFileTransaction(); + } - /** - * OS independant PHP extension load. Remember to take care - * on the correct extension name for case sensitive OSes. - * - * @param string $ext The extension name - * @return bool Success or not on the dl() call - */ - function loadExtension($ext) - { - if (!extension_loaded($ext)) { - // if either returns true dl() will produce a FATAL error, stop that - if ((ini_get('enable_dl') != 1) || (ini_get('safe_mode') == 1)) { - return false; + $usechannel = $channel; + if ($channel == 'pecl.php.net') { + $test = $installregistry->packageExists($pkgname, $channel); + if (!$test) { + $test = $installregistry->packageExists($pkgname, 'pear.php.net'); + $usechannel = 'pear.php.net'; + } + } else { + $test = $installregistry->packageExists($pkgname, $channel); } - if (OS_WINDOWS) { - $suffix = '.dll'; - } elseif (PHP_OS == 'HP-UX') { - $suffix = '.sl'; - } elseif (PHP_OS == 'AIX') { - $suffix = '.a'; - } elseif (PHP_OS == 'OSX') { - $suffix = '.bundle'; + // new: upgrade installs a package if it isn't installed + if (!$test) { + $ret = $installregistry->addPackage2($pkg); } else { - $suffix = '.so'; + if ($usechannel != $channel) { + $installregistry->deletePackage($pkgname, $usechannel); + $ret = $installregistry->addPackage2($pkg); + } else { + $ret = $installregistry->updatePackage2($pkg); + } + $installphase = 'upgrade'; } + } - return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix); + if (!$ret) { + $this->configSet('default_channel', $savechannel); + return $this->raiseError("Adding package $channel/$pkgname to registry failed"); } + // }}} - return true; + $this->configSet('default_channel', $savechannel); + if (class_exists('PEAR_Task_Common')) { // this is auto-included if any tasks exist + if (PEAR_Task_Common::hasPostinstallTasks()) { + PEAR_Task_Common::runPostinstallTasks($installphase); + } + } + + return $pkg->toArray(true); } // }}} -} -if (PEAR_ZE2) { + // {{{ _compileSourceFiles() /** - * This is only meant for PHP 5 to get rid of certain strict warning - * that doesn't get hidden since it's in the shutdown function + * @param string + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 */ - class PEAR5 + function _compileSourceFiles($savechannel, &$filelist) { - /** - * If you have a class that's mostly/entirely static, and you need static - * properties, you can use this method to simulate them. Eg. in your method(s) - * do this: $myVar = &PEAR5::getStaticProperty('myclass', 'myVar'); - * You MUST use a reference, or they will not persist! - * - * @access public - * @param string $class The calling classname, to prevent clashes - * @param string $var The variable to retrieve. - * @return mixed A reference to the variable. If not set it will be - * auto initialised to NULL. - */ - static function &getStaticProperty($class, $var) - { - static $properties; - if (!isset($properties[$class])) { - $properties[$class] = array(); + require_once 'PEAR/Builder.php'; + $this->log(1, "$this->source_files source files, building"); + $bob = &new PEAR_Builder($this->ui); + $bob->debug = $this->debug; + $built = $bob->build($filelist, array(&$this, '_buildCallback')); + if (PEAR::isError($built)) { + $this->rollbackFileTransaction(); + $this->configSet('default_channel', $savechannel); + return $built; + } + + $this->log(1, "\nBuild process completed successfully"); + foreach ($built as $ext) { + $bn = basename($ext['file']); + list($_ext_name, $_ext_suff) = explode('.', $bn); + if ($_ext_suff == '.so' || $_ext_suff == '.dll') { + if (extension_loaded($_ext_name)) { + $this->raiseError("Extension '$_ext_name' already loaded. " . + 'Please unload it in your php.ini file ' . + 'prior to install or upgrade'); + } + $role = 'ext'; + } else { + $role = 'src'; } - if (!array_key_exists($var, $properties[$class])) { - $properties[$class][$var] = null; + $dest = $ext['dest']; + $packagingroot = ''; + if (isset($this->_options['packagingroot'])) { + $packagingroot = $this->_options['packagingroot']; } - return $properties[$class][$var]; - } - } -} + $copyto = $this->_prependPath($dest, $packagingroot); + $extra = $copyto != $dest ? " as '$copyto'" : ''; + $this->log(1, "Installing '$dest'$extra"); -// {{{ _PEAR_call_destructors() + $copydir = dirname($copyto); + // pretty much nothing happens if we are only registering the install + if (empty($this->_options['register-only'])) { + if (!file_exists($copydir) || !is_dir($copydir)) { + if (!$this->mkDirHier($copydir)) { + return $this->raiseError("failed to mkdir $copydir", + PEAR_INSTALLER_FAILED); + } -function _PEAR_call_destructors() -{ - global $_PEAR_destructor_object_list; - if (is_array($_PEAR_destructor_object_list) && - sizeof($_PEAR_destructor_object_list)) - { - reset($_PEAR_destructor_object_list); - if (PEAR_ZE2) { - $destructLifoExists = PEAR5::getStaticProperty('PEAR', 'destructlifo'); - } else { - $destructLifoExists = PEAR::getStaticProperty('PEAR', 'destructlifo'); - } + $this->log(3, "+ mkdir $copydir"); + } - if ($destructLifoExists) { - $_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list); - } + if (!@copy($ext['file'], $copyto)) { + return $this->raiseError("failed to write $copyto ($php_errormsg)", PEAR_INSTALLER_FAILED); + } - while (list($k, $objref) = each($_PEAR_destructor_object_list)) { - $classname = get_class($objref); - while ($classname) { - $destructor = "_$classname"; - if (method_exists($objref, $destructor)) { - $objref->$destructor(); - break; - } else { - $classname = get_parent_class($classname); + $this->log(3, "+ cp $ext[file] $copyto"); + $this->addFileOperation('rename', array($ext['file'], $copyto)); + if (!OS_WINDOWS) { + $mode = 0666 & ~(int)octdec($this->config->get('umask')); + $this->addFileOperation('chmod', array($mode, $copyto)); + if (!@chmod($copyto, $mode)) { + $this->log(0, "failed to change mode of $copyto ($php_errormsg)"); + } } } - } - // Empty the object list to ensure that destructors are - // not called more than once. - $_PEAR_destructor_object_list = array(); - } - // Now call the shutdown functions - if (is_array($GLOBALS['_PEAR_shutdown_funcs']) AND !empty($GLOBALS['_PEAR_shutdown_funcs'])) { - foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) { - call_user_func_array($value[0], $value[1]); - } - } -} -// }}} -/** - * Standard PEAR error class for PHP 4 - * - * This class is supserseded by {@link PEAR_Exception} in PHP 5 - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Tomas V.V. Cox - * @author Gregory Beaver - * @copyright 1997-2006 The PHP Group - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/manual/en/core.pear.pear-error.php - * @see PEAR::raiseError(), PEAR::throwError() - * @since Class available since PHP 4.0.2 - */ -class PEAR_Error -{ - // {{{ properties + $data = array( + 'role' => $role, + 'name' => $bn, + 'installed_as' => $dest, + 'php_api' => $ext['php_api'], + 'zend_mod_api' => $ext['zend_mod_api'], + 'zend_ext_api' => $ext['zend_ext_api'], + ); - var $error_message_prefix = ''; - var $mode = PEAR_ERROR_RETURN; - var $level = E_USER_NOTICE; - var $code = -1; - var $message = ''; - var $userinfo = ''; - var $backtrace = null; + if ($filelist->getPackageXmlVersion() == '1.0') { + $filelist->installedFile($bn, $data); + } else { + $filelist->installedFile($bn, array('attribs' => $data)); + } + } + } // }}} - // {{{ constructor + function &getUninstallPackages() + { + return $this->_downloadedPackages; + } + // {{{ uninstall() /** - * PEAR_Error constructor - * - * @param string $message message - * - * @param int $code (optional) error code - * - * @param int $mode (optional) error mode, one of: PEAR_ERROR_RETURN, - * PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER, - * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION - * - * @param mixed $options (optional) error level, _OR_ in the case of - * PEAR_ERROR_CALLBACK, the callback function or object/method - * tuple. - * - * @param string $userinfo (optional) additional user/debug info + * Uninstall a package * - * @access public + * This method removes all files installed by the application, and then + * removes any empty directories. + * @param string package name + * @param array Command-line options. Possibilities include: * + * - installroot: base installation dir, if not the default + * - register-only : update registry but don't remove files + * - nodeps: do not process dependencies of other packages to ensure + * uninstallation does not break things */ - function PEAR_Error($message = 'unknown error', $code = null, - $mode = null, $options = null, $userinfo = null) + function uninstall($package, $options = array()) { - if ($mode === null) { - $mode = PEAR_ERROR_RETURN; - } - $this->message = $message; - $this->code = $code; - $this->mode = $mode; - $this->userinfo = $userinfo; + $installRoot = isset($options['installroot']) ? $options['installroot'] : ''; + $this->config->setInstallRoot($installRoot); - if (PEAR_ZE2) { - $skiptrace = PEAR5::getStaticProperty('PEAR_Error', 'skiptrace'); + $this->installroot = ''; + $this->_registry = &$this->config->getRegistry(); + if (is_object($package)) { + $channel = $package->getChannel(); + $pkg = $package; + $package = $pkg->getPackage(); } else { - $skiptrace = PEAR::getStaticProperty('PEAR_Error', 'skiptrace'); + $pkg = false; + $info = $this->_registry->parsePackageName($package, + $this->config->get('default_channel')); + $channel = $info['channel']; + $package = $info['package']; } - if (!$skiptrace) { - $this->backtrace = debug_backtrace(); - if (isset($this->backtrace[0]) && isset($this->backtrace[0]['object'])) { - unset($this->backtrace[0]['object']); - } + $savechannel = $this->config->get('default_channel'); + $this->configSet('default_channel', $channel); + if (!is_object($pkg)) { + $pkg = $this->_registry->getPackage($package, $channel); } - if ($mode & PEAR_ERROR_CALLBACK) { - $this->level = E_USER_NOTICE; - $this->callback = $options; - } else { - if ($options === null) { - $options = E_USER_NOTICE; - } - $this->level = $options; - $this->callback = null; + + if (!$pkg) { + $this->configSet('default_channel', $savechannel); + return $this->raiseError($this->_registry->parsedPackageNameToString( + array( + 'channel' => $channel, + 'package' => $package + ), true) . ' not installed'); } - if ($this->mode & PEAR_ERROR_PRINT) { - if (is_null($options) || is_int($options)) { - $format = "%s"; - } else { - $format = $options; - } - printf($format, $this->getMessage()); + + if ($pkg->getInstalledBinary()) { + // this is just an alias for a binary package + return $this->_registry->deletePackage($package, $channel); } - if ($this->mode & PEAR_ERROR_TRIGGER) { - trigger_error($this->getMessage(), $this->level); + + $filelist = $pkg->getFilelist(); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + if (!class_exists('PEAR_Dependency2')) { + require_once 'PEAR/Dependency2.php'; } - if ($this->mode & PEAR_ERROR_DIE) { - $msg = $this->getMessage(); - if (is_null($options) || is_int($options)) { - $format = "%s"; - if (substr($msg, -1) != "\n") { - $msg .= "\n"; - } - } else { - $format = $options; + + $depchecker = &new PEAR_Dependency2($this->config, $options, + array('channel' => $channel, 'package' => $package), + PEAR_VALIDATE_UNINSTALLING); + $e = $depchecker->validatePackageUninstall($this); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($e)) { + if (!isset($options['ignore-errors'])) { + return $this->raiseError($e); } - die(sprintf($format, $msg)); - } - if ($this->mode & PEAR_ERROR_CALLBACK) { - if (is_callable($this->callback)) { - call_user_func($this->callback, $this); + + if (!isset($options['soft'])) { + $this->log(0, 'WARNING: ' . $e->getMessage()); + } + } elseif (is_array($e)) { + if (!isset($options['soft'])) { + $this->log(0, $e[0]); } } - if ($this->mode & PEAR_ERROR_EXCEPTION) { - trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_Exception for exceptions", E_USER_WARNING); - eval('$e = new Exception($this->message, $this->code);throw($e);'); - } - } - // }}} - // {{{ getMode() - - /** - * Get the error mode from an error object. - * - * @return int error mode - * @access public - */ - function getMode() { - return $this->mode; - } - - // }}} - // {{{ getCallback() - - /** - * Get the callback function/method from an error object. - * - * @return mixed callback function or object/method array - * @access public - */ - function getCallback() { - return $this->callback; - } - - // }}} - // {{{ getMessage() - - - /** - * Get the error message from an error object. - * - * @return string full error message - * @access public - */ - function getMessage() - { - return ($this->error_message_prefix . $this->message); - } + $this->pkginfo = &$pkg; + // pretty much nothing happens if we are only registering the uninstall + if (empty($options['register-only'])) { + // {{{ Delete the files + $this->startFileTransaction(); + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + if (PEAR::isError($err = $this->_deletePackageFiles($package, $channel))) { + PEAR::popErrorHandling(); + $this->rollbackFileTransaction(); + $this->configSet('default_channel', $savechannel); + if (!isset($options['ignore-errors'])) { + return $this->raiseError($err); + } + if (!isset($options['soft'])) { + $this->log(0, 'WARNING: ' . $err->getMessage()); + } + } else { + PEAR::popErrorHandling(); + } - // }}} - // {{{ getCode() + if (!$this->commitFileTransaction()) { + $this->rollbackFileTransaction(); + if (!isset($options['ignore-errors'])) { + return $this->raiseError("uninstall failed"); + } - /** - * Get error code from an error object - * - * @return int error code - * @access public - */ - function getCode() - { - return $this->code; - } + if (!isset($options['soft'])) { + $this->log(0, 'WARNING: uninstall failed'); + } + } else { + $this->startFileTransaction(); + $dirtree = $pkg->getDirTree(); + if ($dirtree === false) { + $this->configSet('default_channel', $savechannel); + return $this->_registry->deletePackage($package, $channel); + } - // }}} - // {{{ getType() + // attempt to delete empty directories + uksort($dirtree, array($this, '_sortDirs')); + foreach($dirtree as $dir => $notused) { + $this->addFileOperation('rmdir', array($dir)); + } - /** - * Get the name of this error/exception. - * - * @return string error/exception name (type) - * @access public - */ - function getType() - { - return get_class($this); - } + if (!$this->commitFileTransaction()) { + $this->rollbackFileTransaction(); + if (!isset($options['ignore-errors'])) { + return $this->raiseError("uninstall failed"); + } - // }}} - // {{{ getUserInfo() + if (!isset($options['soft'])) { + $this->log(0, 'WARNING: uninstall failed'); + } + } + } + // }}} + } - /** - * Get additional user-supplied information. - * - * @return string user-supplied information - * @access public - */ - function getUserInfo() - { - return $this->userinfo; + $this->configSet('default_channel', $savechannel); + // Register that the package is no longer installed + return $this->_registry->deletePackage($package, $channel); } - // }}} - // {{{ getDebugInfo() - /** - * Get additional debug information supplied by the application. + * Sort a list of arrays of array(downloaded packagefilename) by dependency. * - * @return string debug information - * @access public + * It also removes duplicate dependencies + * @param array an array of PEAR_PackageFile_v[1/2] objects + * @return array|PEAR_Error array of array(packagefilename, package.xml contents) */ - function getDebugInfo() + function sortPackagesForUninstall(&$packages) { - return $this->getUserInfo(); + $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->config); + if (PEAR::isError($this->_dependencyDB)) { + return $this->_dependencyDB; + } + usort($packages, array(&$this, '_sortUninstall')); } - // }}} - // {{{ getBacktrace() - - /** - * Get the call backtrace from where the error was generated. - * Supported with PHP 4.3.0 or newer. - * - * @param int $frame (optional) what frame to fetch - * @return array Backtrace, or NULL if not available. - * @access public - */ - function getBacktrace($frame = null) + function _sortUninstall($a, $b) { - if (defined('PEAR_IGNORE_BACKTRACE')) { - return null; + if (!$a->getDeps() && !$b->getDeps()) { + return 0; // neither package has dependencies, order is insignificant } - if ($frame === null) { - return $this->backtrace; + if ($a->getDeps() && !$b->getDeps()) { + return -1; // $a must be installed after $b because $a has dependencies } - return $this->backtrace[$frame]; - } - - // }}} - // {{{ addUserInfo() - - function addUserInfo($info) - { - if (empty($this->userinfo)) { - $this->userinfo = $info; - } else { - $this->userinfo .= " ** $info"; + if (!$a->getDeps() && $b->getDeps()) { + return 1; // $b must be installed after $a because $b has dependencies + } + // both packages have dependencies + if ($this->_dependencyDB->dependsOn($a, $b)) { + return -1; + } + if ($this->_dependencyDB->dependsOn($b, $a)) { + return 1; } + return 0; } // }}} - // {{{ toString() - function __toString() + // {{{ _sortDirs() + function _sortDirs($a, $b) { - return $this->getMessage(); + if (strnatcmp($a, $b) == -1) return 1; + if (strnatcmp($a, $b) == 1) return -1; + return 0; } + // }}} - // {{{ toString() - /** - * Make a string representation of this object. - * - * @return string a string with an object summary - * @access public - */ - function toString() { - $modes = array(); - $levels = array(E_USER_NOTICE => 'notice', - E_USER_WARNING => 'warning', - E_USER_ERROR => 'error'); - if ($this->mode & PEAR_ERROR_CALLBACK) { - if (is_array($this->callback)) { - $callback = (is_object($this->callback[0]) ? - strtolower(get_class($this->callback[0])) : - $this->callback[0]) . '::' . - $this->callback[1]; - } else { - $callback = $this->callback; - } - return sprintf('[%s: message="%s" code=%d mode=callback '. - 'callback=%s prefix="%s" info="%s"]', - strtolower(get_class($this)), $this->message, $this->code, - $callback, $this->error_message_prefix, - $this->userinfo); - } - if ($this->mode & PEAR_ERROR_PRINT) { - $modes[] = 'print'; - } - if ($this->mode & PEAR_ERROR_TRIGGER) { - $modes[] = 'trigger'; - } - if ($this->mode & PEAR_ERROR_DIE) { - $modes[] = 'die'; - } - if ($this->mode & PEAR_ERROR_RETURN) { - $modes[] = 'return'; + // {{{ _buildCallback() + + function _buildCallback($what, $data) + { + if (($what == 'cmdoutput' && $this->debug > 1) || + ($what == 'output' && $this->debug > 0)) { + $this->ui->outputData(rtrim($data), 'build'); } - return sprintf('[%s: message="%s" code=%d mode=%s level=%s '. - 'prefix="%s" info="%s"]', - strtolower(get_class($this)), $this->message, $this->code, - implode("|", $modes), $levels[$this->level], - $this->error_message_prefix, - $this->userinfo); } // }}} -} - -/* - * Local Variables: - * mode: php - * tab-width: 4 - * c-basic-offset: 4 - * End: - */PEAR-1.8.0/README100777 764 764 2251 100777 6177 PEAR - The PEAR Installer -========================= - -What is the PEAR Installer? What is PEAR? - -PEAR is the PHP Extension and Application Repository, found at -http://pear.php.net. The PEAR Installer is this software, which -contains executable files and PHP code that is used to download -and install PEAR code from pear.php.net. - -PEAR contains useful software libraries and applications such as -MDB2 (database abstraction), HTML_QuickForm (HTML forms management), -PhpDocumentor (auto-documentation generator), DB_DataObject -(Data Access Abstraction), and many hundreds more. Browse all -available packages at http://pear.php.net, the list is constantly -growing and updating to reflect improvements in the PHP language. - -DOCUMENTATION -============= - -Documentation for PEAR can be found at http://pear.php.net/manual/. -Installation documentation can be found in the INSTALL file included -in this tarball. - -WARNING: DO NOT RUN PEAR WITHOUT INSTALLING IT - if you downloaded this -tarball manually, you MUST install it. Read the instructions in INSTALL -prior to use. - - -Happy PHPing, we hope PEAR will be a great tool for your development work! - -$Id: README,v 1.11 2006/09/22 03:31:36 cellog Exp $PEAR-1.8.0/System.php100664 764 764 47002 100664 7325 + * @package PEAR + * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: System.php,v 1.66 2009/02/24 23:52:56 dufuz Exp $ + * @version CVS: $Id: PackageFile.php 286670 2009-08-02 14:16:06Z dufuz $ * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 + * @since File available since Release 1.4.0a1 */ /** - * base class + * needed for PEAR_VALIDATE_* constants */ -require_once 'PEAR.php'; -require_once 'Console/Getopt.php'; - -$GLOBALS['_System_temp_files'] = array(); - +require_once 'PEAR/Validate.php'; /** -* System offers cross plattform compatible system functions -* -* Static functions for different operations. Should work under -* Unix and Windows. The names and usage has been taken from its respectively -* GNU commands. The functions will return (bool) false on error and will -* trigger the error with the PHP trigger_error() function (you can silence -* the error by prefixing a '@' sign after the function call, but this -* is not recommended practice. Instead use an error handler with -* {@link set_error_handler()}). -* -* Documentation on this class you can find in: -* http://pear.php.net/manual/ -* -* Example usage: -* if (!@System::rm('-r file1 dir1')) { -* print "could not delete file1 or dir1"; -* } -* -* In case you need to to pass file names with spaces, -* pass the params as an array: -* -* System::rm(array('-r', $file1, $dir1)); -* -* @category pear -* @package System -* @author Tomas V.V. Cox -* @copyright 1997-2006 The PHP Group -* @license http://opensource.org/licenses/bsd-license.php New BSD License -* @version Release: 1.8.0 -* @link http://pear.php.net/package/PEAR -* @since Class available since Release 0.1 -* @static -*/ -class System + * Error code if the package.xml tag does not contain a valid version + */ +define('PEAR_PACKAGEFILE_ERROR_NO_PACKAGEVERSION', 1); +/** + * Error code if the package.xml tag version is not supported (version 1.0 and 1.1 are the only supported versions, + * currently + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_PACKAGEVERSION', 2); +/** + * Abstraction for the package.xml package description file + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_PackageFile { /** - * returns the commandline arguments of a function + * @var PEAR_Config + */ + var $_config; + var $_debug; + /** + * Temp directory for uncompressing tgz files. + * @var string|false + */ + var $_tmpdir; + var $_logger = false; + /** + * @var boolean + */ + var $_rawReturn = false; + + /** * - * @param string $argv the commandline - * @param string $short_options the allowed option short-tags - * @param string $long_options the allowed option long-tags - * @return array the given options and there values - * @static - * @access private + * @param PEAR_Config $config + * @param ? $debug + * @param string @tmpdir Optional temporary directory for uncompressing + * files */ - function _parseArgs($argv, $short_options, $long_options = null) + function PEAR_PackageFile(&$config, $debug = false, $tmpdir = false) { - if (!is_array($argv) && $argv !== null) { - $argv = preg_split('/\s+/', $argv, -1, PREG_SPLIT_NO_EMPTY); - } - return Console_Getopt::getopt2($argv, $short_options); + $this->_config = $config; + $this->_debug = $debug; + $this->_tmpdir = $tmpdir; } /** - * Output errors with PHP trigger_error(). You can silence the errors - * with prefixing a "@" sign to the function call: @System::mkdir(..); + * Turn off validation - return a parsed package.xml without checking it * - * @param mixed $error a PEAR error or a string with the error message - * @return bool false - * @static - * @access private + * This is used by the package-validate command */ - function raiseError($error) + function rawReturn() { - if (PEAR::isError($error)) { - $error = $error->getMessage(); - } - trigger_error($error, E_USER_WARNING); - return false; + $this->_rawReturn = true; + } + + function setLogger(&$l) + { + $this->_logger = &$l; } /** - * Creates a nested array representing the structure of a directory - * - * System::_dirToStruct('dir1', 0) => - * Array - * ( - * [dirs] => Array - * ( - * [0] => dir1 - * ) - * - * [files] => Array - * ( - * [0] => dir1/file2 - * [1] => dir1/file3 - * ) - * ) - * @param string $sPath Name of the directory - * @param integer $maxinst max. deep of the lookup - * @param integer $aktinst starting deep of the lookup - * @param bool $silent if true, do not emit errors. - * @return array the structure of the dir - * @static - * @access private + * Create a PEAR_PackageFile_Parser_v* of a given version. + * @param int $version + * @return PEAR_PackageFile_Parser_v1|PEAR_PackageFile_Parser_v1 */ - function _dirToStruct($sPath, $maxinst, $aktinst = 0, $silent = false) + function &parserFactory($version) { - $struct = array('dirs' => array(), 'files' => array()); - if (($dir = @opendir($sPath)) === false) { - if (!$silent) { - System::raiseError("Could not open dir $sPath"); - } - return $struct; // XXX could not open error - } - - $struct['dirs'][] = $sPath = realpath($sPath); // XXX don't add if '.' or '..' ? - $list = array(); - while (false !== ($file = readdir($dir))) { - if ($file != '.' && $file != '..') { - $list[] = $file; - } + if (!in_array($version{0}, array('1', '2'))) { + $a = false; + return $a; } - closedir($dir); - natsort($list); - if ($aktinst < $maxinst || $maxinst == 0) { - foreach ($list as $val) { - $path = $sPath . DIRECTORY_SEPARATOR . $val; - if (is_dir($path) && !is_link($path)) { - $tmp = System::_dirToStruct($path, $maxinst, $aktinst+1, $silent); - $struct = array_merge_recursive($struct, $tmp); - } else { - $struct['files'][] = $path; - } - } - } + include_once 'PEAR/PackageFile/Parser/v' . $version{0} . '.php'; + $version = $version{0}; + $class = "PEAR_PackageFile_Parser_v$version"; + $a = new $class; + return $a; + } - return $struct; + /** + * For simpler unit-testing + * @return string + */ + function getClassPrefix() + { + return 'PEAR_PackageFile_v'; } /** - * Creates a nested array representing the structure of a directory and files - * - * @param array $files Array listing files and dirs - * @return array - * @static - * @see System::_dirToStruct() + * Create a PEAR_PackageFile_v* of a given version. + * @param int $version + * @return PEAR_PackageFile_v1|PEAR_PackageFile_v1 */ - function _multipleToStruct($files) + function &factory($version) { - $struct = array('dirs' => array(), 'files' => array()); - settype($files, 'array'); - foreach ($files as $file) { - if (is_dir($file) && !is_link($file)) { - $tmp = System::_dirToStruct($file, 0); - $struct = array_merge_recursive($tmp, $struct); - } else { - if (!in_array($file, $struct['files'])) { - $struct['files'][] = $file; - } - } + if (!in_array($version{0}, array('1', '2'))) { + $a = false; + return $a; } - return $struct; + + include_once 'PEAR/PackageFile/v' . $version{0} . '.php'; + $version = $version{0}; + $class = $this->getClassPrefix() . $version; + $a = new $class; + return $a; } /** - * The rm command for removing files. - * Supports multiple files and dirs and also recursive deletes + * Create a PEAR_PackageFile_v* from its toArray() method * - * @param string $args the arguments for rm - * @return mixed PEAR_Error or true for success - * @static - * @access public + * WARNING: no validation is performed, the array is assumed to be valid, + * always parse from xml if you want validation. + * @param array $arr + * @return PEAR_PackageFileManager_v1|PEAR_PackageFileManager_v2 + * @uses factory() to construct the returned object. */ - function rm($args) + function &fromArray($arr) { - $opts = System::_parseArgs($args, 'rf'); // "f" does nothing but I like it :-) - if (PEAR::isError($opts)) { - return System::raiseError($opts); - } - foreach ($opts[0] as $opt) { - if ($opt[0] == 'r') { - $do_recursive = true; + if (isset($arr['xsdversion'])) { + $obj = &$this->factory($arr['xsdversion']); + if ($this->_logger) { + $obj->setLogger($this->_logger); } + + $obj->setConfig($this->_config); + $obj->fromArray($arr); + return $obj; } - $ret = true; - if (isset($do_recursive)) { - $struct = System::_multipleToStruct($opts[1]); - foreach ($struct['files'] as $file) { - if (!@unlink($file)) { - $ret = false; - } - } - rsort($struct['dirs']); - foreach ($struct['dirs'] as $dir) { - if (!@rmdir($dir)) { - $ret = false; - } - } + if (isset($arr['package']['attribs']['version'])) { + $obj = &$this->factory($arr['package']['attribs']['version']); } else { - foreach ($opts[1] as $file) { - $delete = (is_dir($file)) ? 'rmdir' : 'unlink'; - if (!@$delete($file)) { - $ret = false; - } - } + $obj = &$this->factory('1.0'); } - return $ret; + + if ($this->_logger) { + $obj->setLogger($this->_logger); + } + + $obj->setConfig($this->_config); + $obj->fromArray($arr); + return $obj; } /** - * Make directories. - * - * The -p option will create parent directories - * @param string $args the name of the director(y|ies) to create - * @return bool True for success - * @static - * @access public + * Create a PEAR_PackageFile_v* from an XML string. + * @access public + * @param string $data contents of package.xml file + * @param int $state package state (one of PEAR_VALIDATE_* constants) + * @param string $file full path to the package.xml file (and the files + * it references) + * @param string $archive optional name of the archive that the XML was + * extracted from, if any + * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @uses parserFactory() to construct a parser to load the package. */ - function mkDir($args) + function &fromXmlString($data, $state, $file, $archive = false) { - $opts = System::_parseArgs($args, 'pm:'); - if (PEAR::isError($opts)) { - return System::raiseError($opts); - } + if (preg_match('/]+version="([0-9]+\.[0-9]+)"/', $data, $packageversion)) { + if (!in_array($packageversion[1], array('1.0', '2.0', '2.1'))) { + return PEAR::raiseError('package.xml version "' . $packageversion[1] . + '" is not supported, only 1.0, 2.0, and 2.1 are supported.'); + } - $mode = 0777; // default mode - foreach ($opts[0] as $opt) { - if ($opt[0] == 'p') { - $create_parents = true; - } elseif ($opt[0] == 'm') { - // if the mode is clearly an octal number (starts with 0) - // convert it to decimal - if (strlen($opt[1]) && $opt[1]{0} == '0') { - $opt[1] = octdec($opt[1]); - } else { - // convert to int - $opt[1] += 0; - } - $mode = $opt[1]; + $object = &$this->parserFactory($packageversion[1]); + if ($this->_logger) { + $object->setLogger($this->_logger); } - } - $ret = true; - if (isset($create_parents)) { - foreach ($opts[1] as $dir) { - $dirstack = array(); - while ((!file_exists($dir) || !is_dir($dir)) && - $dir != DIRECTORY_SEPARATOR) { - array_unshift($dirstack, $dir); - $dir = dirname($dir); - } + $object->setConfig($this->_config); + $pf = $object->parse($data, $file, $archive); + if (PEAR::isError($pf)) { + return $pf; + } - while ($newdir = array_shift($dirstack)) { - if (!is_writeable(dirname($newdir))) { - $ret = false; - break; - } + if ($this->_rawReturn) { + return $pf; + } - if (!mkdir($newdir, $mode)) { - $ret = false; + if (!$pf->validate($state)) {; + if ($this->_config->get('verbose') > 0 + && $this->_logger && $pf->getValidationWarnings(false) + ) { + foreach ($pf->getValidationWarnings(false) as $warning) { + $this->_logger->log(0, 'ERROR: ' . $warning['message']); } } + + $a = PEAR::raiseError('Parsing of package.xml from file "' . $file . '" failed', + 2, null, null, $pf->getValidationWarnings()); + return $a; } - } else { - foreach($opts[1] as $dir) { - if ((@file_exists($dir) || !is_dir($dir)) && !mkdir($dir, $mode)) { - $ret = false; + + if ($this->_logger && $pf->getValidationWarnings(false)) { + foreach ($pf->getValidationWarnings() as $warning) { + $this->_logger->log(0, 'WARNING: ' . $warning['message']); } } - } - return $ret; - } + if (method_exists($pf, 'flattenFilelist')) { + $pf->flattenFilelist(); // for v2 + } - /** - * Concatenate files - * - * Usage: - * 1) $var = System::cat('sample.txt test.txt'); - * 2) System::cat('sample.txt test.txt > final.txt'); - * 3) System::cat('sample.txt test.txt >> final.txt'); - * - * Note: as the class use fopen, urls should work also (test that) - * - * @param string $args the arguments - * @return boolean true on success - * @static - * @access public - */ - function &cat($args) - { - $ret = null; - $files = array(); - if (!is_array($args)) { - $args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY); - } + return $pf; + } elseif (preg_match('/]+version="([^"]+)"/', $data, $packageversion)) { + $a = PEAR::raiseError('package.xml file "' . $file . + '" has unsupported package.xml version "' . $packageversion[1] . '"'); + return $a; + } else { + if (!class_exists('PEAR_ErrorStack')) { + require_once 'PEAR/ErrorStack.php'; + } - $count_args = count($args); - for ($i = 0; $i < $count_args; $i++) { - if ($args[$i] == '>') { - $mode = 'wb'; - $outputfile = $args[$i+1]; - break; - } elseif ($args[$i] == '>>') { - $mode = 'ab+'; - $outputfile = $args[$i+1]; - break; - } else { - $files[] = $args[$i]; + PEAR_ErrorStack::staticPush('PEAR_PackageFile', + PEAR_PACKAGEFILE_ERROR_NO_PACKAGEVERSION, + 'warning', array('xml' => $data), 'package.xml "' . $file . + '" has no package.xml version'); + $object = &$this->parserFactory('1.0'); + $object->setConfig($this->_config); + $pf = $object->parse($data, $file, $archive); + if (PEAR::isError($pf)) { + return $pf; } - } - $outputfd = false; - if (isset($mode)) { - if (!$outputfd = fopen($outputfile, $mode)) { - $err = System::raiseError("Could not open $outputfile"); - return $err; + + if ($this->_rawReturn) { + return $pf; } - $ret = true; - } - foreach ($files as $file) { - if (!$fd = fopen($file, 'r')) { - System::raiseError("Could not open $file"); - continue; + + if (!$pf->validate($state)) { + $a = PEAR::raiseError('Parsing of package.xml from file "' . $file . '" failed', + 2, null, null, $pf->getValidationWarnings()); + return $a; } - while ($cont = fread($fd, 2048)) { - if (is_resource($outputfd)) { - fwrite($outputfd, $cont); - } else { - $ret .= $cont; + + if ($this->_logger && $pf->getValidationWarnings(false)) { + foreach ($pf->getValidationWarnings() as $warning) { + $this->_logger->log(0, 'WARNING: ' . $warning['message']); } } - fclose($fd); - } - if (is_resource($outputfd)) { - fclose($outputfd); + + if (method_exists($pf, 'flattenFilelist')) { + $pf->flattenFilelist(); // for v2 + } + + return $pf; } - return $ret; } /** - * Creates temporary files or directories. This function will remove - * the created files when the scripts finish its execution. - * - * Usage: - * 1) $tempfile = System::mktemp("prefix"); - * 2) $tempdir = System::mktemp("-d prefix"); - * 3) $tempfile = System::mktemp(); - * 4) $tempfile = System::mktemp("-t /var/tmp prefix"); - * - * prefix -> The string that will be prepended to the temp name - * (defaults to "tmp"). - * -d -> A temporary dir will be created instead of a file. - * -t -> The target dir where the temporary (file|dir) will be created. If - * this param is missing by default the env vars TMP on Windows or - * TMPDIR in Unix will be used. If these vars are also missing - * c:\windows\temp or /tmp will be used. + * Register a temporary file or directory. When the destructor is + * executed, all registered temporary files and directories are + * removed. * - * @param string $args The arguments - * @return mixed the full path of the created (file|dir) or false - * @see System::tmpdir() - * @static + * @param string $file name of file or directory + * @return void + */ + function addTempFile($file) + { + $GLOBALS['_PEAR_Common_tempfiles'][] = $file; + } + + /** + * Create a PEAR_PackageFile_v* from a compresed Tar or Tgz file. * @access public + * @param string contents of package.xml file + * @param int package state (one of PEAR_VALIDATE_* constants) + * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @using Archive_Tar to extract the files + * @using fromPackageFile() to load the package after the package.xml + * file is extracted. */ - function mktemp($args = null) + function &fromTgzFile($file, $state) { - static $first_time = true; - $opts = System::_parseArgs($args, 't:d'); - if (PEAR::isError($opts)) { - return System::raiseError($opts); + if (!class_exists('Archive_Tar')) { + require_once 'Archive/Tar.php'; } - foreach ($opts[0] as $opt) { - if ($opt[0] == 'd') { - $tmp_is_dir = true; - } elseif ($opt[0] == 't') { - $tmpdir = $opt[1]; - } + $tar = new Archive_Tar($file); + if ($this->_debug <= 1) { + $tar->pushErrorHandling(PEAR_ERROR_RETURN); } - $prefix = (isset($opts[1][0])) ? $opts[1][0] : 'tmp'; - if (!isset($tmpdir)) { - $tmpdir = System::tmpdir(); + $content = $tar->listContent(); + if ($this->_debug <= 1) { + $tar->popErrorHandling(); } - if (!System::mkDir(array('-p', $tmpdir))) { - return false; + if (!is_array($content)) { + if (is_string($file) && strlen($file < 255) && + (!file_exists($file) || !@is_file($file))) { + $ret = PEAR::raiseError("could not open file \"$file\""); + return $ret; + } + + $file = realpath($file); + $ret = PEAR::raiseError("Could not get contents of package \"$file\"". + '. Invalid tgz file.'); + return $ret; } - $tmp = tempnam($tmpdir, $prefix); - if (isset($tmp_is_dir)) { - unlink($tmp); // be careful possible race condition here - if (!mkdir($tmp, 0700)) { - return System::raiseError("Unable to create temporary directory $tmpdir"); + if (!count($content) && !@is_file($file)) { + $ret = PEAR::raiseError("could not open file \"$file\""); + return $ret; + } + + $xml = null; + $origfile = $file; + foreach ($content as $file) { + $name = $file['filename']; + if ($name == 'package2.xml') { // allow a .tgz to distribute both versions + $xml = $name; + break; + } + + if ($name == 'package.xml') { + $xml = $name; + break; + } elseif (preg_match('/package.xml$/', $name, $match)) { + $xml = $name; + break; } } - $GLOBALS['_System_temp_files'][] = $tmp; - if (isset($tmp_is_dir)) { - //$GLOBALS['_System_temp_files'][] = dirname($tmp); + if ($this->_tmpdir) { + $tmpdir = $this->_tmpdir; + } else { + $tmpdir = System::mkTemp(array('-t', $this->_config->get('temp_dir'), '-d', 'pear')); + if ($tmpdir === false) { + $ret = PEAR::raiseError("there was a problem with getting the configured temp directory"); + return $ret; + } + + PEAR_PackageFile::addTempFile($tmpdir); } - if ($first_time) { - PEAR::registerShutdownFunc(array('System', '_removeTmpFiles')); - $first_time = false; + $this->_extractErrors(); + PEAR::staticPushErrorHandling(PEAR_ERROR_CALLBACK, array($this, '_extractErrors')); + if (!$xml || !$tar->extractList(array($xml), $tmpdir)) { + $extra = implode("\n", $this->_extractErrors()); + if ($extra) { + $extra = ' ' . $extra; + } + + PEAR::staticPopErrorHandling(); + $ret = PEAR::raiseError('could not extract the package.xml file from "' . + $origfile . '"' . $extra); + return $ret; } - return $tmp; + PEAR::staticPopErrorHandling(); + $ret = &PEAR_PackageFile::fromPackageFile("$tmpdir/$xml", $state, $origfile); + return $ret; } /** - * Remove temporary files created my mkTemp. This function is executed - * at script shutdown time + * helper for extracting Archive_Tar errors + * @var array + * @access private + */ + var $_extractErrors = array(); + + /** + * helper callback for extracting Archive_Tar errors * - * @static + * @param PEAR_Error|null $err + * @return array * @access private */ - function _removeTmpFiles() + function _extractErrors($err = null) { - if (count($GLOBALS['_System_temp_files'])) { - $delete = $GLOBALS['_System_temp_files']; - array_unshift($delete, '-r'); - System::rm($delete); - $GLOBALS['_System_temp_files'] = array(); + static $errors = array(); + if ($err === null) { + $e = $errors; + $errors = array(); + return $e; } + $errors[] = $err->getMessage(); } /** - * Get the path of the temporal directory set in the system - * by looking in its environments variables. - * Note: php.ini-recommended removes the "E" from the variables_order setting, - * making unavaible the $_ENV array, that s why we do tests with _ENV + * Create a PEAR_PackageFile_v* from a package.xml file. * - * @static - * @return string The temporary directory on the system + * @access public + * @param string $descfile name of package xml file + * @param int $state package state (one of PEAR_VALIDATE_* constants) + * @param string|false $archive name of the archive this package.xml came + * from, if any + * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @uses PEAR_PackageFile::fromXmlString to create the oject after the + * XML is loaded from the package.xml file. */ - function tmpdir() + function &fromPackageFile($descfile, $state, $archive = false) { - if (OS_WINDOWS) { - if ($var = isset($_ENV['TMP']) ? $_ENV['TMP'] : getenv('TMP')) { - return $var; - } - if ($var = isset($_ENV['TEMP']) ? $_ENV['TEMP'] : getenv('TEMP')) { - return $var; - } - if ($var = isset($_ENV['USERPROFILE']) ? $_ENV['USERPROFILE'] : getenv('USERPROFILE')) { - return $var; - } - if ($var = isset($_ENV['windir']) ? $_ENV['windir'] : getenv('windir')) { - return $var; - } - return getenv('SystemRoot') . '\temp'; - } - if ($var = isset($_ENV['TMPDIR']) ? $_ENV['TMPDIR'] : getenv('TMPDIR')) { - return $var; + $fp = false; + if (is_string($descfile) && strlen($descfile) < 255 && + ( + !file_exists($descfile) || !is_file($descfile) || !is_readable($descfile) + || (!$fp = @fopen($descfile, 'r')) + ) + ) { + $a = PEAR::raiseError("Unable to open $descfile"); + return $a; } - return realpath('/tmp'); + + // read the whole thing so we only get one cdata callback + // for each block of cdata + fclose($fp); + $data = file_get_contents($descfile); + $ret = &PEAR_PackageFile::fromXmlString($data, $state, $descfile, $archive); + return $ret; } + /** - * The "which" command (show the full path of a command) + * Create a PEAR_PackageFile_v* from a .tgz archive or package.xml file. * - * @param string $program The command to search for - * @param mixed $fallback Value to return if $program is not found + * This method is able to extract information about a package from a .tgz + * archive or from a XML package definition file. * - * @return mixed A string with the full path or false if not found - * @static - * @author Stig Bakken + * @access public + * @param string $info file name + * @param int $state package state (one of PEAR_VALIDATE_* constants) + * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @uses fromPackageFile() if the file appears to be XML + * @uses fromTgzFile() to load all non-XML files */ - function which($program, $fallback = false) + function &fromAnyFile($info, $state) { - // enforce API - if (!is_string($program) || '' == $program) { - return $fallback; - } - - // full path given - if (basename($program) != $program) { - $path_elements[] = dirname($program); - $program = basename($program); - } else { - // Honor safe mode - if (!ini_get('safe_mode') || !$path = ini_get('safe_mode_exec_dir')) { - $path = getenv('PATH'); - if (!$path) { - $path = getenv('Path'); // some OSes are just stupid enough to do this - } + if (is_dir($info)) { + $dir_name = realpath($info); + if (file_exists($dir_name . '/package.xml')) { + $info = PEAR_PackageFile::fromPackageFile($dir_name . '/package.xml', $state); + } elseif (file_exists($dir_name . '/package2.xml')) { + $info = PEAR_PackageFile::fromPackageFile($dir_name . '/package2.xml', $state); + } else { + $info = PEAR::raiseError("No package definition found in '$info' directory"); } - $path_elements = explode(PATH_SEPARATOR, $path); - } - if (OS_WINDOWS) { - $exe_suffixes = getenv('PATHEXT') - ? explode(PATH_SEPARATOR, getenv('PATHEXT')) - : array('.exe','.bat','.cmd','.com'); - // allow passing a command.exe param - if (strpos($program, '.') !== false) { - array_unshift($exe_suffixes, ''); - } - // is_executable() is not available on windows for PHP4 - $pear_is_executable = (function_exists('is_executable')) ? 'is_executable' : 'is_file'; - } else { - $exe_suffixes = array(''); - $pear_is_executable = 'is_executable'; + return $info; } - foreach ($exe_suffixes as $suff) { - foreach ($path_elements as $dir) { - $file = $dir . DIRECTORY_SEPARATOR . $program . $suff; - if (@$pear_is_executable($file)) { - return $file; - } + $fp = false; + if (is_string($info) && strlen($info) < 255 && + (file_exists($info) || ($fp = @fopen($info, 'r'))) + ) { + + if ($fp) { + fclose($fp); } - } - return $fallback; - } + $tmp = substr($info, -4); + if ($tmp == '.xml') { + $info = &PEAR_PackageFile::fromPackageFile($info, $state); + } elseif ($tmp == '.tar' || $tmp == '.tgz') { + $info = &PEAR_PackageFile::fromTgzFile($info, $state); + } else { + $fp = fopen($info, 'r'); + $test = fread($fp, 5); + fclose($fp); + if ($test == ' + * @author Tomas V. V. Cox + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Packager.php 286809 2009-08-04 15:10:26Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * base class + */ +require_once 'PEAR/Common.php'; +require_once 'PEAR/PackageFile.php'; +require_once 'System.php'; + +/** + * Administration class used to make a PEAR release tarball. + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Packager extends PEAR_Common +{ /** - * The "find" command - * - * Usage: - * - * System::find($dir); - * System::find("$dir -type d"); - * System::find("$dir -type f"); - * System::find("$dir -name *.php"); - * System::find("$dir -name *.php -name *.htm*"); - * System::find("$dir -maxdepth 1"); - * - * Params implmented: - * $dir -> Start the search at this directory - * -type d -> return only directories - * -type f -> return only files - * -maxdepth -> max depth of recursion - * -name -> search pattern (bash style). Multiple -name param allowed + * @var PEAR_Registry + */ + var $_registry; + + function package($pkgfile = null, $compress = true, $pkg2 = null) + { + // {{{ validate supplied package.xml file + if (empty($pkgfile)) { + $pkgfile = 'package.xml'; + } + + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $pkg = &new PEAR_PackageFile($this->config, $this->debug); + $pf = &$pkg->fromPackageFile($pkgfile, PEAR_VALIDATE_NORMAL); + $main = &$pf; + PEAR::staticPopErrorHandling(); + if (PEAR::isError($pf)) { + if (is_array($pf->getUserInfo())) { + foreach ($pf->getUserInfo() as $error) { + $this->log(0, 'Error: ' . $error['message']); + } + } + + $this->log(0, $pf->getMessage()); + return $this->raiseError("Cannot package, errors in package file"); + } + + foreach ($pf->getValidationWarnings() as $warning) { + $this->log(1, 'Warning: ' . $warning['message']); + } + + // }}} + if ($pkg2) { + $this->log(0, 'Attempting to process the second package file'); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $pf2 = &$pkg->fromPackageFile($pkg2, PEAR_VALIDATE_NORMAL); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($pf2)) { + if (is_array($pf2->getUserInfo())) { + foreach ($pf2->getUserInfo() as $error) { + $this->log(0, 'Error: ' . $error['message']); + } + } + $this->log(0, $pf2->getMessage()); + return $this->raiseError("Cannot package, errors in second package file"); + } + + foreach ($pf2->getValidationWarnings() as $warning) { + $this->log(1, 'Warning: ' . $warning['message']); + } + + if ($pf2->getPackagexmlVersion() == '2.0' || + $pf2->getPackagexmlVersion() == '2.1' + ) { + $main = &$pf2; + $other = &$pf; + } else { + $main = &$pf; + $other = &$pf2; + } + + if ($main->getPackagexmlVersion() != '2.0' && + $main->getPackagexmlVersion() != '2.1') { + return PEAR::raiseError('Error: cannot package two package.xml version 1.0, can ' . + 'only package together a package.xml 1.0 and package.xml 2.0'); + } + + if ($other->getPackagexmlVersion() != '1.0') { + return PEAR::raiseError('Error: cannot package two package.xml version 2.0, can ' . + 'only package together a package.xml 1.0 and package.xml 2.0'); + } + } + + $main->setLogger($this); + if (!$main->validate(PEAR_VALIDATE_PACKAGING)) { + foreach ($main->getValidationWarnings() as $warning) { + $this->log(0, 'Error: ' . $warning['message']); + } + return $this->raiseError("Cannot package, errors in package"); + } + + foreach ($main->getValidationWarnings() as $warning) { + $this->log(1, 'Warning: ' . $warning['message']); + } + + if ($pkg2) { + $other->setLogger($this); + $a = false; + if (!$other->validate(PEAR_VALIDATE_NORMAL) || $a = !$main->isEquivalent($other)) { + foreach ($other->getValidationWarnings() as $warning) { + $this->log(0, 'Error: ' . $warning['message']); + } + + foreach ($main->getValidationWarnings() as $warning) { + $this->log(0, 'Error: ' . $warning['message']); + } + + if ($a) { + return $this->raiseError('The two package.xml files are not equivalent!'); + } + + return $this->raiseError("Cannot package, errors in package"); + } + + foreach ($other->getValidationWarnings() as $warning) { + $this->log(1, 'Warning: ' . $warning['message']); + } + + $gen = &$main->getDefaultGenerator(); + $tgzfile = $gen->toTgz2($this, $other, $compress); + if (PEAR::isError($tgzfile)) { + return $tgzfile; + } + + $dest_package = basename($tgzfile); + $pkgdir = dirname($pkgfile); + + // TAR the Package ------------------------------------------- + $this->log(1, "Package $dest_package done"); + if (file_exists("$pkgdir/CVS/Root")) { + $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $pf->getVersion()); + $cvstag = "RELEASE_$cvsversion"; + $this->log(1, 'Tag the released code with "pear cvstag ' . + $main->getPackageFile() . '"'); + $this->log(1, "(or set the CVS tag $cvstag by hand)"); + } elseif (file_exists("$pkgdir/.svn")) { + $svnversion = preg_replace('/[^a-z0-9]/i', '.', $pf->getVersion()); + $svntag = $pf->getName() . "-$svnversion"; + $this->log(1, 'Tag the released code with "pear svntag ' . + $main->getPackageFile() . '"'); + $this->log(1, "(or set the SVN tag $svntag by hand)"); + } + } else { // this branch is executed for single packagefile packaging + $gen = &$pf->getDefaultGenerator(); + $tgzfile = $gen->toTgz($this, $compress); + if (PEAR::isError($tgzfile)) { + $this->log(0, $tgzfile->getMessage()); + return $this->raiseError("Cannot package, errors in package"); + } + + $dest_package = basename($tgzfile); + $pkgdir = dirname($pkgfile); + + // TAR the Package ------------------------------------------- + $this->log(1, "Package $dest_package done"); + if (file_exists("$pkgdir/CVS/Root")) { + $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $pf->getVersion()); + $cvstag = "RELEASE_$cvsversion"; + $this->log(1, "Tag the released code with `pear cvstag $pkgfile'"); + $this->log(1, "(or set the CVS tag $cvstag by hand)"); + } elseif (file_exists("$pkgdir/.svn")) { + $svnversion = preg_replace('/[^a-z0-9]/i', '.', $pf->getVersion()); + $svntag = $pf->getName() . "-$svnversion"; + $this->log(1, "Tag the released code with `pear svntag $pkgfile'"); + $this->log(1, "(or set the SVN tag $svntag by hand)"); + } + } + + return $dest_package; + } +}PEAR-1.9.0/PEAR/Registry.php100664 764 764 224124 100664 10423 + * @author Tomas V. V. Cox + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Registry.php 287555 2009-08-21 21:27:27Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * for PEAR_Error + */ +require_once 'PEAR.php'; +require_once 'PEAR/DependencyDB.php'; + +define('PEAR_REGISTRY_ERROR_LOCK', -2); +define('PEAR_REGISTRY_ERROR_FORMAT', -3); +define('PEAR_REGISTRY_ERROR_FILE', -4); +define('PEAR_REGISTRY_ERROR_CONFLICT', -5); +define('PEAR_REGISTRY_ERROR_CHANNEL_FILE', -6); + +/** + * Administration class used to maintain the installed package database. + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Tomas V. V. Cox + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Registry extends PEAR +{ + /** + * File containing all channel information. + * @var string + */ + var $channels = ''; + + /** Directory where registry files are stored. + * @var string + */ + var $statedir = ''; + + /** File where the file map is stored + * @var string + */ + var $filemap = ''; + + /** Directory where registry files for channels are stored. + * @var string + */ + var $channelsdir = ''; + + /** Name of file used for locking the registry + * @var string + */ + var $lockfile = ''; + + /** File descriptor used during locking + * @var resource + */ + var $lock_fp = null; + + /** Mode used during locking + * @var int + */ + var $lock_mode = 0; // XXX UNUSED + + /** Cache of package information. Structure: + * array( + * 'package' => array('id' => ... ), + * ... ) + * @var array + */ + var $pkginfo_cache = array(); + + /** Cache of file map. Structure: + * array( '/path/to/file' => 'package', ... ) + * @var array + */ + var $filemap_cache = array(); + + /** + * @var false|PEAR_ChannelFile + */ + var $_pearChannel; + + /** + * @var false|PEAR_ChannelFile + */ + var $_peclChannel; + + /** + * @var false|PEAR_ChannelFile + */ + var $_docChannel; + + /** + * @var PEAR_DependencyDB + */ + var $_dependencyDB; + + /** + * @var PEAR_Config + */ + var $_config; + + /** + * PEAR_Registry constructor. * - * @param mixed Either array or string with the command line - * @return array Array of found files - * @static + * @param string (optional) PEAR install directory (for .php files) + * @param PEAR_ChannelFile PEAR_ChannelFile object representing the PEAR channel, if + * default values are not desired. Only used the very first time a PEAR + * repository is initialized + * @param PEAR_ChannelFile PEAR_ChannelFile object representing the PECL channel, if + * default values are not desired. Only used the very first time a PEAR + * repository is initialized * + * @access public */ - function find($args) + function PEAR_Registry($pear_install_dir = PEAR_INSTALL_DIR, $pear_channel = false, + $pecl_channel = false) { - if (!is_array($args)) { - $args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY); + parent::PEAR(); + $this->setInstallDir($pear_install_dir); + $this->_pearChannel = $pear_channel; + $this->_peclChannel = $pecl_channel; + $this->_config = false; + } + + function setInstallDir($pear_install_dir = PEAR_INSTALL_DIR) + { + $ds = DIRECTORY_SEPARATOR; + $this->install_dir = $pear_install_dir; + $this->channelsdir = $pear_install_dir.$ds.'.channels'; + $this->statedir = $pear_install_dir.$ds.'.registry'; + $this->filemap = $pear_install_dir.$ds.'.filemap'; + $this->lockfile = $pear_install_dir.$ds.'.lock'; + } + + function hasWriteAccess() + { + if (!file_exists($this->install_dir)) { + $dir = $this->install_dir; + while ($dir && $dir != '.') { + $olddir = $dir; + $dir = dirname($dir); + if ($dir != '.' && file_exists($dir)) { + if (is_writeable($dir)) { + return true; + } + + return false; + } + + if ($dir == $olddir) { // this can happen in safe mode + return @is_writable($dir); + } + } + + return false; } - $dir = realpath(array_shift($args)); - if (!$dir) { - return array(); + + return is_writeable($this->install_dir); + } + + function setConfig(&$config, $resetInstallDir = true) + { + $this->_config = &$config; + if ($resetInstallDir) { + $this->setInstallDir($config->get('php_dir')); } - $patterns = array(); - $depth = 0; - $do_files = $do_dirs = true; - $args_count = count($args); - for ($i = 0; $i < $args_count; $i++) { - switch ($args[$i]) { - case '-type': - if (in_array($args[$i+1], array('d', 'f'))) { - if ($args[$i+1] == 'd') { - $do_files = false; - } else { - $do_dirs = false; + } + + function _initializeChannelDirs() + { + static $running = false; + if (!$running) { + $running = true; + $ds = DIRECTORY_SEPARATOR; + if (!is_dir($this->channelsdir) || + !file_exists($this->channelsdir . $ds . 'pear.php.net.reg') || + !file_exists($this->channelsdir . $ds . 'pecl.php.net.reg') || + !file_exists($this->channelsdir . $ds . 'doc.php.net.reg') || + !file_exists($this->channelsdir . $ds . '__uri.reg')) { + if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) { + $pear_channel = $this->_pearChannel; + if (!is_a($pear_channel, 'PEAR_ChannelFile') || !$pear_channel->validate()) { + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + + $pear_channel = new PEAR_ChannelFile; + $pear_channel->setAlias('pear'); + $pear_channel->setServer('pear.php.net'); + $pear_channel->setSummary('PHP Extension and Application Repository'); + $pear_channel->setDefaultPEARProtocols(); + $pear_channel->setBaseURL('REST1.0', 'http://pear.php.net/rest/'); + $pear_channel->setBaseURL('REST1.1', 'http://pear.php.net/rest/'); + $pear_channel->setBaseURL('REST1.3', 'http://pear.php.net/rest/'); + //$pear_channel->setBaseURL('REST1.4', 'http://pear.php.net/rest/'); + } else { + $pear_channel->setServer('pear.php.net'); + $pear_channel->setAlias('pear'); + } + + $pear_channel->validate(); + $this->_addChannel($pear_channel); + } + + if (!file_exists($this->channelsdir . $ds . 'pecl.php.net.reg')) { + $pecl_channel = $this->_peclChannel; + if (!is_a($pecl_channel, 'PEAR_ChannelFile') || !$pecl_channel->validate()) { + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; } + + $pecl_channel = new PEAR_ChannelFile; + $pecl_channel->setAlias('pecl'); + $pecl_channel->setServer('pecl.php.net'); + $pecl_channel->setSummary('PHP Extension Community Library'); + $pecl_channel->setDefaultPEARProtocols(); + $pecl_channel->setBaseURL('REST1.0', 'http://pecl.php.net/rest/'); + $pecl_channel->setBaseURL('REST1.1', 'http://pecl.php.net/rest/'); + $pecl_channel->setValidationPackage('PEAR_Validator_PECL', '1.0'); + } else { + $pecl_channel->setServer('pecl.php.net'); + $pecl_channel->setAlias('pecl'); } - $i++; - break; - case '-name': - $name = preg_quote($args[$i+1], '#'); - // our magic characters ? and * have just been escaped, - // so now we change the escaped versions to PCRE operators - $name = strtr($name, array('\?' => '.', '\*' => '.*')); - $patterns[] = '('.$name.')'; - $i++; - break; - case '-maxdepth': - $depth = $args[$i+1]; - break; + + $pecl_channel->validate(); + $this->_addChannel($pecl_channel); + } + + if (!file_exists($this->channelsdir . $ds . 'doc.php.net.reg')) { + $doc_channel = $this->_docChannel; + if (!is_a($doc_channel, 'PEAR_ChannelFile') || !$doc_channel->validate()) { + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + + $doc_channel = new PEAR_ChannelFile; + $doc_channel->setAlias('phpdocs'); + $doc_channel->setServer('doc.php.net'); + $doc_channel->setSummary('PHP Documentation Team'); + $doc_channel->setDefaultPEARProtocols(); + $doc_channel->setBaseURL('REST1.0', 'http://doc.php.net/rest/'); + $doc_channel->setBaseURL('REST1.1', 'http://doc.php.net/rest/'); + $doc_channel->setBaseURL('REST1.3', 'http://doc.php.net/rest/'); + } else { + $doc_channel->setServer('doc.php.net'); + $doc_channel->setAlias('doc'); + } + + $doc_channel->validate(); + $this->_addChannel($doc_channel); + } + + if (!file_exists($this->channelsdir . $ds . '__uri.reg')) { + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + + $private = new PEAR_ChannelFile; + $private->setName('__uri'); + $private->setDefaultPEARProtocols(); + $private->setBaseURL('REST1.0', '****'); + $private->setSummary('Pseudo-channel for static packages'); + $this->_addChannel($private); + } + $this->_rebuildFileMap(); } + + $running = false; } - $path = System::_dirToStruct($dir, $depth, 0, true); - if ($do_files && $do_dirs) { - $files = array_merge($path['files'], $path['dirs']); - } elseif ($do_dirs) { - $files = $path['dirs']; - } else { - $files = $path['files']; - } - if (count($patterns)) { - $dsq = preg_quote(DIRECTORY_SEPARATOR, '#'); - $pattern = '#(^|'.$dsq.')'.implode('|', $patterns).'($|'.$dsq.')#'; - $ret = array(); - $files_count = count($files); - for ($i = 0; $i < $files_count; $i++) { - // only search in the part of the file below the current directory - $filepart = basename($files[$i]); - if (preg_match($pattern, $filepart)) { - $ret[] = $files[$i]; + } + + function _initializeDirs() + { + $ds = DIRECTORY_SEPARATOR; + // XXX Compatibility code should be removed in the future + // rename all registry files if any to lowercase + if (!OS_WINDOWS && file_exists($this->statedir) && is_dir($this->statedir) && + $handle = opendir($this->statedir)) { + $dest = $this->statedir . $ds; + while (false !== ($file = readdir($handle))) { + if (preg_match('/^.*[A-Z].*\.reg\\z/', $file)) { + rename($dest . $file, $dest . strtolower($file)); } } - return $ret; + closedir($handle); } - return $files; + + $this->_initializeChannelDirs(); + if (!file_exists($this->filemap)) { + $this->_rebuildFileMap(); + } + $this->_initializeDepDB(); } -}PEAR-1.8.0/template.spec100777 764 764 3725 100777 10015 Summary: PEAR: @summary@ -Name: @rpm_package@ -Version: @version@ -Release: 1 -License: @release_license@ -Group: Development/Libraries -Source: http://@master_server@/get/@package@-%{version}.tgz -BuildRoot: %{_tmppath}/%{name}-root -URL: http://@master_server@/package/@package@ -Prefix: %{_prefix} -BuildArchitectures: @arch@ -@extra_headers@ -%description -@description@ + function _initializeDepDB() + { + if (!isset($this->_dependencyDB)) { + static $initializing = false; + if (!$initializing) { + $initializing = true; + if (!$this->_config) { // never used? + $file = OS_WINDOWS ? 'pear.ini' : '.pearrc'; + $this->_config = &new PEAR_Config($this->statedir . DIRECTORY_SEPARATOR . + $file); + $this->_config->setRegistry($this); + $this->_config->set('php_dir', $this->install_dir); + } -%prep -rm -rf %{buildroot}/* -%setup -c -T -# XXX Source files location is missing here in pear cmd -pear -v -c %{buildroot}/pearrc \ - -d php_dir=%{_libdir}/php/pear \ - -d doc_dir=/docs \ - -d bin_dir=%{_bindir} \ - -d data_dir=%{_libdir}/php/pear/data \ - -d test_dir=%{_libdir}/php/pear/tests \ - -d ext_dir=%{_libdir} \@extra_config@ - -s + $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->_config); + if (PEAR::isError($this->_dependencyDB)) { + // attempt to recover by removing the dep db + if (file_exists($this->_config->get('php_dir', null, 'pear.php.net') . + DIRECTORY_SEPARATOR . '.depdb')) { + @unlink($this->_config->get('php_dir', null, 'pear.php.net') . + DIRECTORY_SEPARATOR . '.depdb'); + } -%build -echo BuildRoot=%{buildroot} + $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->_config); + if (PEAR::isError($this->_dependencyDB)) { + echo $this->_dependencyDB->getMessage(); + echo 'Unrecoverable error'; + exit(1); + } + } -%postun -# if refcount = 0 then package has been removed (not upgraded) -if [ "$1" -eq "0" ]; then - pear uninstall --nodeps -r @possible_channel@@package@ - rm @rpm_xml_dir@/@package@.xml -fi + $initializing = false; + } + } + } + /** + * PEAR_Registry destructor. Makes sure no locks are forgotten. + * + * @access private + */ + function _PEAR_Registry() + { + parent::_PEAR(); + if (is_resource($this->lock_fp)) { + $this->_unlock(); + } + } -%post -# if refcount = 2 then package has been upgraded -if [ "$1" -ge "2" ]; then - pear upgrade --nodeps -r @rpm_xml_dir@/@package@.xml -else - pear install --nodeps -r @rpm_xml_dir@/@package@.xml -fi + /** + * Make sure the directory where we keep registry files exists. + * + * @return bool TRUE if directory exists, FALSE if it could not be + * created + * + * @access private + */ + function _assertStateDir($channel = false) + { + if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') { + return $this->_assertChannelStateDir($channel); + } -%install -pear -c %{buildroot}/pearrc install --nodeps -R %{buildroot} \ - $RPM_SOURCE_DIR/@package@-%{version}.tgz -rm %{buildroot}/pearrc -rm %{buildroot}/%{_libdir}/php/pear/.filemap -rm %{buildroot}/%{_libdir}/php/pear/.lock -rm -rf %{buildroot}/%{_libdir}/php/pear/.registry -if [ "@doc_files@" != "" ]; then - mv %{buildroot}/docs/@package@/* . - rm -rf %{buildroot}/docs -fi -mkdir -p %{buildroot}@rpm_xml_dir@ -tar -xzf $RPM_SOURCE_DIR/@package@-%{version}.tgz package@package2xml@.xml -cp -p package@package2xml@.xml %{buildroot}@rpm_xml_dir@/@package@.xml + static $init = false; + if (!file_exists($this->statedir)) { + if (!$this->hasWriteAccess()) { + return false; + } -#rm -rf %{buildroot}/* -#pear -q install -R %{buildroot} -n package@package2xml@.xml -#mkdir -p %{buildroot}@rpm_xml_dir@ -#cp -p package@package2xml@.xml %{buildroot}@rpm_xml_dir@/@package@.xml + require_once 'System.php'; + if (!System::mkdir(array('-p', $this->statedir))) { + return $this->raiseError("could not create directory '{$this->statedir}'"); + } + $init = true; + } elseif (!is_dir($this->statedir)) { + return $this->raiseError('Cannot create directory ' . $this->statedir . ', ' . + 'it already exists and is not a directory'); + } -%files - %defattr(-,root,root) - %doc @doc_files@ - / -package.xml100664 764 764 70773 100664 6267 - - - PEAR - PEAR Base System - The PEAR package contains: - * the PEAR installer, for creating, distributing - and installing packages - * the PEAR_Exception PHP5 error handling mechanism - * the PEAR_ErrorStack advanced error handling mechanism - * the PEAR_Error error handling mechanism + $ds = DIRECTORY_SEPARATOR; + if (!file_exists($this->channelsdir)) { + if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg') || + !file_exists($this->channelsdir . $ds . 'pecl.php.net.reg') || + !file_exists($this->channelsdir . $ds . 'doc.php.net.reg') || + !file_exists($this->channelsdir . $ds . '__uri.reg')) { + $init = true; + } + } elseif (!is_dir($this->channelsdir)) { + return $this->raiseError('Cannot create directory ' . $this->channelsdir . ', ' . + 'it already exists and is not a directory'); + } + + if ($init) { + static $running = false; + if (!$running) { + $running = true; + $this->_initializeDirs(); + $running = false; + $init = false; + } + } else { + $this->_initializeDepDB(); + } + + return true; + } + + /** + * Make sure the directory where we keep registry files exists for a non-standard channel. + * + * @param string channel name + * @return bool TRUE if directory exists, FALSE if it could not be + * created + * + * @access private + */ + function _assertChannelStateDir($channel) + { + $ds = DIRECTORY_SEPARATOR; + if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') { + if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) { + $this->_initializeChannelDirs(); + } + return $this->_assertStateDir($channel); + } + + $channelDir = $this->_channelDirectoryName($channel); + if (!is_dir($this->channelsdir) || + !file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) { + $this->_initializeChannelDirs(); + } + + if (!file_exists($channelDir)) { + if (!$this->hasWriteAccess()) { + return false; + } + + require_once 'System.php'; + if (!System::mkdir(array('-p', $channelDir))) { + return $this->raiseError("could not create directory '" . $channelDir . + "'"); + } + } elseif (!is_dir($channelDir)) { + return $this->raiseError("could not create directory '" . $channelDir . + "', already exists and is not a directory"); + } + + return true; + } + + /** + * Make sure the directory where we keep registry files for channels exists + * + * @return bool TRUE if directory exists, FALSE if it could not be + * created + * + * @access private + */ + function _assertChannelDir() + { + if (!file_exists($this->channelsdir)) { + if (!$this->hasWriteAccess()) { + return false; + } + + require_once 'System.php'; + if (!System::mkdir(array('-p', $this->channelsdir))) { + return $this->raiseError("could not create directory '{$this->channelsdir}'"); + } + } elseif (!is_dir($this->channelsdir)) { + return $this->raiseError("could not create directory '{$this->channelsdir}" . + "', it already exists and is not a directory"); + } + + if (!file_exists($this->channelsdir . DIRECTORY_SEPARATOR . '.alias')) { + if (!$this->hasWriteAccess()) { + return false; + } + + require_once 'System.php'; + if (!System::mkdir(array('-p', $this->channelsdir . DIRECTORY_SEPARATOR . '.alias'))) { + return $this->raiseError("could not create directory '{$this->channelsdir}/.alias'"); + } + } elseif (!is_dir($this->channelsdir . DIRECTORY_SEPARATOR . '.alias')) { + return $this->raiseError("could not create directory '{$this->channelsdir}" . + "/.alias', it already exists and is not a directory"); + } + + return true; + } + + /** + * Get the name of the file where data for a given package is stored. + * + * @param string channel name, or false if this is a PEAR package + * @param string package name + * + * @return string registry file name + * + * @access public + */ + function _packageFileName($package, $channel = false) + { + if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') { + return $this->_channelDirectoryName($channel) . DIRECTORY_SEPARATOR . + strtolower($package) . '.reg'; + } + + return $this->statedir . DIRECTORY_SEPARATOR . strtolower($package) . '.reg'; + } + + /** + * Get the name of the file where data for a given channel is stored. + * @param string channel name + * @return string registry file name + */ + function _channelFileName($channel, $noaliases = false) + { + if (!$noaliases) { + if (file_exists($this->_getChannelAliasFileName($channel))) { + $channel = implode('', file($this->_getChannelAliasFileName($channel))); + } + } + return $this->channelsdir . DIRECTORY_SEPARATOR . str_replace('/', '_', + strtolower($channel)) . '.reg'; + } + + /** + * @param string + * @return string + */ + function _getChannelAliasFileName($alias) + { + return $this->channelsdir . DIRECTORY_SEPARATOR . '.alias' . + DIRECTORY_SEPARATOR . str_replace('/', '_', strtolower($alias)) . '.txt'; + } + + /** + * Get the name of a channel from its alias + */ + function _getChannelFromAlias($channel) + { + if (!$this->_channelExists($channel)) { + if ($channel == 'pear.php.net') { + return 'pear.php.net'; + } + + if ($channel == 'pecl.php.net') { + return 'pecl.php.net'; + } + + if ($channel == 'doc.php.net') { + return 'doc.php.net'; + } + + if ($channel == '__uri') { + return '__uri'; + } + + return false; + } + + $channel = strtolower($channel); + if (file_exists($this->_getChannelAliasFileName($channel))) { + // translate an alias to an actual channel + return implode('', file($this->_getChannelAliasFileName($channel))); + } + + return $channel; + } + + /** + * Get the alias of a channel from its alias or its name + */ + function _getAlias($channel) + { + if (!$this->_channelExists($channel)) { + if ($channel == 'pear.php.net') { + return 'pear'; + } + + if ($channel == 'pecl.php.net') { + return 'pecl'; + } + + if ($channel == 'doc.php.net') { + return 'phpdocs'; + } + + return false; + } + + $channel = $this->_getChannel($channel); + if (PEAR::isError($channel)) { + return $channel; + } + + return $channel->getAlias(); + } + + /** + * Get the name of the file where data for a given package is stored. + * + * @param string channel name, or false if this is a PEAR package + * @param string package name + * + * @return string registry file name + * + * @access public + */ + function _channelDirectoryName($channel) + { + if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') { + return $this->statedir; + } + + $ch = $this->_getChannelFromAlias($channel); + if (!$ch) { + $ch = $channel; + } + + return $this->statedir . DIRECTORY_SEPARATOR . strtolower('.channel.' . + str_replace('/', '_', $ch)); + } + + function _openPackageFile($package, $mode, $channel = false) + { + if (!$this->_assertStateDir($channel)) { + return null; + } + + if (!in_array($mode, array('r', 'rb')) && !$this->hasWriteAccess()) { + return null; + } + + $file = $this->_packageFileName($package, $channel); + if (!file_exists($file) && $mode == 'r' || $mode == 'rb') { + return null; + } + + $fp = @fopen($file, $mode); + if (!$fp) { + return null; + } + + return $fp; + } + + function _closePackageFile($fp) + { + fclose($fp); + } + + function _openChannelFile($channel, $mode) + { + if (!$this->_assertChannelDir()) { + return null; + } + + if (!in_array($mode, array('r', 'rb')) && !$this->hasWriteAccess()) { + return null; + } + + $file = $this->_channelFileName($channel); + if (!file_exists($file) && $mode == 'r' || $mode == 'rb') { + return null; + } + + $fp = @fopen($file, $mode); + if (!$fp) { + return null; + } + + return $fp; + } + + function _closeChannelFile($fp) + { + fclose($fp); + } + + function _rebuildFileMap() + { + if (!class_exists('PEAR_Installer_Role')) { + require_once 'PEAR/Installer/Role.php'; + } + + $channels = $this->_listAllPackages(); + $files = array(); + foreach ($channels as $channel => $packages) { + foreach ($packages as $package) { + $version = $this->_packageInfo($package, 'version', $channel); + $filelist = $this->_packageInfo($package, 'filelist', $channel); + if (!is_array($filelist)) { + continue; + } + + foreach ($filelist as $name => $attrs) { + if (isset($attrs['attribs'])) { + $attrs = $attrs['attribs']; + } + + // it is possible for conflicting packages in different channels to + // conflict with data files/doc files + if ($name == 'dirtree') { + continue; + } + + if (isset($attrs['role']) && !in_array($attrs['role'], + PEAR_Installer_Role::getInstallableRoles())) { + // these are not installed + continue; + } + + if (isset($attrs['role']) && !in_array($attrs['role'], + PEAR_Installer_Role::getBaseinstallRoles())) { + $attrs['baseinstalldir'] = $package; + } + + if (isset($attrs['baseinstalldir'])) { + $file = $attrs['baseinstalldir'].DIRECTORY_SEPARATOR.$name; + } else { + $file = $name; + } + + $file = preg_replace(',^/+,', '', $file); + if ($channel != 'pear.php.net') { + if (!isset($files[$attrs['role']])) { + $files[$attrs['role']] = array(); + } + $files[$attrs['role']][$file] = array(strtolower($channel), + strtolower($package)); + } else { + if (!isset($files[$attrs['role']])) { + $files[$attrs['role']] = array(); + } + $files[$attrs['role']][$file] = strtolower($package); + } + } + } + } + + + $this->_assertStateDir(); + if (!$this->hasWriteAccess()) { + return false; + } + + $fp = @fopen($this->filemap, 'wb'); + if (!$fp) { + return false; + } + + $this->filemap_cache = $files; + fwrite($fp, serialize($files)); + fclose($fp); + return true; + } + + function _readFileMap() + { + if (!file_exists($this->filemap)) { + return array(); + } + + $fp = @fopen($this->filemap, 'r'); + if (!$fp) { + return $this->raiseError('PEAR_Registry: could not open filemap "' . $this->filemap . '"', PEAR_REGISTRY_ERROR_FILE, null, null, $php_errormsg); + } + + clearstatcache(); + $rt = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + $fsize = filesize($this->filemap); + fclose($fp); + $data = file_get_contents($this->filemap); + set_magic_quotes_runtime($rt); + $tmp = unserialize($data); + if (!$tmp && $fsize > 7) { + return $this->raiseError('PEAR_Registry: invalid filemap data', PEAR_REGISTRY_ERROR_FORMAT, null, null, $data); + } + + $this->filemap_cache = $tmp; + return true; + } + + /** + * Lock the registry. + * + * @param integer lock mode, one of LOCK_EX, LOCK_SH or LOCK_UN. + * See flock manual for more information. + * + * @return bool TRUE on success, FALSE if locking failed, or a + * PEAR error if some other error occurs (such as the + * lock file not being writable). + * + * @access private + */ + function _lock($mode = LOCK_EX) + { + if (stristr(php_uname(), 'Windows 9')) { + return true; + } + + if ($mode != LOCK_UN && is_resource($this->lock_fp)) { + // XXX does not check type of lock (LOCK_SH/LOCK_EX) + return true; + } + + if (!$this->_assertStateDir()) { + if ($mode == LOCK_EX) { + return $this->raiseError('Registry directory is not writeable by the current user'); + } + + return true; + } + + $open_mode = 'w'; + // XXX People reported problems with LOCK_SH and 'w' + if ($mode === LOCK_SH || $mode === LOCK_UN) { + if (!file_exists($this->lockfile)) { + touch($this->lockfile); + } + $open_mode = 'r'; + } + + if (!is_resource($this->lock_fp)) { + $this->lock_fp = @fopen($this->lockfile, $open_mode); + } + + if (!is_resource($this->lock_fp)) { + $this->lock_fp = null; + return $this->raiseError("could not create lock file" . + (isset($php_errormsg) ? ": " . $php_errormsg : "")); + } + + if (!(int)flock($this->lock_fp, $mode)) { + switch ($mode) { + case LOCK_SH: $str = 'shared'; break; + case LOCK_EX: $str = 'exclusive'; break; + case LOCK_UN: $str = 'unlock'; break; + default: $str = 'unknown'; break; + } + + //is resource at this point, close it on error. + fclose($this->lock_fp); + $this->lock_fp = null; + return $this->raiseError("could not acquire $str lock ($this->lockfile)", + PEAR_REGISTRY_ERROR_LOCK); + } + + return true; + } + + function _unlock() + { + $ret = $this->_lock(LOCK_UN); + if (is_resource($this->lock_fp)) { + fclose($this->lock_fp); + } + + $this->lock_fp = null; + return $ret; + } + + function _packageExists($package, $channel = false) + { + return file_exists($this->_packageFileName($package, $channel)); + } + + /** + * Determine whether a channel exists in the registry + * + * @param string Channel name + * @param bool if true, then aliases will be ignored + * @return boolean + */ + function _channelExists($channel, $noaliases = false) + { + $a = file_exists($this->_channelFileName($channel, $noaliases)); + if (!$a && $channel == 'pear.php.net') { + return true; + } + + if (!$a && $channel == 'pecl.php.net') { + return true; + } + + if (!$a && $channel == 'doc.php.net') { + return true; + } + + return $a; + } + + /** + * Determine whether a mirror exists within the deafult channel in the registry + * + * @param string Channel name + * @param string Mirror name + * + * @return boolean + */ + function _mirrorExists($channel, $mirror) + { + $data = $this->_channelInfo($channel); + if (!isset($data['servers']['mirror'])) { + return false; + } + + foreach ($data['servers']['mirror'] as $m) { + if ($m['attribs']['host'] == $mirror) { + return true; + } + } + + return false; + } + + /** + * @param PEAR_ChannelFile Channel object + * @param donotuse + * @param string Last-Modified HTTP tag from remote request + * @return boolean|PEAR_Error True on creation, false if it already exists + */ + function _addChannel($channel, $update = false, $lastmodified = false) + { + if (!is_a($channel, 'PEAR_ChannelFile')) { + return false; + } + + if (!$channel->validate()) { + return false; + } + + if (file_exists($this->_channelFileName($channel->getName()))) { + if (!$update) { + return false; + } + + $checker = $this->_getChannel($channel->getName()); + if (PEAR::isError($checker)) { + return $checker; + } + + if ($channel->getAlias() != $checker->getAlias()) { + if (file_exists($this->_getChannelAliasFileName($checker->getAlias()))) { + @unlink($this->_getChannelAliasFileName($checker->getAlias())); + } + } + } else { + if ($update && !in_array($channel->getName(), array('pear.php.net', 'pecl.php.net', 'doc.php.net'))) { + return false; + } + } + + $ret = $this->_assertChannelDir(); + if (PEAR::isError($ret)) { + return $ret; + } + + $ret = $this->_assertChannelStateDir($channel->getName()); + if (PEAR::isError($ret)) { + return $ret; + } + + if ($channel->getAlias() != $channel->getName()) { + if (file_exists($this->_getChannelAliasFileName($channel->getAlias())) && + $this->_getChannelFromAlias($channel->getAlias()) != $channel->getName()) { + $channel->setAlias($channel->getName()); + } + + if (!$this->hasWriteAccess()) { + return false; + } + + $fp = @fopen($this->_getChannelAliasFileName($channel->getAlias()), 'w'); + if (!$fp) { + return false; + } + + fwrite($fp, $channel->getName()); + fclose($fp); + } + + if (!$this->hasWriteAccess()) { + return false; + } + + $fp = @fopen($this->_channelFileName($channel->getName()), 'wb'); + if (!$fp) { + return false; + } + + $info = $channel->toArray(); + if ($lastmodified) { + $info['_lastmodified'] = $lastmodified; + } else { + $info['_lastmodified'] = date('r'); + } + + fwrite($fp, serialize($info)); + fclose($fp); + return true; + } + + /** + * Deletion fails if there are any packages installed from the channel + * @param string|PEAR_ChannelFile channel name + * @return boolean|PEAR_Error True on deletion, false if it doesn't exist + */ + function _deleteChannel($channel) + { + if (!is_string($channel)) { + if (!is_a($channel, 'PEAR_ChannelFile')) { + return false; + } + + if (!$channel->validate()) { + return false; + } + $channel = $channel->getName(); + } + + if ($this->_getChannelFromAlias($channel) == '__uri') { + return false; + } + + if ($this->_getChannelFromAlias($channel) == 'pecl.php.net') { + return false; + } + + if ($this->_getChannelFromAlias($channel) == 'doc.php.net') { + return false; + } + + if (!$this->_channelExists($channel)) { + return false; + } + + if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') { + return false; + } + + $channel = $this->_getChannelFromAlias($channel); + if ($channel == 'pear.php.net') { + return false; + } + + $test = $this->_listChannelPackages($channel); + if (count($test)) { + return false; + } + + $test = @rmdir($this->_channelDirectoryName($channel)); + if (!$test) { + return false; + } + + $file = $this->_getChannelAliasFileName($this->_getAlias($channel)); + if (file_exists($file)) { + $test = @unlink($file); + if (!$test) { + return false; + } + } + + $file = $this->_channelFileName($channel); + $ret = true; + if (file_exists($file)) { + $ret = @unlink($file); + } + + return $ret; + } + + /** + * Determine whether a channel exists in the registry + * @param string Channel Alias + * @return boolean + */ + function _isChannelAlias($alias) + { + return file_exists($this->_getChannelAliasFileName($alias)); + } + + /** + * @param string|null + * @param string|null + * @param string|null + * @return array|null + * @access private + */ + function _packageInfo($package = null, $key = null, $channel = 'pear.php.net') + { + if ($package === null) { + if ($channel === null) { + $channels = $this->_listChannels(); + $ret = array(); + foreach ($channels as $channel) { + $channel = strtolower($channel); + $ret[$channel] = array(); + $packages = $this->_listPackages($channel); + foreach ($packages as $package) { + $ret[$channel][] = $this->_packageInfo($package, null, $channel); + } + } + + return $ret; + } + + $ps = $this->_listPackages($channel); + if (!count($ps)) { + return array(); + } + return array_map(array(&$this, '_packageInfo'), + $ps, array_fill(0, count($ps), null), + array_fill(0, count($ps), $channel)); + } + + $fp = $this->_openPackageFile($package, 'r', $channel); + if ($fp === null) { + return null; + } + + $rt = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + clearstatcache(); + $this->_closePackageFile($fp); + $data = file_get_contents($this->_packageFileName($package, $channel)); + set_magic_quotes_runtime($rt); + $data = unserialize($data); + if ($key === null) { + return $data; + } + + // compatibility for package.xml version 2.0 + if (isset($data['old'][$key])) { + return $data['old'][$key]; + } + + if (isset($data[$key])) { + return $data[$key]; + } + + return null; + } + + /** + * @param string Channel name + * @param bool whether to strictly retrieve info of channels, not just aliases + * @return array|null + */ + function _channelInfo($channel, $noaliases = false) + { + if (!$this->_channelExists($channel, $noaliases)) { + return null; + } + + $fp = $this->_openChannelFile($channel, 'r'); + if ($fp === null) { + return null; + } + + $rt = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + clearstatcache(); + $this->_closeChannelFile($fp); + $data = file_get_contents($this->_channelFileName($channel)); + set_magic_quotes_runtime($rt); + $data = unserialize($data); + return $data; + } + + function _listChannels() + { + $channellist = array(); + if (!file_exists($this->channelsdir) || !is_dir($this->channelsdir)) { + return array('pear.php.net', 'pecl.php.net', 'doc.php.net', '__uri'); + } + + $dp = opendir($this->channelsdir); + while ($ent = readdir($dp)) { + if ($ent{0} == '.' || substr($ent, -4) != '.reg') { + continue; + } + + if ($ent == '__uri.reg') { + $channellist[] = '__uri'; + continue; + } + + $channellist[] = str_replace('_', '/', substr($ent, 0, -4)); + } + + closedir($dp); + if (!in_array('pear.php.net', $channellist)) { + $channellist[] = 'pear.php.net'; + } + + if (!in_array('pecl.php.net', $channellist)) { + $channellist[] = 'pecl.php.net'; + } + + if (!in_array('doc.php.net', $channellist)) { + $channellist[] = 'doc.php.net'; + } + + + if (!in_array('__uri', $channellist)) { + $channellist[] = '__uri'; + } + + natsort($channellist); + return $channellist; + } + + function _listPackages($channel = false) + { + if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') { + return $this->_listChannelPackages($channel); + } + + if (!file_exists($this->statedir) || !is_dir($this->statedir)) { + return array(); + } + + $pkglist = array(); + $dp = opendir($this->statedir); + if (!$dp) { + return $pkglist; + } + + while ($ent = readdir($dp)) { + if ($ent{0} == '.' || substr($ent, -4) != '.reg') { + continue; + } + + $pkglist[] = substr($ent, 0, -4); + } + closedir($dp); + return $pkglist; + } + + function _listChannelPackages($channel) + { + $pkglist = array(); + if (!file_exists($this->_channelDirectoryName($channel)) || + !is_dir($this->_channelDirectoryName($channel))) { + return array(); + } + + $dp = opendir($this->_channelDirectoryName($channel)); + if (!$dp) { + return $pkglist; + } + + while ($ent = readdir($dp)) { + if ($ent{0} == '.' || substr($ent, -4) != '.reg') { + continue; + } + $pkglist[] = substr($ent, 0, -4); + } + + closedir($dp); + return $pkglist; + } + + function _listAllPackages() + { + $ret = array(); + foreach ($this->_listChannels() as $channel) { + $ret[$channel] = $this->_listPackages($channel); + } + + return $ret; + } + + /** + * Add an installed package to the registry + * @param string package name + * @param array package info (parsed by PEAR_Common::infoFrom*() methods) + * @return bool success of saving + * @access private + */ + function _addPackage($package, $info) + { + if ($this->_packageExists($package)) { + return false; + } + + $fp = $this->_openPackageFile($package, 'wb'); + if ($fp === null) { + return false; + } + + $info['_lastmodified'] = time(); + fwrite($fp, serialize($info)); + $this->_closePackageFile($fp); + if (isset($info['filelist'])) { + $this->_rebuildFileMap(); + } + + return true; + } + + /** + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @return bool + * @access private + */ + function _addPackage2($info) + { + if (!is_a($info, 'PEAR_PackageFile_v1') && !is_a($info, 'PEAR_PackageFile_v2')) { + return false; + } + + if (!$info->validate()) { + if (class_exists('PEAR_Common')) { + $ui = PEAR_Frontend::singleton(); + if ($ui) { + foreach ($info->getValidationWarnings() as $err) { + $ui->log($err['message'], true); + } + } + } + return false; + } + + $channel = $info->getChannel(); + $package = $info->getPackage(); + $save = $info; + if ($this->_packageExists($package, $channel)) { + return false; + } + + if (!$this->_channelExists($channel, true)) { + return false; + } + + $info = $info->toArray(true); + if (!$info) { + return false; + } + + $fp = $this->_openPackageFile($package, 'wb', $channel); + if ($fp === null) { + return false; + } + + $info['_lastmodified'] = time(); + fwrite($fp, serialize($info)); + $this->_closePackageFile($fp); + $this->_rebuildFileMap(); + return true; + } + + /** + * @param string Package name + * @param array parsed package.xml 1.0 + * @param bool this parameter is only here for BC. Don't use it. + * @access private + */ + function _updatePackage($package, $info, $merge = true) + { + $oldinfo = $this->_packageInfo($package); + if (empty($oldinfo)) { + return false; + } + + $fp = $this->_openPackageFile($package, 'w'); + if ($fp === null) { + return false; + } + + if (is_object($info)) { + $info = $info->toArray(); + } + $info['_lastmodified'] = time(); + + $newinfo = $info; + if ($merge) { + $info = array_merge($oldinfo, $info); + } else { + $diff = $info; + } + + fwrite($fp, serialize($info)); + $this->_closePackageFile($fp); + if (isset($newinfo['filelist'])) { + $this->_rebuildFileMap(); + } + + return true; + } + + /** + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @return bool + * @access private + */ + function _updatePackage2($info) + { + if (!$this->_packageExists($info->getPackage(), $info->getChannel())) { + return false; + } + + $fp = $this->_openPackageFile($info->getPackage(), 'w', $info->getChannel()); + if ($fp === null) { + return false; + } + + $save = $info; + $info = $save->getArray(true); + $info['_lastmodified'] = time(); + fwrite($fp, serialize($info)); + $this->_closePackageFile($fp); + $this->_rebuildFileMap(); + return true; + } + + /** + * @param string Package name + * @param string Channel name + * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|null + * @access private + */ + function &_getPackage($package, $channel = 'pear.php.net') + { + $info = $this->_packageInfo($package, null, $channel); + if ($info === null) { + return $info; + } + + $a = $this->_config; + if (!$a) { + $this->_config = &new PEAR_Config; + $this->_config->set('php_dir', $this->statedir); + } + + if (!class_exists('PEAR_PackageFile')) { + require_once 'PEAR/PackageFile.php'; + } + + $pkg = &new PEAR_PackageFile($this->_config); + $pf = &$pkg->fromArray($info); + return $pf; + } + + /** + * @param string channel name + * @param bool whether to strictly retrieve channel names + * @return PEAR_ChannelFile|PEAR_Error + * @access private + */ + function &_getChannel($channel, $noaliases = false) + { + $ch = false; + if ($this->_channelExists($channel, $noaliases)) { + $chinfo = $this->_channelInfo($channel, $noaliases); + if ($chinfo) { + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + + $ch = &PEAR_ChannelFile::fromArrayWithErrors($chinfo); + } + } + + if ($ch) { + if ($ch->validate()) { + return $ch; + } + + foreach ($ch->getErrors(true) as $err) { + $message = $err['message'] . "\n"; + } + + $ch = PEAR::raiseError($message); + return $ch; + } + + if ($this->_getChannelFromAlias($channel) == 'pear.php.net') { + // the registry is not properly set up, so use defaults + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + + $pear_channel = new PEAR_ChannelFile; + $pear_channel->setServer('pear.php.net'); + $pear_channel->setAlias('pear'); + $pear_channel->setSummary('PHP Extension and Application Repository'); + $pear_channel->setDefaultPEARProtocols(); + $pear_channel->setBaseURL('REST1.0', 'http://pear.php.net/rest/'); + $pear_channel->setBaseURL('REST1.1', 'http://pear.php.net/rest/'); + $pear_channel->setBaseURL('REST1.3', 'http://pear.php.net/rest/'); + return $pear_channel; + } + + if ($this->_getChannelFromAlias($channel) == 'pecl.php.net') { + // the registry is not properly set up, so use defaults + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + $pear_channel = new PEAR_ChannelFile; + $pear_channel->setServer('pecl.php.net'); + $pear_channel->setAlias('pecl'); + $pear_channel->setSummary('PHP Extension Community Library'); + $pear_channel->setDefaultPEARProtocols(); + $pear_channel->setBaseURL('REST1.0', 'http://pecl.php.net/rest/'); + $pear_channel->setBaseURL('REST1.1', 'http://pecl.php.net/rest/'); + $pear_channel->setValidationPackage('PEAR_Validator_PECL', '1.0'); + return $pear_channel; + } + + if ($this->_getChannelFromAlias($channel) == 'doc.php.net') { + // the registry is not properly set up, so use defaults + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + + $doc_channel = new PEAR_ChannelFile; + $doc_channel->setServer('doc.php.net'); + $doc_channel->setAlias('phpdocs'); + $doc_channel->setSummary('PHP Documentation Team'); + $doc_channel->setDefaultPEARProtocols(); + $doc_channel->setBaseURL('REST1.0', 'http://doc.php.net/rest/'); + $doc_channel->setBaseURL('REST1.1', 'http://doc.php.net/rest/'); + $doc_channel->setBaseURL('REST1.3', 'http://doc.php.net/rest/'); + return $doc_channel; + } + + + if ($this->_getChannelFromAlias($channel) == '__uri') { + // the registry is not properly set up, so use defaults + if (!class_exists('PEAR_ChannelFile')) { + require_once 'PEAR/ChannelFile.php'; + } + + $private = new PEAR_ChannelFile; + $private->setName('__uri'); + $private->setDefaultPEARProtocols(); + $private->setBaseURL('REST1.0', '****'); + $private->setSummary('Pseudo-channel for static packages'); + return $private; + } + + return $ch; + } + + /** + * @param string Package name + * @param string Channel name + * @return bool + */ + function packageExists($package, $channel = 'pear.php.net') + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_packageExists($package, $channel); + $this->_unlock(); + return $ret; + } + + // }}} + + // {{{ channelExists() + + /** + * @param string channel name + * @param bool if true, then aliases will be ignored + * @return bool + */ + function channelExists($channel, $noaliases = false) + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_channelExists($channel, $noaliases); + $this->_unlock(); + return $ret; + } + + // }}} + + /** + * @param string channel name mirror is in + * @param string mirror name + * + * @return bool + */ + function mirrorExists($channel, $mirror) + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + + $ret = $this->_mirrorExists($channel, $mirror); + $this->_unlock(); + return $ret; + } + + // {{{ isAlias() + + /** + * Determines whether the parameter is an alias of a channel + * @param string + * @return bool + */ + function isAlias($alias) + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_isChannelAlias($alias); + $this->_unlock(); + return $ret; + } + + // }}} + // {{{ packageInfo() + + /** + * @param string|null + * @param string|null + * @param string + * @return array|null + */ + function packageInfo($package = null, $key = null, $channel = 'pear.php.net') + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_packageInfo($package, $key, $channel); + $this->_unlock(); + return $ret; + } + + // }}} + // {{{ channelInfo() + + /** + * Retrieve a raw array of channel data. + * + * Do not use this, instead use {@link getChannel()} for normal + * operations. Array structure is undefined in this method + * @param string channel name + * @param bool whether to strictly retrieve information only on non-aliases + * @return array|null|PEAR_Error + */ + function channelInfo($channel = null, $noaliases = false) + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_channelInfo($channel, $noaliases); + $this->_unlock(); + return $ret; + } + + // }}} + + /** + * @param string + */ + function channelName($channel) + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_getChannelFromAlias($channel); + $this->_unlock(); + return $ret; + } + + /** + * @param string + */ + function channelAlias($channel) + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_getAlias($channel); + $this->_unlock(); + return $ret; + } + // {{{ listPackages() + + function listPackages($channel = false) + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_listPackages($channel); + $this->_unlock(); + return $ret; + } + + // }}} + // {{{ listAllPackages() + + function listAllPackages() + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_listAllPackages(); + $this->_unlock(); + return $ret; + } + + // }}} + // {{{ listChannel() + + function listChannels() + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_listChannels(); + $this->_unlock(); + return $ret; + } + + // }}} + // {{{ addPackage() + + /** + * Add an installed package to the registry + * @param string|PEAR_PackageFile_v1|PEAR_PackageFile_v2 package name or object + * that will be passed to {@link addPackage2()} + * @param array package info (parsed by PEAR_Common::infoFrom*() methods) + * @return bool success of saving + */ + function addPackage($package, $info) + { + if (is_object($info)) { + return $this->addPackage2($info); + } + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; + } + $ret = $this->_addPackage($package, $info); + $this->_unlock(); + if ($ret) { + if (!class_exists('PEAR_PackageFile_v1')) { + require_once 'PEAR/PackageFile/v1.php'; + } + $pf = new PEAR_PackageFile_v1; + $pf->setConfig($this->_config); + $pf->fromArray($info); + $this->_dependencyDB->uninstallPackage($pf); + $this->_dependencyDB->installPackage($pf); + } + return $ret; + } + + // }}} + // {{{ addPackage2() + + function addPackage2($info) + { + if (!is_object($info)) { + return $this->addPackage($info['package'], $info); + } + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; + } + $ret = $this->_addPackage2($info); + $this->_unlock(); + if ($ret) { + $this->_dependencyDB->uninstallPackage($info); + $this->_dependencyDB->installPackage($info); + } + return $ret; + } + + // }}} + // {{{ updateChannel() + + /** + * For future expandibility purposes, separate this + * @param PEAR_ChannelFile + */ + function updateChannel($channel, $lastmodified = null) + { + if ($channel->getName() == '__uri') { + return false; + } + return $this->addChannel($channel, $lastmodified, true); + } + + // }}} + // {{{ deleteChannel() + + /** + * Deletion fails if there are any packages installed from the channel + * @param string|PEAR_ChannelFile channel name + * @return boolean|PEAR_Error True on deletion, false if it doesn't exist + */ + function deleteChannel($channel) + { + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; + } + + $ret = $this->_deleteChannel($channel); + $this->_unlock(); + if ($ret && is_a($this->_config, 'PEAR_Config')) { + $this->_config->setChannels($this->listChannels()); + } + + return $ret; + } + + // }}} + // {{{ addChannel() + + /** + * @param PEAR_ChannelFile Channel object + * @param string Last-Modified header from HTTP for caching + * @return boolean|PEAR_Error True on creation, false if it already exists + */ + function addChannel($channel, $lastmodified = false, $update = false) + { + if (!is_a($channel, 'PEAR_ChannelFile') || !$channel->validate()) { + return false; + } + + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; + } + + $ret = $this->_addChannel($channel, $update, $lastmodified); + $this->_unlock(); + if (!$update && $ret && is_a($this->_config, 'PEAR_Config')) { + $this->_config->setChannels($this->listChannels()); + } + + return $ret; + } + + // }}} + // {{{ deletePackage() + + function deletePackage($package, $channel = 'pear.php.net') + { + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; + } + + $file = $this->_packageFileName($package, $channel); + $ret = file_exists($file) ? @unlink($file) : false; + $this->_rebuildFileMap(); + $this->_unlock(); + $p = array('channel' => $channel, 'package' => $package); + $this->_dependencyDB->uninstallPackage($p); + return $ret; + } + + // }}} + // {{{ updatePackage() + + function updatePackage($package, $info, $merge = true) + { + if (is_object($info)) { + return $this->updatePackage2($info, $merge); + } + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; + } + $ret = $this->_updatePackage($package, $info, $merge); + $this->_unlock(); + if ($ret) { + if (!class_exists('PEAR_PackageFile_v1')) { + require_once 'PEAR/PackageFile/v1.php'; + } + $pf = new PEAR_PackageFile_v1; + $pf->setConfig($this->_config); + $pf->fromArray($this->packageInfo($package)); + $this->_dependencyDB->uninstallPackage($pf); + $this->_dependencyDB->installPackage($pf); + } + return $ret; + } + + // }}} + // {{{ updatePackage2() + + function updatePackage2($info) + { + + if (!is_object($info)) { + return $this->updatePackage($info['package'], $info, $merge); + } + + if (!$info->validate(PEAR_VALIDATE_DOWNLOADING)) { + return false; + } + + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; + } + + $ret = $this->_updatePackage2($info); + $this->_unlock(); + if ($ret) { + $this->_dependencyDB->uninstallPackage($info); + $this->_dependencyDB->installPackage($info); + } + + return $ret; + } + + // }}} + // {{{ getChannel() + /** + * @param string channel name + * @param bool whether to strictly return raw channels (no aliases) + * @return PEAR_ChannelFile|PEAR_Error + */ + function &getChannel($channel, $noaliases = false) + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = &$this->_getChannel($channel, $noaliases); + $this->_unlock(); + if (!$ret) { + return PEAR::raiseError('Unknown channel: ' . $channel); + } + return $ret; + } + + // }}} + // {{{ getPackage() + /** + * @param string package name + * @param string channel name + * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|null + */ + function &getPackage($package, $channel = 'pear.php.net') + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $pf = &$this->_getPackage($package, $channel); + $this->_unlock(); + return $pf; + } + + // }}} + + /** + * Get PEAR_PackageFile_v[1/2] objects representing the contents of + * a dependency group that are installed. + * + * This is used at uninstall-time + * @param array + * @return array|false + */ + function getInstalledGroup($group) + { + $ret = array(); + if (isset($group['package'])) { + if (!isset($group['package'][0])) { + $group['package'] = array($group['package']); + } + foreach ($group['package'] as $package) { + $depchannel = isset($package['channel']) ? $package['channel'] : '__uri'; + $p = &$this->getPackage($package['name'], $depchannel); + if ($p) { + $save = &$p; + $ret[] = &$save; + } + } + } + if (isset($group['subpackage'])) { + if (!isset($group['subpackage'][0])) { + $group['subpackage'] = array($group['subpackage']); + } + foreach ($group['subpackage'] as $package) { + $depchannel = isset($package['channel']) ? $package['channel'] : '__uri'; + $p = &$this->getPackage($package['name'], $depchannel); + if ($p) { + $save = &$p; + $ret[] = &$save; + } + } + } + if (!count($ret)) { + return false; + } + return $ret; + } + + // {{{ getChannelValidator() + /** + * @param string channel name + * @return PEAR_Validate|false + */ + function &getChannelValidator($channel) + { + $chan = $this->getChannel($channel); + if (PEAR::isError($chan)) { + return $chan; + } + $val = $chan->getValidationObject(); + return $val; + } + // }}} + // {{{ getChannels() + /** + * @param string channel name + * @return array an array of PEAR_ChannelFile objects representing every installed channel + */ + function &getChannels() + { + $ret = array(); + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + foreach ($this->_listChannels() as $channel) { + $e = &$this->_getChannel($channel); + if (!$e || PEAR::isError($e)) { + continue; + } + $ret[] = $e; + } + $this->_unlock(); + return $ret; + } + + // }}} + // {{{ checkFileMap() + + /** + * Test whether a file or set of files belongs to a package. + * + * If an array is passed in + * @param string|array file path, absolute or relative to the pear + * install dir + * @param string|array name of PEAR package or array('package' => name, 'channel' => + * channel) of a package that will be ignored + * @param string API version - 1.1 will exclude any files belonging to a package + * @param array private recursion variable + * @return array|false which package and channel the file belongs to, or an empty + * string if the file does not belong to an installed package, + * or belongs to the second parameter's package + */ + function checkFileMap($path, $package = false, $api = '1.0', $attrs = false) + { + if (is_array($path)) { + static $notempty; + if (empty($notempty)) { + if (!class_exists('PEAR_Installer_Role')) { + require_once 'PEAR/Installer/Role.php'; + } + $notempty = create_function('$a','return !empty($a);'); + } + $package = is_array($package) ? array(strtolower($package[0]), strtolower($package[1])) + : strtolower($package); + $pkgs = array(); + foreach ($path as $name => $attrs) { + if (is_array($attrs)) { + if (isset($attrs['install-as'])) { + $name = $attrs['install-as']; + } + if (!in_array($attrs['role'], PEAR_Installer_Role::getInstallableRoles())) { + // these are not installed + continue; + } + if (!in_array($attrs['role'], PEAR_Installer_Role::getBaseinstallRoles())) { + $attrs['baseinstalldir'] = is_array($package) ? $package[1] : $package; + } + if (isset($attrs['baseinstalldir'])) { + $name = $attrs['baseinstalldir'] . DIRECTORY_SEPARATOR . $name; + } + } + $pkgs[$name] = $this->checkFileMap($name, $package, $api, $attrs); + if (PEAR::isError($pkgs[$name])) { + return $pkgs[$name]; + } + } + return array_filter($pkgs, $notempty); + } + if (empty($this->filemap_cache)) { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $err = $this->_readFileMap(); + $this->_unlock(); + if (PEAR::isError($err)) { + return $err; + } + } + if (!$attrs) { + $attrs = array('role' => 'php'); // any old call would be for PHP role only + } + if (isset($this->filemap_cache[$attrs['role']][$path])) { + if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path] == $package) { + return false; + } + return $this->filemap_cache[$attrs['role']][$path]; + } + $l = strlen($this->install_dir); + if (substr($path, 0, $l) == $this->install_dir) { + $path = preg_replace('!^'.DIRECTORY_SEPARATOR.'+!', '', substr($path, $l)); + } + if (isset($this->filemap_cache[$attrs['role']][$path])) { + if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path] == $package) { + return false; + } + return $this->filemap_cache[$attrs['role']][$path]; + } + return false; + } + + // }}} + // {{{ flush() + /** + * Force a reload of the filemap + * @since 1.5.0RC3 + */ + function flushFileMap() + { + $this->filemap_cache = null; + clearstatcache(); // ensure that the next read gets the full, current filemap + } + + // }}} + // {{{ apiVersion() + /** + * Get the expected API version. Channels API is version 1.1, as it is backwards + * compatible with 1.0 + * @return string + */ + function apiVersion() + { + return '1.1'; + } + // }}} + + + /** + * Parse a package name, or validate a parsed package name array + * @param string|array pass in an array of format + * array( + * 'package' => 'pname', + * ['channel' => 'channame',] + * ['version' => 'version',] + * ['state' => 'state',] + * ['group' => 'groupname']) + * or a string of format + * [channel://][channame/]pname[-version|-state][/group=groupname] + * @return array|PEAR_Error + */ + function parsePackageName($param, $defaultchannel = 'pear.php.net') + { + $saveparam = $param; + if (is_array($param)) { + // convert to string for error messages + $saveparam = $this->parsedPackageNameToString($param); + // process the array + if (!isset($param['package'])) { + return PEAR::raiseError('parsePackageName(): array $param ' . + 'must contain a valid package name in index "param"', + 'package', null, null, $param); + } + if (!isset($param['uri'])) { + if (!isset($param['channel'])) { + $param['channel'] = $defaultchannel; + } + } else { + $param['channel'] = '__uri'; + } + } else { + $components = @parse_url((string) $param); + if (isset($components['scheme'])) { + if ($components['scheme'] == 'http') { + // uri package + $param = array('uri' => $param, 'channel' => '__uri'); + } elseif($components['scheme'] != 'channel') { + return PEAR::raiseError('parsePackageName(): only channel:// uris may ' . + 'be downloaded, not "' . $param . '"', 'invalid', null, null, $param); + } + } + if (!isset($components['path'])) { + return PEAR::raiseError('parsePackageName(): array $param ' . + 'must contain a valid package name in "' . $param . '"', + 'package', null, null, $param); + } + if (isset($components['host'])) { + // remove the leading "/" + $components['path'] = substr($components['path'], 1); + } + if (!isset($components['scheme'])) { + if (strpos($components['path'], '/') !== false) { + if ($components['path']{0} == '/') { + return PEAR::raiseError('parsePackageName(): this is not ' . + 'a package name, it begins with "/" in "' . $param . '"', + 'invalid', null, null, $param); + } + $parts = explode('/', $components['path']); + $components['host'] = array_shift($parts); + if (count($parts) > 1) { + $components['path'] = array_pop($parts); + $components['host'] .= '/' . implode('/', $parts); + } else { + $components['path'] = implode('/', $parts); + } + } else { + $components['host'] = $defaultchannel; + } + } else { + if (strpos($components['path'], '/')) { + $parts = explode('/', $components['path']); + $components['path'] = array_pop($parts); + $components['host'] .= '/' . implode('/', $parts); + } + } + + if (is_array($param)) { + $param['package'] = $components['path']; + } else { + $param = array( + 'package' => $components['path'] + ); + if (isset($components['host'])) { + $param['channel'] = $components['host']; + } + } + if (isset($components['fragment'])) { + $param['group'] = $components['fragment']; + } + if (isset($components['user'])) { + $param['user'] = $components['user']; + } + if (isset($components['pass'])) { + $param['pass'] = $components['pass']; + } + if (isset($components['query'])) { + parse_str($components['query'], $param['opts']); + } + // check for extension + $pathinfo = pathinfo($param['package']); + if (isset($pathinfo['extension']) && + in_array(strtolower($pathinfo['extension']), array('tgz', 'tar'))) { + $param['extension'] = $pathinfo['extension']; + $param['package'] = substr($pathinfo['basename'], 0, + strlen($pathinfo['basename']) - 4); + } + // check for version + if (strpos($param['package'], '-')) { + $test = explode('-', $param['package']); + if (count($test) != 2) { + return PEAR::raiseError('parsePackageName(): only one version/state ' . + 'delimiter "-" is allowed in "' . $saveparam . '"', + 'version', null, null, $param); + } + list($param['package'], $param['version']) = $test; + } + } + // validation + $info = $this->channelExists($param['channel']); + if (PEAR::isError($info)) { + return $info; + } + if (!$info) { + return PEAR::raiseError('unknown channel "' . $param['channel'] . + '" in "' . $saveparam . '"', 'channel', null, null, $param); + } + $chan = $this->getChannel($param['channel']); + if (PEAR::isError($chan)) { + return $chan; + } + if (!$chan) { + return PEAR::raiseError("Exception: corrupt registry, could not " . + "retrieve channel " . $param['channel'] . " information", + 'registry', null, null, $param); + } + $param['channel'] = $chan->getName(); + $validate = $chan->getValidationObject(); + $vpackage = $chan->getValidationPackage(); + // validate package name + if (!$validate->validPackageName($param['package'], $vpackage['_content'])) { + return PEAR::raiseError('parsePackageName(): invalid package name "' . + $param['package'] . '" in "' . $saveparam . '"', + 'package', null, null, $param); + } + if (isset($param['group'])) { + if (!PEAR_Validate::validGroupName($param['group'])) { + return PEAR::raiseError('parsePackageName(): dependency group "' . $param['group'] . + '" is not a valid group name in "' . $saveparam . '"', 'group', null, null, + $param); + } + } + if (isset($param['state'])) { + if (!in_array(strtolower($param['state']), $validate->getValidStates())) { + return PEAR::raiseError('parsePackageName(): state "' . $param['state'] + . '" is not a valid state in "' . $saveparam . '"', + 'state', null, null, $param); + } + } + if (isset($param['version'])) { + if (isset($param['state'])) { + return PEAR::raiseError('parsePackageName(): cannot contain both ' . + 'a version and a stability (state) in "' . $saveparam . '"', + 'version/state', null, null, $param); + } + // check whether version is actually a state + if (in_array(strtolower($param['version']), $validate->getValidStates())) { + $param['state'] = strtolower($param['version']); + unset($param['version']); + } else { + if (!$validate->validVersion($param['version'])) { + return PEAR::raiseError('parsePackageName(): "' . $param['version'] . + '" is neither a valid version nor a valid state in "' . + $saveparam . '"', 'version/state', null, null, $param); + } + } + } + return $param; + } + + /** + * @param array + * @return string + */ + function parsedPackageNameToString($parsed, $brief = false) + { + if (is_string($parsed)) { + return $parsed; + } + if (is_object($parsed)) { + $p = $parsed; + $parsed = array( + 'package' => $p->getPackage(), + 'channel' => $p->getChannel(), + 'version' => $p->getVersion(), + ); + } + if (isset($parsed['uri'])) { + return $parsed['uri']; + } + if ($brief) { + if ($channel = $this->channelAlias($parsed['channel'])) { + return $channel . '/' . $parsed['package']; + } + } + $upass = ''; + if (isset($parsed['user'])) { + $upass = $parsed['user']; + if (isset($parsed['pass'])) { + $upass .= ':' . $parsed['pass']; + } + $upass = "$upass@"; + } + $ret = 'channel://' . $upass . $parsed['channel'] . '/' . $parsed['package']; + if (isset($parsed['version']) || isset($parsed['state'])) { + $ver = isset($parsed['version']) ? $parsed['version'] : ''; + $ver .= isset($parsed['state']) ? $parsed['state'] : ''; + $ret .= '-' . $ver; + } + if (isset($parsed['extension'])) { + $ret .= '.' . $parsed['extension']; + } + if (isset($parsed['opts'])) { + $ret .= '?'; + foreach ($parsed['opts'] as $name => $value) { + $parsed['opts'][$name] = "$name=$value"; + } + $ret .= implode('&', $parsed['opts']); + } + if (isset($parsed['group'])) { + $ret .= '#' . $parsed['group']; + } + return $ret; + } +}PEAR-1.9.0/PEAR/REST.php100664 764 764 36073 100664 7354 + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: REST.php 286489 2009-07-29 05:59:08Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * For downloading xml files + */ +require_once 'PEAR.php'; +require_once 'PEAR/XMLParser.php'; + +/** + * Intelligently retrieve data, following hyperlinks if necessary, and re-directing + * as well + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_REST +{ + var $config; + var $_options; + + function PEAR_REST(&$config, $options = array()) + { + $this->config = &$config; + $this->_options = $options; + } + + /** + * Retrieve REST data, but always retrieve the local cache if it is available. + * + * This is useful for elements that should never change, such as information on a particular + * release + * @param string full URL to this resource + * @param array|false contents of the accept-encoding header + * @param boolean if true, xml will be returned as a string, otherwise, xml will be + * parsed using PEAR_XMLParser + * @return string|array + */ + function retrieveCacheFirst($url, $accept = false, $forcestring = false, $channel = false) + { + $cachefile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . + md5($url) . 'rest.cachefile'; + + if (file_exists($cachefile)) { + return unserialize(implode('', file($cachefile))); + } + + return $this->retrieveData($url, $accept, $forcestring, $channel); + } + + /** + * Retrieve a remote REST resource + * @param string full URL to this resource + * @param array|false contents of the accept-encoding header + * @param boolean if true, xml will be returned as a string, otherwise, xml will be + * parsed using PEAR_XMLParser + * @return string|array + */ + function retrieveData($url, $accept = false, $forcestring = false, $channel = false) + { + $cacheId = $this->getCacheId($url); + if ($ret = $this->useLocalCache($url, $cacheId)) { + return $ret; + } + + $file = $trieddownload = false; + if (!isset($this->_options['offline'])) { + $trieddownload = true; + $file = $this->downloadHttp($url, $cacheId ? $cacheId['lastChange'] : false, $accept, $channel); + } + + if (PEAR::isError($file)) { + if ($file->getCode() !== -9276) { + return $file; + } + + $trieddownload = false; + $file = false; // use local copy if available on socket connect error + } + + if (!$file) { + $ret = $this->getCache($url); + if (!PEAR::isError($ret) && $trieddownload) { + // reset the age of the cache if the server says it was unmodified + $this->saveCache($url, $ret, null, true, $cacheId); + } + + return $ret; + } + + if (is_array($file)) { + $headers = $file[2]; + $lastmodified = $file[1]; + $content = $file[0]; + } else { + $headers = array(); + $lastmodified = false; + $content = $file; + } + + if ($forcestring) { + $this->saveCache($url, $content, $lastmodified, false, $cacheId); + return $content; + } + + if (isset($headers['content-type'])) { + switch ($headers['content-type']) { + case 'text/xml' : + case 'application/xml' : + case 'text/plain' : + if ($headers['content-type'] === 'text/plain') { + $check = substr($content, 0, 5); + if ($check !== 'parse($content); + PEAR::popErrorHandling(); + if (PEAR::isError($err)) { + return PEAR::raiseError('Invalid xml downloaded from "' . $url . '": ' . + $err->getMessage()); + } + $content = $parser->getData(); + case 'text/html' : + default : + // use it as a string + } + } else { + // assume XML + $parser = new PEAR_XMLParser; + $parser->parse($content); + $content = $parser->getData(); + } + + $this->saveCache($url, $content, $lastmodified, false, $cacheId); + return $content; + } + + function useLocalCache($url, $cacheid = null) + { + if ($cacheid === null) { + $cacheidfile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . + md5($url) . 'rest.cacheid'; + if (!file_exists($cacheidfile)) { + return false; + } + + $cacheid = unserialize(implode('', file($cacheidfile))); + } + + $cachettl = $this->config->get('cache_ttl'); + // If cache is newer than $cachettl seconds, we use the cache! + if (time() - $cacheid['age'] < $cachettl) { + return $this->getCache($url); + } + + return false; + } + + function getCacheId($url) + { + $cacheidfile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . + md5($url) . 'rest.cacheid'; + + if (!file_exists($cacheidfile)) { + return false; + } + + $ret = unserialize(implode('', file($cacheidfile))); + return $ret; + } + + function getCache($url) + { + $cachefile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . + md5($url) . 'rest.cachefile'; + + if (!file_exists($cachefile)) { + return PEAR::raiseError('No cached content available for "' . $url . '"'); + } + + return unserialize(implode('', file($cachefile))); + } + + /** + * @param string full URL to REST resource + * @param string original contents of the REST resource + * @param array HTTP Last-Modified and ETag headers + * @param bool if true, then the cache id file should be regenerated to + * trigger a new time-to-live value + */ + function saveCache($url, $contents, $lastmodified, $nochange = false, $cacheid = null) + { + $cachedir = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . md5($url); + $cacheidfile = $cachedir . 'rest.cacheid'; + $cachefile = $cachedir . 'rest.cachefile'; + + if ($cacheid === null && $nochange) { + $cacheid = unserialize(implode('', file($cacheidfile))); + } + + $fp = @fopen($cacheidfile, 'wb'); + if (!$fp) { + $cache_dir = $this->config->get('cache_dir'); + if (is_dir($cache_dir)) { + return false; + } + + System::mkdir(array('-p', $cache_dir)); + $fp = @fopen($cacheidfile, 'wb'); + if (!$fp) { + return false; + } + } + + if ($nochange) { + fwrite($fp, serialize(array( + 'age' => time(), + 'lastChange' => $cacheid['lastChange'], + )) + ); + + fclose($fp); + return true; + } + + fwrite($fp, serialize(array( + 'age' => time(), + 'lastChange' => $lastmodified, + )) + ); + + fclose($fp); + $fp = @fopen($cachefile, 'wb'); + if (!$fp) { + if (file_exists($cacheidfile)) { + @unlink($cacheidfile); + } + + return false; + } + + fwrite($fp, serialize($contents)); + fclose($fp); + return true; + } + + /** + * Efficiently Download a file through HTTP. Returns downloaded file as a string in-memory + * This is best used for small files + * + * If an HTTP proxy has been configured (http_proxy PEAR_Config + * setting), the proxy will be used. + * + * @param string $url the URL to download + * @param string $save_dir directory to save file in + * @param false|string|array $lastmodified header values to check against for caching + * use false to return the header values from this download + * @param false|array $accept Accept headers to send + * @return string|array Returns the contents of the downloaded file or a PEAR + * error on failure. If the error is caused by + * socket-related errors, the error object will + * have the fsockopen error code available through + * getCode(). If caching is requested, then return the header + * values. + * + * @access public + */ + function downloadHttp($url, $lastmodified = null, $accept = false, $channel = false) + { + static $redirect = 0; + // always reset , so we are clean case of error + $wasredirect = $redirect; + $redirect = 0; + + $info = parse_url($url); + if (!isset($info['scheme']) || !in_array($info['scheme'], array('http', 'https'))) { + return PEAR::raiseError('Cannot download non-http URL "' . $url . '"'); + } + + if (!isset($info['host'])) { + return PEAR::raiseError('Cannot download from non-URL "' . $url . '"'); + } + + $host = isset($info['host']) ? $info['host'] : null; + $port = isset($info['port']) ? $info['port'] : null; + $path = isset($info['path']) ? $info['path'] : null; + $schema = (isset($info['scheme']) && $info['scheme'] == 'https') ? 'https' : 'http'; + + $proxy_host = $proxy_port = $proxy_user = $proxy_pass = ''; + if ($this->config->get('http_proxy')&& + $proxy = parse_url($this->config->get('http_proxy')) + ) { + $proxy_host = isset($proxy['host']) ? $proxy['host'] : null; + if ($schema === 'https') { + $proxy_host = 'ssl://' . $proxy_host; + } + + $proxy_port = isset($proxy['port']) ? $proxy['port'] : 8080; + $proxy_user = isset($proxy['user']) ? urldecode($proxy['user']) : null; + $proxy_pass = isset($proxy['pass']) ? urldecode($proxy['pass']) : null; + $proxy_schema = (isset($proxy['scheme']) && $proxy['scheme'] == 'https') ? 'https' : 'http'; + } + + if (empty($port)) { + $port = (isset($info['scheme']) && $info['scheme'] == 'https') ? 443 : 80; + } + + if (isset($proxy['host'])) { + $request = "GET $url HTTP/1.1\r\n"; + } else { + $request = "GET $path HTTP/1.1\r\n"; + } + + $request .= "Host: $host:$port\r\n"; + $ifmodifiedsince = ''; + if (is_array($lastmodified)) { + if (isset($lastmodified['Last-Modified'])) { + $ifmodifiedsince = 'If-Modified-Since: ' . $lastmodified['Last-Modified'] . "\r\n"; + } + + if (isset($lastmodified['ETag'])) { + $ifmodifiedsince .= "If-None-Match: $lastmodified[ETag]\r\n"; + } + } else { + $ifmodifiedsince = ($lastmodified ? "If-Modified-Since: $lastmodified\r\n" : ''); + } + + $request .= $ifmodifiedsince . + "User-Agent: PEAR/1.9.0/PHP/" . PHP_VERSION . "\r\n"; + + $username = $this->config->get('username', null, $channel); + $password = $this->config->get('password', null, $channel); + + if ($username && $password) { + $tmp = base64_encode("$username:$password"); + $request .= "Authorization: Basic $tmp\r\n"; + } + + if ($proxy_host != '' && $proxy_user != '') { + $request .= 'Proxy-Authorization: Basic ' . + base64_encode($proxy_user . ':' . $proxy_pass) . "\r\n"; + } + + if ($accept) { + $request .= 'Accept: ' . implode(', ', $accept) . "\r\n"; + } + + $request .= "Accept-Encoding:\r\n"; + $request .= "Connection: close\r\n"; + $request .= "\r\n"; + + if ($proxy_host != '') { + $fp = @fsockopen($proxy_host, $proxy_port, $errno, $errstr, 15); + if (!$fp) { + return PEAR::raiseError("Connection to `$proxy_host:$proxy_port' failed: $errstr", -9276); + } + } else { + if ($schema === 'https') { + $host = 'ssl://' . $host; + } + + $fp = @fsockopen($host, $port, $errno, $errstr); + if (!$fp) { + return PEAR::raiseError("Connection to `$host:$port' failed: $errstr", $errno); + } + } + + fwrite($fp, $request); + + $headers = array(); + $reply = 0; + while ($line = trim(fgets($fp, 1024))) { + if (preg_match('/^([^:]+):\s+(.*)\s*\\z/', $line, $matches)) { + $headers[strtolower($matches[1])] = trim($matches[2]); + } elseif (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) { + $reply = (int)$matches[1]; + if ($reply == 304 && ($lastmodified || ($lastmodified === false))) { + return false; + } + + if (!in_array($reply, array(200, 301, 302, 303, 305, 307))) { + return PEAR::raiseError("File $schema://$host:$port$path not valid (received: $line)"); + } + } + } + + if ($reply != 200) { + if (!isset($headers['location'])) { + return PEAR::raiseError("File $schema://$host:$port$path not valid (redirected but no location)"); + } + + if ($wasredirect > 4) { + return PEAR::raiseError("File $schema://$host:$port$path not valid (redirection looped more than 5 times)"); + } + + $redirect = $wasredirect + 1; + return $this->downloadHttp($headers['location'], $lastmodified, $accept, $channel); + } + + $length = isset($headers['content-length']) ? $headers['content-length'] : -1; + + $data = ''; + while ($chunk = @fread($fp, 8192)) { + $data .= $chunk; + } + fclose($fp); + + if ($lastmodified === false || $lastmodified) { + if (isset($headers['etag'])) { + $lastmodified = array('ETag' => $headers['etag']); + } + + if (isset($headers['last-modified'])) { + if (is_array($lastmodified)) { + $lastmodified['Last-Modified'] = $headers['last-modified']; + } else { + $lastmodified = $headers['last-modified']; + } + } + + return array($data, $lastmodified, $headers); + } + + return $data; + } +}PEAR-1.9.0/PEAR/RunTest.php100664 764 764 105252 100664 10217 + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: RunTest.php 287447 2009-08-18 11:46:19Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.3.3 + */ + +/** + * for error handling + */ +require_once 'PEAR.php'; +require_once 'PEAR/Config.php'; + +define('DETAILED', 1); +putenv("PHP_PEAR_RUNTESTS=1"); + +/** + * Simplified version of PHP's test suite + * + * Try it with: + * + * $ php -r 'include "../PEAR/RunTest.php"; $t=new PEAR_RunTest; $o=$t->run("./pear_system.phpt");print_r($o);' + * + * + * @category pear + * @package PEAR + * @author Tomas V.V.Cox + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.3.3 + */ +class PEAR_RunTest +{ + var $_headers = array(); + var $_logger; + var $_options; + var $_php; + var $tests_count; + var $xdebug_loaded; + /** + * Saved value of php executable, used to reset $_php when we + * have a test that uses cgi + * + * @var unknown_type + */ + var $_savephp; + var $ini_overwrites = array( + 'output_handler=', + 'open_basedir=', + 'safe_mode=0', + 'disable_functions=', + 'output_buffering=Off', + 'display_errors=1', + 'log_errors=0', + 'html_errors=0', + 'track_errors=1', + 'report_memleaks=0', + 'report_zend_debug=0', + 'docref_root=', + 'docref_ext=.html', + 'error_prepend_string=', + 'error_append_string=', + 'auto_prepend_file=', + 'auto_append_file=', + 'magic_quotes_runtime=0', + 'xdebug.default_enable=0', + 'allow_url_fopen=1', + ); + + /** + * An object that supports the PEAR_Common->log() signature, or null + * @param PEAR_Common|null + */ + function PEAR_RunTest($logger = null, $options = array()) + { + if (!defined('E_DEPRECATED')) { + define('E_DEPRECATED', 0); + } + if (!defined('E_STRICT')) { + define('E_STRICT', 0); + } + $this->ini_overwrites[] = 'error_reporting=' . (E_ALL & ~(E_DEPRECATED | E_STRICT)); + if (is_null($logger)) { + require_once 'PEAR/Common.php'; + $logger = new PEAR_Common; + } + $this->_logger = $logger; + $this->_options = $options; + + $conf = &PEAR_Config::singleton(); + $this->_php = $conf->get('php_bin'); + } + + /** + * Taken from php-src/run-tests.php + * + * @param string $commandline command name + * @param array $env + * @param string $stdin standard input to pass to the command + * @return unknown + */ + function system_with_timeout($commandline, $env = null, $stdin = null) + { + $data = ''; + if (version_compare(phpversion(), '5.0.0', '<')) { + $proc = proc_open($commandline, array( + 0 => array('pipe', 'r'), + 1 => array('pipe', 'w'), + 2 => array('pipe', 'w') + ), $pipes); + } else { + $proc = proc_open($commandline, array( + 0 => array('pipe', 'r'), + 1 => array('pipe', 'w'), + 2 => array('pipe', 'w') + ), $pipes, null, $env, array('suppress_errors' => true)); + } + + if (!$proc) { + return false; + } + + if (is_string($stdin)) { + fwrite($pipes[0], $stdin); + } + fclose($pipes[0]); + + while (true) { + /* hide errors from interrupted syscalls */ + $r = $pipes; + $e = $w = null; + $n = @stream_select($r, $w, $e, 60); + + if ($n === 0) { + /* timed out */ + $data .= "\n ** ERROR: process timed out **\n"; + proc_terminate($proc); + return array(1234567890, $data); + } else if ($n > 0) { + $line = fread($pipes[1], 8192); + if (strlen($line) == 0) { + /* EOF */ + break; + } + $data .= $line; + } + } + if (function_exists('proc_get_status')) { + $stat = proc_get_status($proc); + if ($stat['signaled']) { + $data .= "\nTermsig=".$stat['stopsig']; + } + } + $code = proc_close($proc); + if (function_exists('proc_get_status')) { + $code = $stat['exitcode']; + } + return array($code, $data); + } + + /** + * Turns a PHP INI string into an array + * + * Turns -d "include_path=/foo/bar" into this: + * array( + * 'include_path' => array( + * 'operator' => '-d', + * 'value' => '/foo/bar', + * ) + * ) + * Works both with quotes and without + * + * @param string an PHP INI string, -d "include_path=/foo/bar" + * @return array + */ + function iniString2array($ini_string) + { + if (!$ini_string) { + return array(); + } + $split = preg_split('/[\s]|=/', $ini_string, -1, PREG_SPLIT_NO_EMPTY); + $key = $split[1][0] == '"' ? substr($split[1], 1) : $split[1]; + $value = $split[2][strlen($split[2]) - 1] == '"' ? substr($split[2], 0, -1) : $split[2]; + // FIXME review if this is really the struct to go with + $array = array($key => array('operator' => $split[0], 'value' => $value)); + return $array; + } + + function settings2array($settings, $ini_settings) + { + foreach ($settings as $setting) { + if (strpos($setting, '=') !== false) { + $setting = explode('=', $setting, 2); + $name = trim(strtolower($setting[0])); + $value = trim($setting[1]); + $ini_settings[$name] = $value; + } + } + return $ini_settings; + } + + function settings2params($ini_settings) + { + $settings = ''; + foreach ($ini_settings as $name => $value) { + if (is_array($value)) { + $operator = $value['operator']; + $value = $value['value']; + } else { + $operator = '-d'; + } + $value = addslashes($value); + $settings .= " $operator \"$name=$value\""; + } + return $settings; + } + + function _preparePhpBin($php, $file, $ini_settings) + { + $file = escapeshellarg($file); + // This was fixed in php 5.3 and is not needed after that + if (OS_WINDOWS && version_compare(PHP_VERSION, '5.3', '<')) { + $cmd = '"'.escapeshellarg($php).' '.$ini_settings.' -f ' . $file .'"'; + } else { + $cmd = $php . $ini_settings . ' -f ' . $file; + } + + return $cmd; + } + + function runPHPUnit($file, $ini_settings = '') + { + if (!file_exists($file) && file_exists(getcwd() . DIRECTORY_SEPARATOR . $file)) { + $file = realpath(getcwd() . DIRECTORY_SEPARATOR . $file); + } elseif (file_exists($file)) { + $file = realpath($file); + } + + $cmd = $this->_preparePhpBin($this->_php, $file, $ini_settings); + if (isset($this->_logger)) { + $this->_logger->log(2, 'Running command "' . $cmd . '"'); + } + + $savedir = getcwd(); // in case the test moves us around + chdir(dirname($file)); + echo `$cmd`; + chdir($savedir); + return 'PASSED'; // we have no way of knowing this information so assume passing + } + + /** + * Runs an individual test case. + * + * @param string The filename of the test + * @param array|string INI settings to be applied to the test run + * @param integer Number what the current running test is of the + * whole test suite being runned. + * + * @return string|object Returns PASSED, WARNED, FAILED depending on how the + * test came out. + * PEAR Error when the tester it self fails + */ + function run($file, $ini_settings = array(), $test_number = 1) + { + if (isset($this->_savephp)) { + $this->_php = $this->_savephp; + unset($this->_savephp); + } + if (empty($this->_options['cgi'])) { + // try to see if php-cgi is in the path + $res = $this->system_with_timeout('php-cgi -v'); + if (false !== $res && !(is_array($res) && $res === array(127, ''))) { + $this->_options['cgi'] = 'php-cgi'; + } + } + if (1 < $len = strlen($this->tests_count)) { + $test_number = str_pad($test_number, $len, ' ', STR_PAD_LEFT); + $test_nr = "[$test_number/$this->tests_count] "; + } else { + $test_nr = ''; + } + + $file = realpath($file); + $section_text = $this->_readFile($file); + if (PEAR::isError($section_text)) { + return $section_text; + } + + if (isset($section_text['POST_RAW']) && isset($section_text['UPLOAD'])) { + return PEAR::raiseError("Cannot contain both POST_RAW and UPLOAD in test file: $file"); + } + + $cwd = getcwd(); + + $pass_options = ''; + if (!empty($this->_options['ini'])) { + $pass_options = $this->_options['ini']; + } + + if (is_string($ini_settings)) { + $ini_settings = $this->iniString2array($ini_settings); + } + + $ini_settings = $this->settings2array($this->ini_overwrites, $ini_settings); + if ($section_text['INI']) { + if (strpos($section_text['INI'], '{PWD}') !== false) { + $section_text['INI'] = str_replace('{PWD}', dirname($file), $section_text['INI']); + } + $ini = preg_split( "/[\n\r]+/", $section_text['INI']); + $ini_settings = $this->settings2array($ini, $ini_settings); + } + $ini_settings = $this->settings2params($ini_settings); + $shortname = str_replace($cwd . DIRECTORY_SEPARATOR, '', $file); + + $tested = trim($section_text['TEST']); + $tested.= !isset($this->_options['simple']) ? "[$shortname]" : ' '; + + if (!empty($section_text['POST']) || !empty($section_text['POST_RAW']) || + !empty($section_text['UPLOAD']) || !empty($section_text['GET']) || + !empty($section_text['COOKIE']) || !empty($section_text['EXPECTHEADERS'])) { + if (empty($this->_options['cgi'])) { + if (!isset($this->_options['quiet'])) { + $this->_logger->log(0, "SKIP $test_nr$tested (reason: --cgi option needed for this test, type 'pear help run-tests')"); + } + if (isset($this->_options['tapoutput'])) { + return array('ok', ' # skip --cgi option needed for this test, "pear help run-tests" for info'); + } + return 'SKIPPED'; + } + $this->_savephp = $this->_php; + $this->_php = $this->_options['cgi']; + } + + $temp_dir = realpath(dirname($file)); + $main_file_name = basename($file, 'phpt'); + $diff_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'diff'; + $log_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'log'; + $exp_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'exp'; + $output_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'out'; + $memcheck_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'mem'; + $temp_file = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'php'; + $temp_skipif = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'skip.php'; + $temp_clean = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'clean.php'; + $tmp_post = $temp_dir . DIRECTORY_SEPARATOR . uniqid('phpt.'); + + // unlink old test results + $this->_cleanupOldFiles($file); + + // Check if test should be skipped. + $res = $this->_runSkipIf($section_text, $temp_skipif, $tested, $ini_settings); + if (count($res) != 2) { + return $res; + } + $info = $res['info']; + $warn = $res['warn']; + + // We've satisfied the preconditions - run the test! + if (isset($this->_options['coverage']) && $this->xdebug_loaded) { + $xdebug_file = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'xdebug'; + $text = '"; + + $len_f = 5; + if (substr($section_text['FILE'], 0, 5) != 'save_text($temp_file, $text); + } else { + $this->save_text($temp_file, $section_text['FILE']); + } + + $args = $section_text['ARGS'] ? ' -- '.$section_text['ARGS'] : ''; + $cmd = $this->_preparePhpBin($this->_php, $temp_file, $ini_settings); + $cmd.= "$args 2>&1"; + if (isset($this->_logger)) { + $this->_logger->log(2, 'Running command "' . $cmd . '"'); + } + + // Reset environment from any previous test. + $env = $this->_resetEnv($section_text, $temp_file); + + $section_text = $this->_processUpload($section_text, $file); + if (PEAR::isError($section_text)) { + return $section_text; + } + + if (array_key_exists('POST_RAW', $section_text) && !empty($section_text['POST_RAW'])) { + $post = trim($section_text['POST_RAW']); + $raw_lines = explode("\n", $post); + + $request = ''; + $started = false; + foreach ($raw_lines as $i => $line) { + if (empty($env['CONTENT_TYPE']) && + preg_match('/^Content-Type:(.*)/i', $line, $res)) { + $env['CONTENT_TYPE'] = trim(str_replace("\r", '', $res[1])); + continue; + } + if ($started) { + $request .= "\n"; + } + $started = true; + $request .= $line; + } + + $env['CONTENT_LENGTH'] = strlen($request); + $env['REQUEST_METHOD'] = 'POST'; + + $this->save_text($tmp_post, $request); + $cmd = "$this->_php$pass_options$ini_settings \"$temp_file\" 2>&1 < $tmp_post"; + } elseif (array_key_exists('POST', $section_text) && !empty($section_text['POST'])) { + $post = trim($section_text['POST']); + $this->save_text($tmp_post, $post); + $content_length = strlen($post); + + $env['REQUEST_METHOD'] = 'POST'; + $env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'; + $env['CONTENT_LENGTH'] = $content_length; + + $cmd = "$this->_php$pass_options$ini_settings \"$temp_file\" 2>&1 < $tmp_post"; + } else { + $env['REQUEST_METHOD'] = 'GET'; + $env['CONTENT_TYPE'] = ''; + $env['CONTENT_LENGTH'] = ''; + } + + if (OS_WINDOWS && isset($section_text['RETURNS'])) { + ob_start(); + system($cmd, $return_value); + $out = ob_get_contents(); + ob_end_clean(); + $section_text['RETURNS'] = (int) trim($section_text['RETURNS']); + $returnfail = ($return_value != $section_text['RETURNS']); + } else { + $returnfail = false; + $stdin = isset($section_text['STDIN']) ? $section_text['STDIN'] : null; + $out = $this->system_with_timeout($cmd, $env, $stdin); + $return_value = $out[0]; + $out = $out[1]; + } + + $output = preg_replace('/\r\n/', "\n", trim($out)); + + if (isset($tmp_post) && realpath($tmp_post) && file_exists($tmp_post)) { + @unlink(realpath($tmp_post)); + } + chdir($cwd); // in case the test moves us around + + $this->_testCleanup($section_text, $temp_clean); + + /* when using CGI, strip the headers from the output */ + $output = $this->_stripHeadersCGI($output); + + if (isset($section_text['EXPECTHEADERS'])) { + $testheaders = $this->_processHeaders($section_text['EXPECTHEADERS']); + $missing = array_diff_assoc($testheaders, $this->_headers); + $changed = ''; + foreach ($missing as $header => $value) { + if (isset($this->_headers[$header])) { + $changed .= "-$header: $value\n+$header: "; + $changed .= $this->_headers[$header]; + } else { + $changed .= "-$header: $value\n"; + } + } + if ($missing) { + // tack on failed headers to output: + $output .= "\n====EXPECTHEADERS FAILURE====:\n$changed"; + } + } + // Does the output match what is expected? + do { + if (isset($section_text['EXPECTF']) || isset($section_text['EXPECTREGEX'])) { + if (isset($section_text['EXPECTF'])) { + $wanted = trim($section_text['EXPECTF']); + } else { + $wanted = trim($section_text['EXPECTREGEX']); + } + $wanted_re = preg_replace('/\r\n/', "\n", $wanted); + if (isset($section_text['EXPECTF'])) { + $wanted_re = preg_quote($wanted_re, '/'); + // Stick to basics + $wanted_re = str_replace("%s", ".+?", $wanted_re); //not greedy + $wanted_re = str_replace("%i", "[+\-]?[0-9]+", $wanted_re); + $wanted_re = str_replace("%d", "[0-9]+", $wanted_re); + $wanted_re = str_replace("%x", "[0-9a-fA-F]+", $wanted_re); + $wanted_re = str_replace("%f", "[+\-]?\.?[0-9]+\.?[0-9]*(E-?[0-9]+)?", $wanted_re); + $wanted_re = str_replace("%c", ".", $wanted_re); + // %f allows two points "-.0.0" but that is the best *simple* expression + } + + /* DEBUG YOUR REGEX HERE + var_dump($wanted_re); + print(str_repeat('=', 80) . "\n"); + var_dump($output); + */ + if (!$returnfail && preg_match("/^$wanted_re\$/s", $output)) { + if (file_exists($temp_file)) { + unlink($temp_file); + } + if (array_key_exists('FAIL', $section_text)) { + break; + } + if (!isset($this->_options['quiet'])) { + $this->_logger->log(0, "PASS $test_nr$tested$info"); + } + if (isset($this->_options['tapoutput'])) { + return array('ok', ' - ' . $tested); + } + return 'PASSED'; + } + } else { + if (isset($section_text['EXPECTFILE'])) { + $f = $temp_dir . '/' . trim($section_text['EXPECTFILE']); + if (!($fp = @fopen($f, 'rb'))) { + return PEAR::raiseError('--EXPECTFILE-- section file ' . + $f . ' not found'); + } + fclose($fp); + $section_text['EXPECT'] = file_get_contents($f); + } + + if (isset($section_text['EXPECT'])) { + $wanted = preg_replace('/\r\n/', "\n", trim($section_text['EXPECT'])); + } else { + $wanted = ''; + } + + // compare and leave on success + if (!$returnfail && 0 == strcmp($output, $wanted)) { + if (file_exists($temp_file)) { + unlink($temp_file); + } + if (array_key_exists('FAIL', $section_text)) { + break; + } + if (!isset($this->_options['quiet'])) { + $this->_logger->log(0, "PASS $test_nr$tested$info"); + } + if (isset($this->_options['tapoutput'])) { + return array('ok', ' - ' . $tested); + } + return 'PASSED'; + } + } + } while (false); + + if (array_key_exists('FAIL', $section_text)) { + // we expect a particular failure + // this is only used for testing PEAR_RunTest + $expectf = isset($section_text['EXPECTF']) ? $wanted_re : null; + $faildiff = $this->generate_diff($wanted, $output, null, $expectf); + $faildiff = preg_replace('/\r/', '', $faildiff); + $wanted = preg_replace('/\r/', '', trim($section_text['FAIL'])); + if ($faildiff == $wanted) { + if (!isset($this->_options['quiet'])) { + $this->_logger->log(0, "PASS $test_nr$tested$info"); + } + if (isset($this->_options['tapoutput'])) { + return array('ok', ' - ' . $tested); + } + return 'PASSED'; + } + unset($section_text['EXPECTF']); + $output = $faildiff; + if (isset($section_text['RETURNS'])) { + return PEAR::raiseError('Cannot have both RETURNS and FAIL in the same test: ' . + $file); + } + } + + // Test failed so we need to report details. + $txt = $warn ? 'WARN ' : 'FAIL '; + $this->_logger->log(0, $txt . $test_nr . $tested . $info); + + // write .exp + $res = $this->_writeLog($exp_filename, $wanted); + if (PEAR::isError($res)) { + return $res; + } + + // write .out + $res = $this->_writeLog($output_filename, $output); + if (PEAR::isError($res)) { + return $res; + } + + // write .diff + $returns = isset($section_text['RETURNS']) ? + array(trim($section_text['RETURNS']), $return_value) : null; + $expectf = isset($section_text['EXPECTF']) ? $wanted_re : null; + $data = $this->generate_diff($wanted, $output, $returns, $expectf); + $res = $this->_writeLog($diff_filename, $data); + if (PEAR::isError($res)) { + return $res; + } + + // write .log + $data = " +---- EXPECTED OUTPUT +$wanted +---- ACTUAL OUTPUT +$output +---- FAILED +"; + + if ($returnfail) { + $data .= " +---- EXPECTED RETURN +$section_text[RETURNS] +---- ACTUAL RETURN +$return_value +"; + } + + $res = $this->_writeLog($log_filename, $data); + if (PEAR::isError($res)) { + return $res; + } + + if (isset($this->_options['tapoutput'])) { + $wanted = explode("\n", $wanted); + $wanted = "# Expected output:\n#\n#" . implode("\n#", $wanted); + $output = explode("\n", $output); + $output = "#\n#\n# Actual output:\n#\n#" . implode("\n#", $output); + return array($wanted . $output . 'not ok', ' - ' . $tested); + } + return $warn ? 'WARNED' : 'FAILED'; + } + + function generate_diff($wanted, $output, $rvalue, $wanted_re) + { + $w = explode("\n", $wanted); + $o = explode("\n", $output); + $wr = explode("\n", $wanted_re); + $w1 = array_diff_assoc($w, $o); + $o1 = array_diff_assoc($o, $w); + $o2 = $w2 = array(); + foreach ($w1 as $idx => $val) { + if (!$wanted_re || !isset($wr[$idx]) || !isset($o1[$idx]) || + !preg_match('/^' . $wr[$idx] . '\\z/', $o1[$idx])) { + $w2[sprintf("%03d<", $idx)] = sprintf("%03d- ", $idx + 1) . $val; + } + } + foreach ($o1 as $idx => $val) { + if (!$wanted_re || !isset($wr[$idx]) || + !preg_match('/^' . $wr[$idx] . '\\z/', $val)) { + $o2[sprintf("%03d>", $idx)] = sprintf("%03d+ ", $idx + 1) . $val; + } + } + $diff = array_merge($w2, $o2); + ksort($diff); + $extra = $rvalue ? "##EXPECTED: $rvalue[0]\r\n##RETURNED: $rvalue[1]" : ''; + return implode("\r\n", $diff) . $extra; + } + + // Write the given text to a temporary file, and return the filename. + function save_text($filename, $text) + { + if (!$fp = fopen($filename, 'w')) { + return PEAR::raiseError("Cannot open file '" . $filename . "' (save_text)"); + } + fwrite($fp, $text); + fclose($fp); + if (1 < DETAILED) echo " +FILE $filename {{{ +$text +}}} +"; + } + + function _cleanupOldFiles($file) + { + $temp_dir = realpath(dirname($file)); + $mainFileName = basename($file, 'phpt'); + $diff_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'diff'; + $log_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'log'; + $exp_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'exp'; + $output_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'out'; + $memcheck_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'mem'; + $temp_file = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'php'; + $temp_skipif = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'skip.php'; + $temp_clean = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'clean.php'; + $tmp_post = $temp_dir . DIRECTORY_SEPARATOR . uniqid('phpt.'); + + // unlink old test results + @unlink($diff_filename); + @unlink($log_filename); + @unlink($exp_filename); + @unlink($output_filename); + @unlink($memcheck_filename); + @unlink($temp_file); + @unlink($temp_skipif); + @unlink($tmp_post); + @unlink($temp_clean); + } + + function _runSkipIf($section_text, $temp_skipif, $tested, $ini_settings) + { + $info = ''; + $warn = false; + if (array_key_exists('SKIPIF', $section_text) && trim($section_text['SKIPIF'])) { + $this->save_text($temp_skipif, $section_text['SKIPIF']); + $output = $this->system_with_timeout("$this->_php$ini_settings -f \"$temp_skipif\""); + $output = $output[1]; + $loutput = ltrim($output); + unlink($temp_skipif); + if (!strncasecmp('skip', $loutput, 4)) { + $skipreason = "SKIP $tested"; + if (preg_match('/^\s*skip\s*(.+)\s*/i', $output, $m)) { + $skipreason .= '(reason: ' . $m[1] . ')'; + } + if (!isset($this->_options['quiet'])) { + $this->_logger->log(0, $skipreason); + } + if (isset($this->_options['tapoutput'])) { + return array('ok', ' # skip ' . $reason); + } + return 'SKIPPED'; + } + + if (!strncasecmp('info', $loutput, 4) + && preg_match('/^\s*info\s*(.+)\s*/i', $output, $m)) { + $info = " (info: $m[1])"; + } + + if (!strncasecmp('warn', $loutput, 4) + && preg_match('/^\s*warn\s*(.+)\s*/i', $output, $m)) { + $warn = true; /* only if there is a reason */ + $info = " (warn: $m[1])"; + } + } + + return array('warn' => $warn, 'info' => $info); + } + + function _stripHeadersCGI($output) + { + $this->headers = array(); + if (!empty($this->_options['cgi']) && + $this->_php == $this->_options['cgi'] && + preg_match("/^(.*?)(?:\n\n(.*)|\\z)/s", $output, $match)) { + $output = isset($match[2]) ? trim($match[2]) : ''; + $this->_headers = $this->_processHeaders($match[1]); + } + + return $output; + } + + /** + * Return an array that can be used with array_diff() to compare headers + * + * @param string $text + */ + function _processHeaders($text) + { + $headers = array(); + $rh = preg_split("/[\n\r]+/", $text); + foreach ($rh as $line) { + if (strpos($line, ':')!== false) { + $line = explode(':', $line, 2); + $headers[trim($line[0])] = trim($line[1]); + } + } + return $headers; + } + + function _readFile($file) + { + // Load the sections of the test file. + $section_text = array( + 'TEST' => '(unnamed test)', + 'SKIPIF' => '', + 'GET' => '', + 'COOKIE' => '', + 'POST' => '', + 'ARGS' => '', + 'INI' => '', + 'CLEAN' => '', + ); + + if (!is_file($file) || !$fp = fopen($file, "r")) { + return PEAR::raiseError("Cannot open test file: $file"); + } + + $section = ''; + while (!feof($fp)) { + $line = fgets($fp); + + // Match the beginning of a section. + if (preg_match('/^--([_A-Z]+)--/', $line, $r)) { + $section = $r[1]; + $section_text[$section] = ''; + continue; + } elseif (empty($section)) { + fclose($fp); + return PEAR::raiseError("Invalid sections formats in test file: $file"); + } + + // Add to the section text. + $section_text[$section] .= $line; + } + fclose($fp); + + return $section_text; + } + + function _writeLog($logname, $data) + { + if (!$log = fopen($logname, 'w')) { + return PEAR::raiseError("Cannot create test log - $logname"); + } + fwrite($log, $data); + fclose($log); + } + + function _resetEnv($section_text, $temp_file) + { + $env = $_ENV; + $env['REDIRECT_STATUS'] = ''; + $env['QUERY_STRING'] = ''; + $env['PATH_TRANSLATED'] = ''; + $env['SCRIPT_FILENAME'] = ''; + $env['REQUEST_METHOD'] = ''; + $env['CONTENT_TYPE'] = ''; + $env['CONTENT_LENGTH'] = ''; + if (!empty($section_text['ENV'])) { + if (strpos($section_text['ENV'], '{PWD}') !== false) { + $section_text['ENV'] = str_replace('{PWD}', dirname($temp_file), $section_text['ENV']); + } + foreach (explode("\n", trim($section_text['ENV'])) as $e) { + $e = explode('=', trim($e), 2); + if (!empty($e[0]) && isset($e[1])) { + $env[$e[0]] = $e[1]; + } + } + } + if (array_key_exists('GET', $section_text)) { + $env['QUERY_STRING'] = trim($section_text['GET']); + } else { + $env['QUERY_STRING'] = ''; + } + if (array_key_exists('COOKIE', $section_text)) { + $env['HTTP_COOKIE'] = trim($section_text['COOKIE']); + } else { + $env['HTTP_COOKIE'] = ''; + } + $env['REDIRECT_STATUS'] = '1'; + $env['PATH_TRANSLATED'] = $temp_file; + $env['SCRIPT_FILENAME'] = $temp_file; + + return $env; + } + + function _processUpload($section_text, $file) + { + if (array_key_exists('UPLOAD', $section_text) && !empty($section_text['UPLOAD'])) { + $upload_files = trim($section_text['UPLOAD']); + $upload_files = explode("\n", $upload_files); + + $request = "Content-Type: multipart/form-data; boundary=---------------------------20896060251896012921717172737\n" . + "-----------------------------20896060251896012921717172737\n"; + foreach ($upload_files as $fileinfo) { + $fileinfo = explode('=', $fileinfo); + if (count($fileinfo) != 2) { + return PEAR::raiseError("Invalid UPLOAD section in test file: $file"); + } + if (!realpath(dirname($file) . '/' . $fileinfo[1])) { + return PEAR::raiseError("File for upload does not exist: $fileinfo[1] " . + "in test file: $file"); + } + $file_contents = file_get_contents(dirname($file) . '/' . $fileinfo[1]); + $fileinfo[1] = basename($fileinfo[1]); + $request .= "Content-Disposition: form-data; name=\"$fileinfo[0]\"; filename=\"$fileinfo[1]\"\n"; + $request .= "Content-Type: text/plain\n\n"; + $request .= $file_contents . "\n" . + "-----------------------------20896060251896012921717172737\n"; + } + + if (array_key_exists('POST', $section_text) && !empty($section_text['POST'])) { + // encode POST raw + $post = trim($section_text['POST']); + $post = explode('&', $post); + foreach ($post as $i => $post_info) { + $post_info = explode('=', $post_info); + if (count($post_info) != 2) { + return PEAR::raiseError("Invalid POST data in test file: $file"); + } + $post_info[0] = rawurldecode($post_info[0]); + $post_info[1] = rawurldecode($post_info[1]); + $post[$i] = $post_info; + } + foreach ($post as $post_info) { + $request .= "Content-Disposition: form-data; name=\"$post_info[0]\"\n\n"; + $request .= $post_info[1] . "\n" . + "-----------------------------20896060251896012921717172737\n"; + } + unset($section_text['POST']); + } + $section_text['POST_RAW'] = $request; + } + + return $section_text; + } + + function _testCleanup($section_text, $temp_clean) + { + if ($section_text['CLEAN']) { + // perform test cleanup + $this->save_text($temp_clean, $section_text['CLEAN']); + $output = $this->system_with_timeout("$this->_php $temp_clean 2>&1"); + if (strlen($output[1])) { + echo "BORKED --CLEAN-- section! output:\n", $output[1]; + } + if (file_exists($temp_clean)) { + unlink($temp_clean); + } + } + } +}PEAR-1.9.0/PEAR/Validate.php100664 764 764 53055 100664 10327 + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Validate.php 276383 2009-02-24 23:39:37Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/**#@+ + * Constants for install stage + */ +define('PEAR_VALIDATE_INSTALLING', 1); +define('PEAR_VALIDATE_UNINSTALLING', 2); // this is not bit-mapped like the others +define('PEAR_VALIDATE_NORMAL', 3); +define('PEAR_VALIDATE_DOWNLOADING', 4); // this is not bit-mapped like the others +define('PEAR_VALIDATE_PACKAGING', 7); +/**#@-*/ +require_once 'PEAR/Common.php'; +require_once 'PEAR/Validator/PECL.php'; + +/** + * Validation class for package.xml - channel-level advanced validation + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Validate +{ + var $packageregex = _PEAR_COMMON_PACKAGE_NAME_PREG; + /** + * @var PEAR_PackageFile_v1|PEAR_PackageFile_v2 + */ + var $_packagexml; + /** + * @var int one of the PEAR_VALIDATE_* constants + */ + var $_state = PEAR_VALIDATE_NORMAL; + /** + * Format: ('error' => array('field' => name, 'reason' => reason), 'warning' => same) + * @var array + * @access private + */ + var $_failures = array('error' => array(), 'warning' => array()); + + /** + * Override this method to handle validation of normal package names + * @param string + * @return bool + * @access protected + */ + function _validPackageName($name) + { + return (bool) preg_match('/^' . $this->packageregex . '\\z/', $name); + } + + /** + * @param string package name to validate + * @param string name of channel-specific validation package + * @final + */ + function validPackageName($name, $validatepackagename = false) + { + if ($validatepackagename) { + if (strtolower($name) == strtolower($validatepackagename)) { + return (bool) preg_match('/^[a-zA-Z0-9_]+(?:\.[a-zA-Z0-9_]+)*\\z/', $name); + } + } + return $this->_validPackageName($name); + } + + /** + * This validates a bundle name, and bundle names must conform + * to the PEAR naming convention, so the method is final and static. + * @param string + * @final + * @static + */ + function validGroupName($name) + { + return (bool) preg_match('/^' . _PEAR_COMMON_PACKAGE_NAME_PREG . '\\z/', $name); + } + + /** + * Determine whether $state represents a valid stability level + * @param string + * @return bool + * @static + * @final + */ + function validState($state) + { + return in_array($state, array('snapshot', 'devel', 'alpha', 'beta', 'stable')); + } + + /** + * Get a list of valid stability levels + * @return array + * @static + * @final + */ + function getValidStates() + { + return array('snapshot', 'devel', 'alpha', 'beta', 'stable'); + } + + /** + * Determine whether a version is a properly formatted version number that can be used + * by version_compare + * @param string + * @return bool + * @static + * @final + */ + function validVersion($ver) + { + return (bool) preg_match(PEAR_COMMON_PACKAGE_VERSION_PREG, $ver); + } + + /** + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + */ + function setPackageFile(&$pf) + { + $this->_packagexml = &$pf; + } + + /** + * @access private + */ + function _addFailure($field, $reason) + { + $this->_failures['errors'][] = array('field' => $field, 'reason' => $reason); + } + + /** + * @access private + */ + function _addWarning($field, $reason) + { + $this->_failures['warnings'][] = array('field' => $field, 'reason' => $reason); + } + + function getFailures() + { + $failures = $this->_failures; + $this->_failures = array('warnings' => array(), 'errors' => array()); + return $failures; + } + + /** + * @param int one of the PEAR_VALIDATE_* constants + */ + function validate($state = null) + { + if (!isset($this->_packagexml)) { + return false; + } + if ($state !== null) { + $this->_state = $state; + } + $this->_failures = array('warnings' => array(), 'errors' => array()); + $this->validatePackageName(); + $this->validateVersion(); + $this->validateMaintainers(); + $this->validateDate(); + $this->validateSummary(); + $this->validateDescription(); + $this->validateLicense(); + $this->validateNotes(); + if ($this->_packagexml->getPackagexmlVersion() == '1.0') { + $this->validateState(); + $this->validateFilelist(); + } elseif ($this->_packagexml->getPackagexmlVersion() == '2.0' || + $this->_packagexml->getPackagexmlVersion() == '2.1') { + $this->validateTime(); + $this->validateStability(); + $this->validateDeps(); + $this->validateMainFilelist(); + $this->validateReleaseFilelist(); + //$this->validateGlobalTasks(); + $this->validateChangelog(); + } + return !((bool) count($this->_failures['errors'])); + } + + /** + * @access protected + */ + function validatePackageName() + { + if ($this->_state == PEAR_VALIDATE_PACKAGING || + $this->_state == PEAR_VALIDATE_NORMAL) { + if (($this->_packagexml->getPackagexmlVersion() == '2.0' || + $this->_packagexml->getPackagexmlVersion() == '2.1') && + $this->_packagexml->getExtends()) { + $version = $this->_packagexml->getVersion() . ''; + $name = $this->_packagexml->getPackage(); + $test = array_shift($a = explode('.', $version)); + if ($test == '0') { + return true; + } + $vlen = strlen($test); + $majver = substr($name, strlen($name) - $vlen); + while ($majver && !is_numeric($majver{0})) { + $majver = substr($majver, 1); + } + if ($majver != $test) { + $this->_addWarning('package', "package $name extends package " . + $this->_packagexml->getExtends() . ' and so the name should ' . + 'have a postfix equal to the major version like "' . + $this->_packagexml->getExtends() . $test . '"'); + return true; + } elseif (substr($name, 0, strlen($name) - $vlen) != + $this->_packagexml->getExtends()) { + $this->_addWarning('package', "package $name extends package " . + $this->_packagexml->getExtends() . ' and so the name must ' . + 'be an extension like "' . $this->_packagexml->getExtends() . + $test . '"'); + return true; + } + } + } + if (!$this->validPackageName($this->_packagexml->getPackage())) { + $this->_addFailure('name', 'package name "' . + $this->_packagexml->getPackage() . '" is invalid'); + return false; + } + } + + /** + * @access protected + */ + function validateVersion() + { + if ($this->_state != PEAR_VALIDATE_PACKAGING) { + if (!$this->validVersion($this->_packagexml->getVersion())) { + $this->_addFailure('version', + 'Invalid version number "' . $this->_packagexml->getVersion() . '"'); + } + return false; + } + $version = $this->_packagexml->getVersion(); + $versioncomponents = explode('.', $version); + if (count($versioncomponents) != 3) { + $this->_addWarning('version', + 'A version number should have 3 decimals (x.y.z)'); + return true; + } + $name = $this->_packagexml->getPackage(); + // version must be based upon state + switch ($this->_packagexml->getState()) { + case 'snapshot' : + return true; + case 'devel' : + if ($versioncomponents[0] . 'a' == '0a') { + return true; + } + if ($versioncomponents[0] == 0) { + $versioncomponents[0] = '0'; + $this->_addWarning('version', + 'version "' . $version . '" should be "' . + implode('.' ,$versioncomponents) . '"'); + } else { + $this->_addWarning('version', + 'packages with devel stability must be < version 1.0.0'); + } + return true; + break; + case 'alpha' : + case 'beta' : + // check for a package that extends a package, + // like Foo and Foo2 + if ($this->_state == PEAR_VALIDATE_PACKAGING) { + if (substr($versioncomponents[2], 1, 2) == 'rc') { + $this->_addFailure('version', 'Release Candidate versions ' . + 'must have capital RC, not lower-case rc'); + return false; + } + } + if (!$this->_packagexml->getExtends()) { + if ($versioncomponents[0] == '1') { + if ($versioncomponents[2]{0} == '0') { + if ($versioncomponents[2] == '0') { + // version 1.*.0000 + $this->_addWarning('version', + 'version 1.' . $versioncomponents[1] . + '.0 probably should not be alpha or beta'); + return true; + } elseif (strlen($versioncomponents[2]) > 1) { + // version 1.*.0RC1 or 1.*.0beta24 etc. + return true; + } else { + // version 1.*.0 + $this->_addWarning('version', + 'version 1.' . $versioncomponents[1] . + '.0 probably should not be alpha or beta'); + return true; + } + } else { + $this->_addWarning('version', + 'bugfix versions (1.3.x where x > 0) probably should ' . + 'not be alpha or beta'); + return true; + } + } elseif ($versioncomponents[0] != '0') { + $this->_addWarning('version', + 'major versions greater than 1 are not allowed for packages ' . + 'without an tag or an identical postfix (foo2 v2.0.0)'); + return true; + } + if ($versioncomponents[0] . 'a' == '0a') { + return true; + } + if ($versioncomponents[0] == 0) { + $versioncomponents[0] = '0'; + $this->_addWarning('version', + 'version "' . $version . '" should be "' . + implode('.' ,$versioncomponents) . '"'); + } + } else { + $vlen = strlen($versioncomponents[0] . ''); + $majver = substr($name, strlen($name) - $vlen); + while ($majver && !is_numeric($majver{0})) { + $majver = substr($majver, 1); + } + if (($versioncomponents[0] != 0) && $majver != $versioncomponents[0]) { + $this->_addWarning('version', 'first version number "' . + $versioncomponents[0] . '" must match the postfix of ' . + 'package name "' . $name . '" (' . + $majver . ')'); + return true; + } + if ($versioncomponents[0] == $majver) { + if ($versioncomponents[2]{0} == '0') { + if ($versioncomponents[2] == '0') { + // version 2.*.0000 + $this->_addWarning('version', + "version $majver." . $versioncomponents[1] . + '.0 probably should not be alpha or beta'); + return false; + } elseif (strlen($versioncomponents[2]) > 1) { + // version 2.*.0RC1 or 2.*.0beta24 etc. + return true; + } else { + // version 2.*.0 + $this->_addWarning('version', + "version $majver." . $versioncomponents[1] . + '.0 cannot be alpha or beta'); + return true; + } + } else { + $this->_addWarning('version', + "bugfix versions ($majver.x.y where y > 0) should " . + 'not be alpha or beta'); + return true; + } + } elseif ($versioncomponents[0] != '0') { + $this->_addWarning('version', + "only versions 0.x.y and $majver.x.y are allowed for alpha/beta releases"); + return true; + } + if ($versioncomponents[0] . 'a' == '0a') { + return true; + } + if ($versioncomponents[0] == 0) { + $versioncomponents[0] = '0'; + $this->_addWarning('version', + 'version "' . $version . '" should be "' . + implode('.' ,$versioncomponents) . '"'); + } + } + return true; + break; + case 'stable' : + if ($versioncomponents[0] == '0') { + $this->_addWarning('version', 'versions less than 1.0.0 cannot ' . + 'be stable'); + return true; + } + if (!is_numeric($versioncomponents[2])) { + if (preg_match('/\d+(rc|a|alpha|b|beta)\d*/i', + $versioncomponents[2])) { + $this->_addWarning('version', 'version "' . $version . '" or any ' . + 'RC/beta/alpha version cannot be stable'); + return true; + } + } + // check for a package that extends a package, + // like Foo and Foo2 + if ($this->_packagexml->getExtends()) { + $vlen = strlen($versioncomponents[0] . ''); + $majver = substr($name, strlen($name) - $vlen); + while ($majver && !is_numeric($majver{0})) { + $majver = substr($majver, 1); + } + if (($versioncomponents[0] != 0) && $majver != $versioncomponents[0]) { + $this->_addWarning('version', 'first version number "' . + $versioncomponents[0] . '" must match the postfix of ' . + 'package name "' . $name . '" (' . + $majver . ')'); + return true; + } + } elseif ($versioncomponents[0] > 1) { + $this->_addWarning('version', 'major version x in x.y.z may not be greater than ' . + '1 for any package that does not have an tag'); + } + return true; + break; + default : + return false; + break; + } + } + + /** + * @access protected + */ + function validateMaintainers() + { + // maintainers can only be truly validated server-side for most channels + // but allow this customization for those who wish it + return true; + } + + /** + * @access protected + */ + function validateDate() + { + if ($this->_state == PEAR_VALIDATE_NORMAL || + $this->_state == PEAR_VALIDATE_PACKAGING) { + + if (!preg_match('/(\d\d\d\d)\-(\d\d)\-(\d\d)/', + $this->_packagexml->getDate(), $res) || + count($res) < 4 + || !checkdate($res[2], $res[3], $res[1]) + ) { + $this->_addFailure('date', 'invalid release date "' . + $this->_packagexml->getDate() . '"'); + return false; + } + + if ($this->_state == PEAR_VALIDATE_PACKAGING && + $this->_packagexml->getDate() != date('Y-m-d')) { + $this->_addWarning('date', 'Release Date "' . + $this->_packagexml->getDate() . '" is not today'); + } + } + return true; + } + + /** + * @access protected + */ + function validateTime() + { + if (!$this->_packagexml->getTime()) { + // default of no time value set + return true; + } + + // packager automatically sets time, so only validate if pear validate is called + if ($this->_state = PEAR_VALIDATE_NORMAL) { + if (!preg_match('/\d\d:\d\d:\d\d/', + $this->_packagexml->getTime())) { + $this->_addFailure('time', 'invalid release time "' . + $this->_packagexml->getTime() . '"'); + return false; + } + + $result = preg_match('|\d{2}\:\d{2}\:\d{2}|', $this->_packagexml->getTime(), $matches); + if ($result === false || empty($matches)) { + $this->_addFailure('time', 'invalid release time "' . + $this->_packagexml->getTime() . '"'); + return false; + } + } + + return true; + } + + /** + * @access protected + */ + function validateState() + { + // this is the closest to "final" php4 can get + if (!PEAR_Validate::validState($this->_packagexml->getState())) { + if (strtolower($this->_packagexml->getState() == 'rc')) { + $this->_addFailure('state', 'RC is not a state, it is a version ' . + 'postfix, use ' . $this->_packagexml->getVersion() . 'RC1, state beta'); + } + $this->_addFailure('state', 'invalid release state "' . + $this->_packagexml->getState() . '", must be one of: ' . + implode(', ', PEAR_Validate::getValidStates())); + return false; + } + return true; + } + + /** + * @access protected + */ + function validateStability() + { + $ret = true; + $packagestability = $this->_packagexml->getState(); + $apistability = $this->_packagexml->getState('api'); + if (!PEAR_Validate::validState($packagestability)) { + $this->_addFailure('state', 'invalid release stability "' . + $this->_packagexml->getState() . '", must be one of: ' . + implode(', ', PEAR_Validate::getValidStates())); + $ret = false; + } + $apistates = PEAR_Validate::getValidStates(); + array_shift($apistates); // snapshot is not allowed + if (!in_array($apistability, $apistates)) { + $this->_addFailure('state', 'invalid API stability "' . + $this->_packagexml->getState('api') . '", must be one of: ' . + implode(', ', $apistates)); + $ret = false; + } + return $ret; + } + + /** + * @access protected + */ + function validateSummary() + { + return true; + } + + /** + * @access protected + */ + function validateDescription() + { + return true; + } + + /** + * @access protected + */ + function validateLicense() + { + return true; + } + + /** + * @access protected + */ + function validateNotes() + { + return true; + } + + /** + * for package.xml 2.0 only - channels can't use package.xml 1.0 + * @access protected + */ + function validateDependencies() + { + return true; + } + + /** + * for package.xml 1.0 only + * @access private + */ + function _validateFilelist() + { + return true; // placeholder for now + } + + /** + * for package.xml 2.0 only + * @access protected + */ + function validateMainFilelist() + { + return true; // placeholder for now + } + + /** + * for package.xml 2.0 only + * @access protected + */ + function validateReleaseFilelist() + { + return true; // placeholder for now + } + + /** + * @access protected + */ + function validateChangelog() + { + return true; + } + + /** + * @access protected + */ + function validateFilelist() + { + return true; + } + + /** + * @access protected + */ + function validateDeps() + { + return true; + } +}PEAR-1.9.0/PEAR/XMLParser.php100664 764 764 16001 100664 10401 + * @author Stephan Schmidt (original XML_Unserializer code) + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license New BSD License + * @version CVS: $Id: XMLParser.php 282970 2009-06-28 23:10:07Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * Parser for any xml file + * @category pear + * @package PEAR + * @author Greg Beaver + * @author Stephan Schmidt (original XML_Unserializer code) + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_XMLParser +{ + /** + * unserilialized data + * @var string $_serializedData + */ + var $_unserializedData = null; + + /** + * name of the root tag + * @var string $_root + */ + var $_root = null; + + /** + * stack for all data that is found + * @var array $_dataStack + */ + var $_dataStack = array(); + + /** + * stack for all values that are generated + * @var array $_valStack + */ + var $_valStack = array(); + + /** + * current tag depth + * @var int $_depth + */ + var $_depth = 0; + + /** + * The XML encoding to use + * @var string $encoding + */ + var $encoding = 'ISO-8859-1'; + + /** + * @return array + */ + function getData() + { + return $this->_unserializedData; + } + + /** + * @param string xml content + * @return true|PEAR_Error + */ + function parse($data) + { + if (!extension_loaded('xml')) { + include_once 'PEAR.php'; + return PEAR::raiseError("XML Extension not found", 1); + } + $this->_dataStack = $this->_valStack = array(); + $this->_depth = 0; + + if ( + strpos($data, 'encoding="UTF-8"') + || strpos($data, 'encoding="utf-8"') + || strpos($data, "encoding='UTF-8'") + || strpos($data, "encoding='utf-8'") + ) { + $this->encoding = 'UTF-8'; + } + + if (version_compare(phpversion(), '5.0.0', 'lt') && $this->encoding == 'UTF-8') { + $data = utf8_decode($data); + $this->encoding = 'ISO-8859-1'; + } + + $xp = xml_parser_create($this->encoding); + xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, 0); + xml_set_object($xp, $this); + xml_set_element_handler($xp, 'startHandler', 'endHandler'); + xml_set_character_data_handler($xp, 'cdataHandler'); + if (!xml_parse($xp, $data)) { + $msg = xml_error_string(xml_get_error_code($xp)); + $line = xml_get_current_line_number($xp); + xml_parser_free($xp); + include_once 'PEAR.php'; + return PEAR::raiseError("XML Error: '$msg' on line '$line'", 2); + } + xml_parser_free($xp); + return true; + } + + /** + * Start element handler for XML parser + * + * @access private + * @param object $parser XML parser object + * @param string $element XML element + * @param array $attribs attributes of XML tag + * @return void + */ + function startHandler($parser, $element, $attribs) + { + $this->_depth++; + $this->_dataStack[$this->_depth] = null; + + $val = array( + 'name' => $element, + 'value' => null, + 'type' => 'string', + 'childrenKeys' => array(), + 'aggregKeys' => array() + ); + + if (count($attribs) > 0) { + $val['children'] = array(); + $val['type'] = 'array'; + $val['children']['attribs'] = $attribs; + } + + array_push($this->_valStack, $val); + } + + /** + * post-process data + * + * @param string $data + * @param string $element element name + */ + function postProcess($data, $element) + { + return trim($data); + } + + /** + * End element handler for XML parser + * + * @access private + * @param object XML parser object + * @param string + * @return void + */ + function endHandler($parser, $element) + { + $value = array_pop($this->_valStack); + $data = $this->postProcess($this->_dataStack[$this->_depth], $element); + + // adjust type of the value + switch (strtolower($value['type'])) { + // unserialize an array + case 'array': + if ($data !== '') { + $value['children']['_content'] = $data; + } + + $value['value'] = isset($value['children']) ? $value['children'] : array(); + break; + + /* + * unserialize a null value + */ + case 'null': + $data = null; + break; + + /* + * unserialize any scalar value + */ + default: + settype($data, $value['type']); + $value['value'] = $data; + break; + } + + $parent = array_pop($this->_valStack); + if ($parent === null) { + $this->_unserializedData = &$value['value']; + $this->_root = &$value['name']; + return true; + } + + // parent has to be an array + if (!isset($parent['children']) || !is_array($parent['children'])) { + $parent['children'] = array(); + if ($parent['type'] != 'array') { + $parent['type'] = 'array'; + } + } + + if (!empty($value['name'])) { + // there already has been a tag with this name + if (in_array($value['name'], $parent['childrenKeys'])) { + // no aggregate has been created for this tag + if (!in_array($value['name'], $parent['aggregKeys'])) { + if (isset($parent['children'][$value['name']])) { + $parent['children'][$value['name']] = array($parent['children'][$value['name']]); + } else { + $parent['children'][$value['name']] = array(); + } + array_push($parent['aggregKeys'], $value['name']); + } + array_push($parent['children'][$value['name']], $value['value']); + } else { + $parent['children'][$value['name']] = &$value['value']; + array_push($parent['childrenKeys'], $value['name']); + } + } else { + array_push($parent['children'],$value['value']); + } + array_push($this->_valStack, $parent); + + $this->_depth--; + } + + /** + * Handler for character data + * + * @access private + * @param object XML parser object + * @param string CDATA + * @return void + */ + function cdataHandler($parser, $cdata) + { + $this->_dataStack[$this->_depth] .= $cdata; + } +}PEAR-1.9.0/scripts/pear.bat100775 764 764 11102 100775 10435 @ECHO OFF + +REM ---------------------------------------------------------------------- +REM PHP version 5 +REM ---------------------------------------------------------------------- +REM Copyright (c) 1997-2004 The PHP Group +REM ---------------------------------------------------------------------- +REM This source file is subject to version 3.0 of the PHP license, +REM that is bundled with this package in the file LICENSE, and is +REM available at through the world-wide-web at +REM http://www.php.net/license/3_0.txt. +REM If you did not receive a copy of the PHP license and are unable to +REM obtain it through the world-wide-web, please send a note to +REM license@php.net so we can mail you a copy immediately. +REM ---------------------------------------------------------------------- +REM Authors: Alexander Merz (alexmerz@php.net) +REM ---------------------------------------------------------------------- +REM +REM Last updated 12/29/2004 ($Id$ is not replaced if the file is binary) + +REM change this lines to match the paths of your system +REM ------------------- + + +REM Test to see if this is a raw pear.bat (uninstalled version) +SET TMPTMPTMPTMPT=@includ +SET PMTPMTPMT=%TMPTMPTMPTMPT%e_path@ +FOR %%x IN ("@include_path@") DO (if %%x=="%PMTPMTPMT%" GOTO :NOTINSTALLED) + +REM Check PEAR global ENV, set them if they do not exist +IF "%PHP_PEAR_INSTALL_DIR%"=="" SET "PHP_PEAR_INSTALL_DIR=@include_path@" +IF "%PHP_PEAR_BIN_DIR%"=="" SET "PHP_PEAR_BIN_DIR=@bin_dir@" +IF "%PHP_PEAR_PHP_BIN%"=="" SET "PHP_PEAR_PHP_BIN=@php_bin@" +GOTO :INSTALLED + +:NOTINSTALLED +ECHO WARNING: This is a raw, uninstalled pear.bat + +REM Check to see if we can grab the directory of this file (Windows NT+) +IF %~n0 == pear ( +FOR %%x IN (cli\php.exe php.exe) DO (if "%%~$PATH:x" NEQ "" ( +SET "PHP_PEAR_PHP_BIN=%%~$PATH:x" +echo Using PHP Executable "%PHP_PEAR_PHP_BIN%" +"%PHP_PEAR_PHP_BIN%" -v +GOTO :NEXTTEST +)) +GOTO :FAILAUTODETECT +:NEXTTEST +IF "%PHP_PEAR_PHP_BIN%" NEQ "" ( + +REM We can use this PHP to run a temporary php file to get the dirname of pear + +echo ^ > ~~getloc.php +"%PHP_PEAR_PHP_BIN%" ~~getloc.php +set /p PHP_PEAR_BIN_DIR=fakeprompt < ~a.a +DEL ~a.a +DEL ~~getloc.php +set "PHP_PEAR_INSTALL_DIR=%PHP_PEAR_BIN_DIR%pear" + +REM Make sure there is a pearcmd.php at our disposal + +IF NOT EXIST %PHP_PEAR_INSTALL_DIR%\pearcmd.php ( +IF EXIST %PHP_PEAR_INSTALL_DIR%\scripts\pearcmd.php COPY %PHP_PEAR_INSTALL_DIR%\scripts\pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php +IF EXIST pearcmd.php COPY pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php +IF EXIST %~dp0\scripts\pearcmd.php COPY %~dp0\scripts\pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php +) +) +GOTO :INSTALLED +) ELSE ( +REM Windows Me/98 cannot succeed, so allow the batch to fail +) +:FAILAUTODETECT +echo WARNING: failed to auto-detect pear information +:INSTALLED + +REM Check Folders and files +IF NOT EXIST "%PHP_PEAR_INSTALL_DIR%" GOTO PEAR_INSTALL_ERROR +IF NOT EXIST "%PHP_PEAR_INSTALL_DIR%\pearcmd.php" GOTO PEAR_INSTALL_ERROR2 +IF NOT EXIST "%PHP_PEAR_BIN_DIR%" GOTO PEAR_BIN_ERROR +IF NOT EXIST "%PHP_PEAR_PHP_BIN%" GOTO PEAR_PHPBIN_ERROR +REM launch pearcmd +GOTO RUN +:PEAR_INSTALL_ERROR +ECHO PHP_PEAR_INSTALL_DIR is not set correctly. +ECHO Please fix it using your environment variable or modify +ECHO the default value in pear.bat +ECHO The current value is: +ECHO %PHP_PEAR_INSTALL_DIR% +GOTO END +:PEAR_INSTALL_ERROR2 +ECHO PHP_PEAR_INSTALL_DIR is not set correctly. +ECHO pearcmd.php could not be found there. +ECHO Please fix it using your environment variable or modify +ECHO the default value in pear.bat +ECHO The current value is: +ECHO %PHP_PEAR_INSTALL_DIR% +GOTO END +:PEAR_BIN_ERROR +ECHO PHP_PEAR_BIN_DIR is not set correctly. +ECHO Please fix it using your environment variable or modify +ECHO the default value in pear.bat +ECHO The current value is: +ECHO %PHP_PEAR_BIN_DIR% +GOTO END +:PEAR_PHPBIN_ERROR +ECHO PHP_PEAR_PHP_BIN is not set correctly. +ECHO Please fix it using your environment variable or modify +ECHO the default value in pear.bat +ECHO The current value is: +ECHO %PHP_PEAR_PHP_BIN% +GOTO END +:RUN +"%PHP_PEAR_PHP_BIN%" -C -d output_buffering=1 -d safe_mode=0 -d open_basedir="" -d auto_prepend_file="" -d auto_append_file="" -d variables_order=EGPCS -d register_argc_argv="On" -d include_path="%PHP_PEAR_INSTALL_DIR%" -f "%PHP_PEAR_INSTALL_DIR%\pearcmd.php" -- %1 %2 %3 %4 %5 %6 %7 %8 %9 +:END +@ECHO ONPEAR-1.9.0/scripts/peardev.bat100664 764 764 11112 100664 11127 @ECHO OFF + +REM ---------------------------------------------------------------------- +REM PHP version 5 +REM ---------------------------------------------------------------------- +REM Copyright (c) 1997-2004 The PHP Group +REM ---------------------------------------------------------------------- +REM This source file is subject to version 3.0 of the PHP license, +REM that is bundled with this package in the file LICENSE, and is +REM available at through the world-wide-web at +REM http://www.php.net/license/3_0.txt. +REM If you did not receive a copy of the PHP license and are unable to +REM obtain it through the world-wide-web, please send a note to +REM license@php.net so we can mail you a copy immediately. +REM ---------------------------------------------------------------------- +REM Authors: Alexander Merz (alexmerz@php.net) +REM ---------------------------------------------------------------------- +REM +REM $Id: peardev.bat,v 1.6 2007-09-03 03:00:17 cellog Exp $ + +REM change this lines to match the paths of your system +REM ------------------- + + +REM Test to see if this is a raw pear.bat (uninstalled version) +SET TMPTMPTMPTMPT=@includ +SET PMTPMTPMT=%TMPTMPTMPTMPT%e_path@ +FOR %%x IN ("@include_path@") DO (if %%x=="%PMTPMTPMT%" GOTO :NOTINSTALLED) + +REM Check PEAR global ENV, set them if they do not exist +IF "%PHP_PEAR_INSTALL_DIR%"=="" SET "PHP_PEAR_INSTALL_DIR=@include_path@" +IF "%PHP_PEAR_BIN_DIR%"=="" SET "PHP_PEAR_BIN_DIR=@bin_dir@" +IF "%PHP_PEAR_PHP_BIN%"=="" SET "PHP_PEAR_PHP_BIN=@php_bin@" +GOTO :INSTALLED + +:NOTINSTALLED +ECHO WARNING: This is a raw, uninstalled pear.bat + +REM Check to see if we can grab the directory of this file (Windows NT+) +IF %~n0 == pear ( +FOR %%x IN (cli\php.exe php.exe) DO (if "%%~$PATH:x" NEQ "" ( +SET "PHP_PEAR_PHP_BIN=%%~$PATH:x" +echo Using PHP Executable "%PHP_PEAR_PHP_BIN%" +"%PHP_PEAR_PHP_BIN%" -v +GOTO :NEXTTEST +)) +GOTO :FAILAUTODETECT +:NEXTTEST +IF "%PHP_PEAR_PHP_BIN%" NEQ "" ( + +REM We can use this PHP to run a temporary php file to get the dirname of pear + +echo ^ > ~~getloc.php +"%PHP_PEAR_PHP_BIN%" ~~getloc.php +set /p PHP_PEAR_BIN_DIR=fakeprompt < ~a.a +DEL ~a.a +DEL ~~getloc.php +set "PHP_PEAR_INSTALL_DIR=%PHP_PEAR_BIN_DIR%pear" + +REM Make sure there is a pearcmd.php at our disposal + +IF NOT EXIST %PHP_PEAR_INSTALL_DIR%\pearcmd.php ( +IF EXIST %PHP_PEAR_INSTALL_DIR%\scripts\pearcmd.php COPY %PHP_PEAR_INSTALL_DIR%\scripts\pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php +IF EXIST pearcmd.php COPY pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php +IF EXIST %~dp0\scripts\pearcmd.php COPY %~dp0\scripts\pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php +) +) +GOTO :INSTALLED +) ELSE ( +REM Windows Me/98 cannot succeed, so allow the batch to fail +) +:FAILAUTODETECT +echo WARNING: failed to auto-detect pear information +:INSTALLED + +REM Check Folders and files +IF NOT EXIST "%PHP_PEAR_INSTALL_DIR%" GOTO PEAR_INSTALL_ERROR +IF NOT EXIST "%PHP_PEAR_INSTALL_DIR%\pearcmd.php" GOTO PEAR_INSTALL_ERROR2 +IF NOT EXIST "%PHP_PEAR_BIN_DIR%" GOTO PEAR_BIN_ERROR +IF NOT EXIST "%PHP_PEAR_PHP_BIN%" GOTO PEAR_PHPBIN_ERROR +REM launch pearcmd +GOTO RUN +:PEAR_INSTALL_ERROR +ECHO PHP_PEAR_INSTALL_DIR is not set correctly. +ECHO Please fix it using your environment variable or modify +ECHO the default value in pear.bat +ECHO The current value is: +ECHO %PHP_PEAR_INSTALL_DIR% +GOTO END +:PEAR_INSTALL_ERROR2 +ECHO PHP_PEAR_INSTALL_DIR is not set correctly. +ECHO pearcmd.php could not be found there. +ECHO Please fix it using your environment variable or modify +ECHO the default value in pear.bat +ECHO The current value is: +ECHO %PHP_PEAR_INSTALL_DIR% +GOTO END +:PEAR_BIN_ERROR +ECHO PHP_PEAR_BIN_DIR is not set correctly. +ECHO Please fix it using your environment variable or modify +ECHO the default value in pear.bat +ECHO The current value is: +ECHO %PHP_PEAR_BIN_DIR% +GOTO END +:PEAR_PHPBIN_ERROR +ECHO PHP_PEAR_PHP_BIN is not set correctly. +ECHO Please fix it using your environment variable or modify +ECHO the default value in pear.bat +ECHO The current value is: +ECHO %PHP_PEAR_PHP_BIN% +GOTO END +:RUN +"%PHP_PEAR_PHP_BIN%" -C -d memory_limit="-1" -d safe_mode=0 -d register_argc_argv="On" -d auto_prepend_file="" -d auto_append_file="" -d variables_order=EGPCS -d open_basedir="" -d output_buffering=1 -d include_path="%PHP_PEAR_INSTALL_DIR%" -f "%PHP_PEAR_INSTALL_DIR%\pearcmd.php" -- %1 %2 %3 %4 %5 %6 %7 %8 %9 +:END +@ECHO ONPEAR-1.9.0/scripts/pecl.bat100664 764 764 11003 100664 10423 @ECHO OFF + +REM ---------------------------------------------------------------------- +REM PHP version 5 +REM ---------------------------------------------------------------------- +REM Copyright (c) 1997-2004 The PHP Group +REM ---------------------------------------------------------------------- +REM This source file is subject to version 3.0 of the PHP license, +REM that is bundled with this package in the file LICENSE, and is +REM available at through the world-wide-web at +REM http://www.php.net/license/3_0.txt. +REM If you did not receive a copy of the PHP license and are unable to +REM obtain it through the world-wide-web, please send a note to +REM license@php.net so we can mail you a copy immediately. +REM ---------------------------------------------------------------------- +REM Authors: Alexander Merz (alexmerz@php.net) +REM ---------------------------------------------------------------------- +REM +REM Last updated 02/08/2004 ($Id$ is not replaced if the file is binary) + +REM change this lines to match the paths of your system +REM ------------------- + + +REM Test to see if this is a raw pear.bat (uninstalled version) +SET TMPTMPTMPTMPT=@includ +SET PMTPMTPMT=%TMPTMPTMPTMPT%e_path@ +FOR %%x IN ("@include_path@") DO (if %%x=="%PMTPMTPMT%" GOTO :NOTINSTALLED) + +REM Check PEAR global ENV, set them if they do not exist +IF "%PHP_PEAR_INSTALL_DIR%"=="" SET "PHP_PEAR_INSTALL_DIR=@include_path@" +IF "%PHP_PEAR_BIN_DIR%"=="" SET "PHP_PEAR_BIN_DIR=@bin_dir@" +IF "%PHP_PEAR_PHP_BIN%"=="" SET "PHP_PEAR_PHP_BIN=@php_bin@" +GOTO :INSTALLED + +:NOTINSTALLED +ECHO WARNING: This is a raw, uninstalled pear.bat + +REM Check to see if we can grab the directory of this file (Windows NT+) +IF %~n0 == pear ( +FOR %%x IN (cli\php.exe php.exe) DO (if "%%~$PATH:x" NEQ "" ( +SET "PHP_PEAR_PHP_BIN=%%~$PATH:x" +echo Using PHP Executable "%PHP_PEAR_PHP_BIN%" +"%PHP_PEAR_PHP_BIN%" -v +GOTO :NEXTTEST +)) +GOTO :FAILAUTODETECT +:NEXTTEST +IF "%PHP_PEAR_PHP_BIN%" NEQ "" ( + +REM We can use this PHP to run a temporary php file to get the dirname of pear + +echo ^ > ~~getloc.php +"%PHP_PEAR_PHP_BIN%" ~~getloc.php +set /p PHP_PEAR_BIN_DIR=fakeprompt < ~a.a +DEL ~a.a +DEL ~~getloc.php +set "PHP_PEAR_INSTALL_DIR=%PHP_PEAR_BIN_DIR%pear" + +REM Make sure there is a pearcmd.php at our disposal + +IF NOT EXIST %PHP_PEAR_INSTALL_DIR%\pearcmd.php ( +IF EXIST %PHP_PEAR_INSTALL_DIR%\scripts\pearcmd.php COPY %PHP_PEAR_INSTALL_DIR%\scripts\pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php +IF EXIST pearcmd.php COPY pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php +IF EXIST %~dp0\scripts\pearcmd.php COPY %~dp0\scripts\pearcmd.php %PHP_PEAR_INSTALL_DIR%\pearcmd.php +) +) +GOTO :INSTALLED +) ELSE ( +REM Windows Me/98 cannot succeed, so allow the batch to fail +) +:FAILAUTODETECT +echo WARNING: failed to auto-detect pear information +:INSTALLED + +REM Check Folders and files +IF NOT EXIST "%PHP_PEAR_INSTALL_DIR%" GOTO PEAR_INSTALL_ERROR +IF NOT EXIST "%PHP_PEAR_INSTALL_DIR%\pearcmd.php" GOTO PEAR_INSTALL_ERROR2 +IF NOT EXIST "%PHP_PEAR_BIN_DIR%" GOTO PEAR_BIN_ERROR +IF NOT EXIST "%PHP_PEAR_PHP_BIN%" GOTO PEAR_PHPBIN_ERROR +REM launch pearcmd +GOTO RUN +:PEAR_INSTALL_ERROR +ECHO PHP_PEAR_INSTALL_DIR is not set correctly. +ECHO Please fix it using your environment variable or modify +ECHO the default value in pear.bat +ECHO The current value is: +ECHO %PHP_PEAR_INSTALL_DIR% +GOTO END +:PEAR_INSTALL_ERROR2 +ECHO PHP_PEAR_INSTALL_DIR is not set correctly. +ECHO pearcmd.php could not be found there. +ECHO Please fix it using your environment variable or modify +ECHO the default value in pear.bat +ECHO The current value is: +ECHO %PHP_PEAR_INSTALL_DIR% +GOTO END +:PEAR_BIN_ERROR +ECHO PHP_PEAR_BIN_DIR is not set correctly. +ECHO Please fix it using your environment variable or modify +ECHO the default value in pear.bat +ECHO The current value is: +ECHO %PHP_PEAR_BIN_DIR% +GOTO END +:PEAR_PHPBIN_ERROR +ECHO PHP_PEAR_PHP_BIN is not set correctly. +ECHO Please fix it using your environment variable or modify +ECHO the default value in pear.bat +ECHO The current value is: +ECHO %PHP_PEAR_PHP_BIN% +GOTO END +:RUN +"%PHP_PEAR_PHP_BIN%" -C -n -d output_buffering=1 -d safe_mode=0 -d include_path="%PHP_PEAR_INSTALL_DIR%" -d register_argc_argv="On" -d variables_order=EGPCS -f "%PHP_PEAR_INSTALL_DIR%\peclcmd.php" -- %1 %2 %3 %4 %5 %6 %7 %8 %9 +:END +@ECHO ONPEAR-1.9.0/scripts/pear.sh100664 764 764 1362 100664 10262 #!/bin/sh + +# first find which PHP binary to use +if test "x$PHP_PEAR_PHP_BIN" != "x"; then + PHP="$PHP_PEAR_PHP_BIN" +else + if test "@php_bin@" = '@'php_bin'@'; then + PHP=php + else + PHP="@php_bin@" + fi +fi + +# then look for the right pear include dir +if test "x$PHP_PEAR_INSTALL_DIR" != "x"; then + INCDIR=$PHP_PEAR_INSTALL_DIR + INCARG="-d include_path=$PHP_PEAR_INSTALL_DIR" +else + if test "@php_dir@" = '@'php_dir'@'; then + INCDIR=`dirname $0` + INCARG="" + else + INCDIR="@php_dir@" + INCARG="-d include_path=@php_dir@" + fi +fi + +exec $PHP -C -q $INCARG -d output_buffering=1 -d variables_order=EGPCS -d open_basedir="" -d safe_mode=0 -d register_argc_argv="On" -d auto_prepend_file="" -d auto_append_file="" $INCDIR/pearcmd.php "$@" +PEAR-1.9.0/scripts/peardev.sh100664 764 764 1407 100664 10761 #!/bin/sh + +# first find which PHP binary to use +if test "x$PHP_PEAR_PHP_BIN" != "x"; then + PHP="$PHP_PEAR_PHP_BIN" +else + if test "@php_bin@" = '@'php_bin'@'; then + PHP=php + else + PHP="@php_bin@" + fi +fi + +# then look for the right pear include dir +if test "x$PHP_PEAR_INSTALL_DIR" != "x"; then + INCDIR=$PHP_PEAR_INSTALL_DIR + INCARG="-d include_path=$PHP_PEAR_INSTALL_DIR" +else + if test "@php_dir@" = '@'php_dir'@'; then + INCDIR=`dirname $0` + INCARG="" + else + INCDIR="@php_dir@" + INCARG="-d include_path=@php_dir@" + fi +fi + +exec $PHP -d memory_limit="-1" -C -q $INCARG -d output_buffering=1 -d open_basedir="" -d safe_mode=0 -d register_argc_argv="On" -d auto_prepend_file="" -d variables_order=EGPCS -d auto_append_file="" $INCDIR/pearcmd.php "$@" +PEAR-1.9.0/scripts/pecl.sh100664 764 764 1263 100664 10256 #!/bin/sh + +# first find which PHP binary to use +if test "x$PHP_PEAR_PHP_BIN" != "x"; then + PHP="$PHP_PEAR_PHP_BIN" +else + if test "@php_bin@" = '@'php_bin'@'; then + PHP=php + else + PHP="@php_bin@" + fi +fi + +# then look for the right pear include dir +if test "x$PHP_PEAR_INSTALL_DIR" != "x"; then + INCDIR=$PHP_PEAR_INSTALL_DIR + INCARG="-d include_path=$PHP_PEAR_INSTALL_DIR" +else + if test "@php_dir@" = '@'php_dir'@'; then + INCDIR=`dirname $0` + INCARG="" + else + INCDIR="@php_dir@" + INCARG="-d include_path=@php_dir@" + fi +fi + +exec $PHP -C -n -q $INCARG -d output_buffering=1 -d variables_order=EGPCS -d safe_mode=0 -d register_argc_argv="On" $INCDIR/peclcmd.php "$@" +PEAR-1.9.0/scripts/pearcmd.php100664 764 764 34076 100664 11153 + * @author Tomas V.V.Cox + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: pearcmd.php 286487 2009-07-29 05:57:28Z dufuz $ + * @link http://pear.php.net/package/PEAR + */ + +ob_end_clean(); +if (!defined('PEAR_RUNTYPE')) { + // this is defined in peclcmd.php as 'pecl' + define('PEAR_RUNTYPE', 'pear'); +} +define('PEAR_IGNORE_BACKTRACE', 1); +/** + * @nodep Gtk + */ +if ('@include_path@' != '@'.'include_path'.'@') { + ini_set('include_path', '@include_path@'); + $raw = false; +} else { + // this is a raw, uninstalled pear, either a cvs checkout, or php distro + $raw = true; +} +@ini_set('allow_url_fopen', true); +if (!ini_get('safe_mode')) { + @set_time_limit(0); +} +ob_implicit_flush(true); +@ini_set('track_errors', true); +@ini_set('html_errors', false); +@ini_set('magic_quotes_runtime', false); +$_PEAR_PHPDIR = '#$%^&*'; +set_error_handler('error_handler'); + +$pear_package_version = "@pear_version@"; + +require_once 'PEAR.php'; +require_once 'PEAR/Frontend.php'; +require_once 'PEAR/Config.php'; +require_once 'PEAR/Command.php'; +require_once 'Console/Getopt.php'; + + +PEAR_Command::setFrontendType('CLI'); +$all_commands = PEAR_Command::getCommands(); + +// remove this next part when we stop supporting that crap-ass PHP 4.2 +if (!isset($_SERVER['argv']) && !isset($argv) && !isset($HTTP_SERVER_VARS['argv'])) { + echo 'ERROR: either use the CLI php executable, or set register_argc_argv=On in php.ini'; + exit(1); +} + +$argv = Console_Getopt::readPHPArgv(); +// fix CGI sapi oddity - the -- in pear.bat/pear is not removed +if (php_sapi_name() != 'cli' && isset($argv[1]) && $argv[1] == '--') { + unset($argv[1]); + $argv = array_values($argv); +} +$progname = PEAR_RUNTYPE; +array_shift($argv); +$options = Console_Getopt::getopt2($argv, "c:C:d:D:Gh?sSqu:vV"); +if (PEAR::isError($options)) { + usage($options); +} + +$opts = $options[0]; + +$fetype = 'CLI'; +if ($progname == 'gpear' || $progname == 'pear-gtk') { + $fetype = 'Gtk'; +} else { + foreach ($opts as $opt) { + if ($opt[0] == 'G') { + $fetype = 'Gtk'; + } + } +} +//Check if Gtk and PHP >= 5.1.0 +if ($fetype == 'Gtk' && version_compare(phpversion(), '5.1.0', '>=')) { + $fetype = 'Gtk2'; +} + +$pear_user_config = ''; +$pear_system_config = ''; +$store_user_config = false; +$store_system_config = false; +$verbose = 1; + +foreach ($opts as $opt) { + switch ($opt[0]) { + case 'c': + $pear_user_config = $opt[1]; + break; + case 'C': + $pear_system_config = $opt[1]; + break; + } +} + +PEAR_Command::setFrontendType($fetype); +$ui = &PEAR_Command::getFrontendObject(); +$config = &PEAR_Config::singleton($pear_user_config, $pear_system_config); + +if (PEAR::isError($config)) { + $_file = ''; + if ($pear_user_config !== false) { + $_file .= $pear_user_config; + } + if ($pear_system_config !== false) { + $_file .= '/' . $pear_system_config; + } + if ($_file == '/') { + $_file = 'The default config file'; + } + $config->getMessage(); + $ui->outputData("ERROR: $_file is not a valid config file or is corrupted."); + // We stop, we have no idea where we are :) + exit(1); +} + +// this is used in the error handler to retrieve a relative path +$_PEAR_PHPDIR = $config->get('php_dir'); +$ui->setConfig($config); +PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, array($ui, "displayFatalError")); +if (ini_get('safe_mode')) { + $ui->outputData('WARNING: running in safe mode requires that all files created ' . + 'be the same uid as the current script. PHP reports this script is uid: ' . + @getmyuid() . ', and current user is: ' . @get_current_user()); +} + +$verbose = $config->get("verbose"); +$cmdopts = array(); + +if ($raw) { + if (!$config->isDefinedLayer('user') && !$config->isDefinedLayer('system')) { + $found = false; + foreach ($opts as $opt) { + if ($opt[0] == 'd' || $opt[0] == 'D') { + $found = true; // the user knows what they are doing, and are setting config values + } + } + if (!$found) { + // no prior runs, try to install PEAR + if (strpos(dirname(__FILE__), 'scripts')) { + $packagexml = dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'package2.xml'; + $pearbase = dirname(dirname(__FILE__)); + } else { + $packagexml = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'package2.xml'; + $pearbase = dirname(__FILE__); + } + if (file_exists($packagexml)) { + $options[1] = array( + 'install', + $packagexml + ); + $config->set('php_dir', $pearbase . DIRECTORY_SEPARATOR . 'php'); + $config->set('data_dir', $pearbase . DIRECTORY_SEPARATOR . 'data'); + $config->set('doc_dir', $pearbase . DIRECTORY_SEPARATOR . 'docs'); + $config->set('test_dir', $pearbase . DIRECTORY_SEPARATOR . 'tests'); + $config->set('ext_dir', $pearbase . DIRECTORY_SEPARATOR . 'extensions'); + $config->set('bin_dir', $pearbase); + $config->mergeConfigFile($pearbase . 'pear.ini', false); + $config->store(); + $config->set('auto_discover', 1); + } + } + } +} +foreach ($opts as $opt) { + $param = !empty($opt[1]) ? $opt[1] : true; + switch ($opt[0]) { + case 'd': + if ($param === true) { + die('Invalid usage of "-d" option, expected -d config_value=value, ' . + 'received "-d"' . "\n"); + } + $possible = explode('=', $param); + if (count($possible) != 2) { + die('Invalid usage of "-d" option, expected -d config_value=value, received "' . + $param . '"' . "\n"); + } + list($key, $value) = explode('=', $param); + $config->set($key, $value, 'user'); + break; + case 'D': + if ($param === true) { + die('Invalid usage of "-d" option, expected -d config_value=value, ' . + 'received "-d"' . "\n"); + } + $possible = explode('=', $param); + if (count($possible) != 2) { + die('Invalid usage of "-d" option, expected -d config_value=value, received "' . + $param . '"' . "\n"); + } + list($key, $value) = explode('=', $param); + $config->set($key, $value, 'system'); + break; + case 's': + $store_user_config = true; + break; + case 'S': + $store_system_config = true; + break; + case 'u': + $config->remove($param, 'user'); + break; + case 'v': + $config->set('verbose', $config->get('verbose') + 1); + break; + case 'q': + $config->set('verbose', $config->get('verbose') - 1); + break; + case 'V': + usage(null, 'version'); + case 'c': + case 'C': + break; + default: + // all non pear params goes to the command + $cmdopts[$opt[0]] = $param; + break; + } +} + +if ($store_system_config) { + $config->store('system'); +} + +if ($store_user_config) { + $config->store('user'); +} + +$command = (isset($options[1][0])) ? $options[1][0] : null; +if (empty($command) && ($store_user_config || $store_system_config)) { + exit; +} + +if ($fetype == 'Gtk' || $fetype == 'Gtk2') { + if (!$config->validConfiguration()) { + PEAR::raiseError('CRITICAL ERROR: no existing valid configuration files found in files ' . + "'$pear_user_config' or '$pear_system_config', please copy an existing configuration" . + 'file to one of these locations, or use the -c and -s options to create one'); + } + Gtk::main(); +} else do { + if ($command == 'help') { + usage(null, @$options[1][1]); + } + + if (!$config->validConfiguration()) { + PEAR::raiseError('CRITICAL ERROR: no existing valid configuration files found in files ' . + "'$pear_user_config' or '$pear_system_config', please copy an existing configuration" . + 'file to one of these locations, or use the -c and -s options to create one'); + } + + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $cmd = PEAR_Command::factory($command, $config); + PEAR::popErrorHandling(); + if (PEAR::isError($cmd)) { + usage(null, @$options[1][0]); + } + + $short_args = $long_args = null; + PEAR_Command::getGetoptArgs($command, $short_args, $long_args); + array_shift($options[1]); + $tmp = Console_Getopt::getopt2($options[1], $short_args, $long_args); + + if (PEAR::isError($tmp)) { + break; + } + + list($tmpopt, $params) = $tmp; + $opts = array(); + foreach ($tmpopt as $foo => $tmp2) { + list($opt, $value) = $tmp2; + if ($value === null) { + $value = true; // options without args + } + + if (strlen($opt) == 1) { + $cmdoptions = $cmd->getOptions($command); + foreach ($cmdoptions as $o => $d) { + if (isset($d['shortopt']) && $d['shortopt'] == $opt) { + $opts[$o] = $value; + } + } + } else { + if (substr($opt, 0, 2) == '--') { + $opts[substr($opt, 2)] = $value; + } + } + } + + $ok = $cmd->run($command, $opts, $params); + if ($ok === false) { + PEAR::raiseError("unknown command `$command'"); + } + + if (PEAR::isError($ok)) { + PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, array($ui, "displayFatalError")); + PEAR::raiseError($ok); + } +} while (false); + +// {{{ usage() + +function usage($error = null, $helpsubject = null) +{ + global $progname, $all_commands; + $stderr = fopen('php://stderr', 'w'); + if (PEAR::isError($error)) { + fputs($stderr, $error->getMessage() . "\n"); + } elseif ($error !== null) { + fputs($stderr, "$error\n"); + } + + if ($helpsubject != null) { + $put = cmdHelp($helpsubject); + } else { + $put = + "Commands:\n"; + $maxlen = max(array_map("strlen", $all_commands)); + $formatstr = "%-{$maxlen}s %s\n"; + ksort($all_commands); + foreach ($all_commands as $cmd => $class) { + $put .= sprintf($formatstr, $cmd, PEAR_Command::getDescription($cmd)); + } + $put .= + "Usage: $progname [options] command [command-options] \n". + "Type \"$progname help options\" to list all options.\n". + "Type \"$progname help shortcuts\" to list all command shortcuts.\n". + "Type \"$progname help \" to get the help for the specified command."; + } + fputs($stderr, "$put\n"); + fclose($stderr); + exit(1); +} + +function cmdHelp($command) +{ + global $progname, $all_commands, $config; + if ($command == "options") { + return + "Options:\n". + " -v increase verbosity level (default 1)\n". + " -q be quiet, decrease verbosity level\n". + " -c file find user configuration in `file'\n". + " -C file find system configuration in `file'\n". + " -d foo=bar set user config variable `foo' to `bar'\n". + " -D foo=bar set system config variable `foo' to `bar'\n". + " -G start in graphical (Gtk) mode\n". + " -s store user configuration\n". + " -S store system configuration\n". + " -u foo unset `foo' in the user configuration\n". + " -h, -? display help/usage (this message)\n". + " -V version information\n"; + } elseif ($command == "shortcuts") { + $sc = PEAR_Command::getShortcuts(); + $ret = "Shortcuts:\n"; + foreach ($sc as $s => $c) { + $ret .= sprintf(" %-8s %s\n", $s, $c); + } + return $ret; + + } elseif ($command == "version") { + return "PEAR Version: ".$GLOBALS['pear_package_version']. + "\nPHP Version: ".phpversion(). + "\nZend Engine Version: ".zend_version(). + "\nRunning on: ".php_uname(); + + } elseif ($help = PEAR_Command::getHelp($command)) { + if (is_string($help)) { + return "$progname $command [options] $help\n"; + } + + if ($help[1] === null) { + return "$progname $command $help[0]"; + } + + return "$progname $command [options] $help[0]\n$help[1]"; + } + + return "Command '$command' is not valid, try '$progname help'"; +} + +// }}} + +function error_handler($errno, $errmsg, $file, $line, $vars) { + if ((defined('E_STRICT') && $errno & E_STRICT) || (defined('E_DEPRECATED') && + $errno & E_DEPRECATED) || !error_reporting()) { + if (defined('E_STRICT') && $errno & E_STRICT) { + return; // E_STRICT + } + if (defined('E_DEPRECATED') && $errno & E_DEPRECATED) { + return; // E_DEPRECATED + } + if ($GLOBALS['config']->get('verbose') < 4) { + return false; // @silenced error, show all if debug is high enough + } + } + $errortype = array ( + E_ERROR => "Error", + E_WARNING => "Warning", + E_PARSE => "Parsing Error", + E_NOTICE => "Notice", + E_CORE_ERROR => "Core Error", + E_CORE_WARNING => "Core Warning", + E_COMPILE_ERROR => "Compile Error", + E_COMPILE_WARNING => "Compile Warning", + E_USER_ERROR => "User Error", + E_USER_WARNING => "User Warning", + E_USER_NOTICE => "User Notice" + ); + $prefix = $errortype[$errno]; + global $_PEAR_PHPDIR; + if (stristr($file, $_PEAR_PHPDIR)) { + $file = substr($file, strlen($_PEAR_PHPDIR) + 1); + } else { + $file = basename($file); + } + print "\n$prefix: $errmsg in $file on line $line\n"; + return false; +} + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * indent-tabs-mode: nil + * mode: php + * End: + */ +// vim600:syn=phpPEAR-1.9.0/scripts/peclcmd.php100664 764 764 1636 100664 11123 + * @author Tomas V.V.Cox + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: peclcmd.php 276392 2009-02-25 00:06:23Z dufuz $ + * @link http://pear.php.net/package/PEAR + */ + +/** + * @nodep Gtk + */ +if ('@include_path@' != '@'.'include_path'.'@') { + ini_set('include_path', '@include_path@'); + $raw = false; +} else { + // this is a raw, uninstalled pear, either a cvs checkout, or php distro + $raw = true; +} +define('PEAR_RUNTYPE', 'pecl'); +require_once 'pearcmd.php'; +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * indent-tabs-mode: nil + * mode: php + * End: + */ +// vim600:syn=php + +?> +PEAR-1.9.0/LICENSE100664 764 764 2705 100664 6317 Copyright (c) 1997-2009, + Stig Bakken , + Gregory Beaver , + Helgi Þormar Þorbjörnsson , + Tomas V.V.Cox , + Martin Jansen . +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +PEAR-1.9.0/INSTALL100664 764 764 3641 100664 6343 PEAR - The PEAR Installer +========================= +Installing the PEAR Installer. + +You should install PEAR on a local development machine first. Installing +PEAR on a remote production machine should only be done after you are +familiar with PEAR and have tested code using PEAR on your development +machine. + +There are two methods of installing PEAR + - PEAR bundled in PHP + - go-pear + +We will first examine how to install PEAR that is bundled with PHP. + +Microsoft Windows +================= +If you are running PHP 5.2.0 or newer, simply download and +run the windows installer (.msi) and PEAR can be automatically +installed. + +Otherwise, for older PHP versions, download the .zip of windows, +there is a script included with your PHP distribution that is called +"go-pear". You must open a command box in order to run it. Click +"start" then click "Run..." and type "cmd.exe" to open a command box. +Use "cd" to change directory to the location of PHP where you unzipped it, +and run the go-pear command. + +Unix +==== +make sure you have enabled default extensions, and if you want faster +downloads, enable the zlib extension. You must also enable the CLI +SAPI with the --enable-cli extension directive. After this, simply run: + +make install-pear + +and PEAR will be automatically configured for you. + +go-pear +======= +For users who cannot perform the above steps, or who wish to obtain the +latest PEAR with a slightly higher risk of failure, use go-pear. go-pear +is obtained by downloading http://go-pear.org and saving it as go-pear.php. +After downloading, simply run "php go-pear.php" or open it in a web browser +(windows only) to download and install PEAR. + +You can always ask general installation questions on pear-general@lists.php.net, +a public mailing list devoted to support for PEAR packages and installation- +related issues. + +Happy PHPing, we hope PEAR will be a great tool for your development work! + +$Id: INSTALL 220345 2006-09-22 03:31:36Z cellog $PEAR-1.9.0/package.dtd100664 764 764 6477 100664 7414 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +PEAR-1.9.0/PEAR5.php100664 764 764 2077 100664 6641 + * @author Stig Bakken + * @author Tomas V.V.Cox + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: PEAR.php 286670 2009-08-02 14:16:06Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/**#@+ + * ERROR constants + */ +define('PEAR_ERROR_RETURN', 1); +define('PEAR_ERROR_PRINT', 2); +define('PEAR_ERROR_TRIGGER', 4); +define('PEAR_ERROR_DIE', 8); +define('PEAR_ERROR_CALLBACK', 16); +/** + * WARNING: obsolete + * @deprecated + */ +define('PEAR_ERROR_EXCEPTION', 32); +/**#@-*/ +define('PEAR_ZE2', (function_exists('version_compare') && + version_compare(zend_version(), "2-dev", "ge"))); + +if (substr(PHP_OS, 0, 3) == 'WIN') { + define('OS_WINDOWS', true); + define('OS_UNIX', false); + define('PEAR_OS', 'Windows'); +} else { + define('OS_WINDOWS', false); + define('OS_UNIX', true); + define('PEAR_OS', 'Unix'); // blatant assumption +} + +$GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_RETURN; +$GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE; +$GLOBALS['_PEAR_destructor_object_list'] = array(); +$GLOBALS['_PEAR_shutdown_funcs'] = array(); +$GLOBALS['_PEAR_error_handler_stack'] = array(); + +@ini_set('track_errors', true); + +/** + * Base class for other PEAR classes. Provides rudimentary + * emulation of destructors. + * + * If you want a destructor in your class, inherit PEAR and make a + * destructor method called _yourclassname (same name as the + * constructor, but with a "_" prefix). Also, in your constructor you + * have to call the PEAR constructor: $this->PEAR();. + * The destructor method will be called without parameters. Note that + * at in some SAPI implementations (such as Apache), any output during + * the request shutdown (in which destructors are called) seems to be + * discarded. If you need to get any debug information from your + * destructor, use error_log(), syslog() or something similar. + * + * IMPORTANT! To use the emulated destructors you need to create the + * objects by reference: $obj =& new PEAR_child; + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Tomas V.V. Cox + * @author Greg Beaver + * @copyright 1997-2006 The PHP Group + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @see PEAR_Error + * @since Class available since PHP 4.0.2 + * @link http://pear.php.net/manual/en/core.pear.php#core.pear.pear + */ +class PEAR +{ + // {{{ properties + + /** + * Whether to enable internal debug messages. + * + * @var bool + * @access private + */ + var $_debug = false; + + /** + * Default error mode for this object. + * + * @var int + * @access private + */ + var $_default_error_mode = null; + + /** + * Default error options used for this object when error mode + * is PEAR_ERROR_TRIGGER. + * + * @var int + * @access private + */ + var $_default_error_options = null; + + /** + * Default error handler (callback) for this object, if error mode is + * PEAR_ERROR_CALLBACK. + * + * @var string + * @access private + */ + var $_default_error_handler = ''; + + /** + * Which class to use for error objects. + * + * @var string + * @access private + */ + var $_error_class = 'PEAR_Error'; + + /** + * An array of expected errors. + * + * @var array + * @access private + */ + var $_expected_errors = array(); + + // }}} + + // {{{ constructor + + /** + * Constructor. Registers this object in + * $_PEAR_destructor_object_list for destructor emulation if a + * destructor object exists. + * + * @param string $error_class (optional) which class to use for + * error objects, defaults to PEAR_Error. + * @access public + * @return void + */ + function PEAR($error_class = null) + { + $classname = strtolower(get_class($this)); + if ($this->_debug) { + print "PEAR constructor called, class=$classname\n"; + } + if ($error_class !== null) { + $this->_error_class = $error_class; + } + while ($classname && strcasecmp($classname, "pear")) { + $destructor = "_$classname"; + if (method_exists($this, $destructor)) { + global $_PEAR_destructor_object_list; + $_PEAR_destructor_object_list[] = &$this; + if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { + register_shutdown_function("_PEAR_call_destructors"); + $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; + } + break; + } else { + $classname = get_parent_class($classname); + } + } + } + + // }}} + // {{{ destructor + + /** + * Destructor (the emulated type of...). Does nothing right now, + * but is included for forward compatibility, so subclass + * destructors should always call it. + * + * See the note in the class desciption about output from + * destructors. + * + * @access public + * @return void + */ + function _PEAR() { + if ($this->_debug) { + printf("PEAR destructor called, class=%s\n", strtolower(get_class($this))); + } + } + + // }}} + // {{{ getStaticProperty() + + /** + * If you have a class that's mostly/entirely static, and you need static + * properties, you can use this method to simulate them. Eg. in your method(s) + * do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar'); + * You MUST use a reference, or they will not persist! + * + * @access public + * @param string $class The calling classname, to prevent clashes + * @param string $var The variable to retrieve. + * @return mixed A reference to the variable. If not set it will be + * auto initialised to NULL. + */ + function &getStaticProperty($class, $var) + { + static $properties; + if (!isset($properties[$class])) { + $properties[$class] = array(); + } + + if (!array_key_exists($var, $properties[$class])) { + $properties[$class][$var] = null; + } + + return $properties[$class][$var]; + } + + // }}} + // {{{ registerShutdownFunc() + + /** + * Use this function to register a shutdown method for static + * classes. + * + * @access public + * @param mixed $func The function name (or array of class/method) to call + * @param mixed $args The arguments to pass to the function + * @return void + */ + function registerShutdownFunc($func, $args = array()) + { + // if we are called statically, there is a potential + // that no shutdown func is registered. Bug #6445 + if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { + register_shutdown_function("_PEAR_call_destructors"); + $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; + } + $GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args); + } + + // }}} + // {{{ isError() + + /** + * Tell whether a value is a PEAR error. + * + * @param mixed $data the value to test + * @param int $code if $data is an error object, return true + * only if $code is a string and + * $obj->getMessage() == $code or + * $code is an integer and $obj->getCode() == $code + * @access public + * @return bool true if parameter is an error + */ + function isError($data, $code = null) + { + if (!is_a($data, 'PEAR_Error')) { + return false; + } + + if (is_null($code)) { + return true; + } elseif (is_string($code)) { + return $data->getMessage() == $code; + } + + return $data->getCode() == $code; + } + + // }}} + // {{{ setErrorHandling() + + /** + * Sets how errors generated by this object should be handled. + * Can be invoked both in objects and statically. If called + * statically, setErrorHandling sets the default behaviour for all + * PEAR objects. If called in an object, setErrorHandling sets + * the default behaviour for that object. + * + * @param int $mode + * One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, + * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, + * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION. + * + * @param mixed $options + * When $mode is PEAR_ERROR_TRIGGER, this is the error level (one + * of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). + * + * When $mode is PEAR_ERROR_CALLBACK, this parameter is expected + * to be the callback function or method. A callback + * function is a string with the name of the function, a + * callback method is an array of two elements: the element + * at index 0 is the object, and the element at index 1 is + * the name of the method to call in the object. + * + * When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is + * a printf format string used when printing the error + * message. + * + * @access public + * @return void + * @see PEAR_ERROR_RETURN + * @see PEAR_ERROR_PRINT + * @see PEAR_ERROR_TRIGGER + * @see PEAR_ERROR_DIE + * @see PEAR_ERROR_CALLBACK + * @see PEAR_ERROR_EXCEPTION + * + * @since PHP 4.0.5 + */ + + function setErrorHandling($mode = null, $options = null) + { + if (isset($this) && is_a($this, 'PEAR')) { + $setmode = &$this->_default_error_mode; + $setoptions = &$this->_default_error_options; + } else { + $setmode = &$GLOBALS['_PEAR_default_error_mode']; + $setoptions = &$GLOBALS['_PEAR_default_error_options']; + } + + switch ($mode) { + case PEAR_ERROR_EXCEPTION: + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $setmode = $mode; + $setoptions = $options; + break; + + case PEAR_ERROR_CALLBACK: + $setmode = $mode; + // class/object method callback + if (is_callable($options)) { + $setoptions = $options; + } else { + trigger_error("invalid error callback", E_USER_WARNING); + } + break; + + default: + trigger_error("invalid error mode", E_USER_WARNING); + break; + } + } + + // }}} + // {{{ expectError() + + /** + * This method is used to tell which errors you expect to get. + * Expected errors are always returned with error mode + * PEAR_ERROR_RETURN. Expected error codes are stored in a stack, + * and this method pushes a new element onto it. The list of + * expected errors are in effect until they are popped off the + * stack with the popExpect() method. + * + * Note that this method can not be called statically + * + * @param mixed $code a single error code or an array of error codes to expect + * + * @return int the new depth of the "expected errors" stack + * @access public + */ + function expectError($code = '*') + { + if (is_array($code)) { + array_push($this->_expected_errors, $code); + } else { + array_push($this->_expected_errors, array($code)); + } + return sizeof($this->_expected_errors); + } + + // }}} + // {{{ popExpect() + + /** + * This method pops one element off the expected error codes + * stack. + * + * @return array the list of error codes that were popped + */ + function popExpect() + { + return array_pop($this->_expected_errors); + } + + // }}} + // {{{ _checkDelExpect() + + /** + * This method checks unsets an error code if available + * + * @param mixed error code + * @return bool true if the error code was unset, false otherwise + * @access private + * @since PHP 4.3.0 + */ + function _checkDelExpect($error_code) + { + $deleted = false; + + foreach ($this->_expected_errors AS $key => $error_array) { + if (in_array($error_code, $error_array)) { + unset($this->_expected_errors[$key][array_search($error_code, $error_array)]); + $deleted = true; + } + + // clean up empty arrays + if (0 == count($this->_expected_errors[$key])) { + unset($this->_expected_errors[$key]); + } + } + return $deleted; + } + + // }}} + // {{{ delExpect() + + /** + * This method deletes all occurences of the specified element from + * the expected error codes stack. + * + * @param mixed $error_code error code that should be deleted + * @return mixed list of error codes that were deleted or error + * @access public + * @since PHP 4.3.0 + */ + function delExpect($error_code) + { + $deleted = false; + if ((is_array($error_code) && (0 != count($error_code)))) { + // $error_code is a non-empty array here; + // we walk through it trying to unset all + // values + foreach($error_code as $key => $error) { + if ($this->_checkDelExpect($error)) { + $deleted = true; + } else { + $deleted = false; + } + } + return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME + } elseif (!empty($error_code)) { + // $error_code comes alone, trying to unset it + if ($this->_checkDelExpect($error_code)) { + return true; + } else { + return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME + } + } + + // $error_code is empty + return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME + } + + // }}} + // {{{ raiseError() + + /** + * This method is a wrapper that returns an instance of the + * configured error class with this object's default error + * handling applied. If the $mode and $options parameters are not + * specified, the object's defaults are used. + * + * @param mixed $message a text error message or a PEAR error object + * + * @param int $code a numeric error code (it is up to your class + * to define these if you want to use codes) + * + * @param int $mode One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, + * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, + * PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION. + * + * @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter + * specifies the PHP-internal error level (one of + * E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). + * If $mode is PEAR_ERROR_CALLBACK, this + * parameter specifies the callback function or + * method. In other error modes this parameter + * is ignored. + * + * @param string $userinfo If you need to pass along for example debug + * information, this parameter is meant for that. + * + * @param string $error_class The returned error object will be + * instantiated from this class, if specified. + * + * @param bool $skipmsg If true, raiseError will only pass error codes, + * the error message parameter will be dropped. + * + * @access public + * @return object a PEAR error object + * @see PEAR::setErrorHandling + * @since PHP 4.0.5 + */ + function &raiseError($message = null, + $code = null, + $mode = null, + $options = null, + $userinfo = null, + $error_class = null, + $skipmsg = false) + { + // The error is yet a PEAR error object + if (is_object($message)) { + $code = $message->getCode(); + $userinfo = $message->getUserInfo(); + $error_class = $message->getType(); + $message->error_message_prefix = ''; + $message = $message->getMessage(); + } + + if (isset($this) && isset($this->_expected_errors) && sizeof($this->_expected_errors) > 0 && sizeof($exp = end($this->_expected_errors))) { + if ($exp[0] == "*" || + (is_int(reset($exp)) && in_array($code, $exp)) || + (is_string(reset($exp)) && in_array($message, $exp))) { + $mode = PEAR_ERROR_RETURN; + } + } + + // No mode given, try global ones + if ($mode === null) { + // Class error handler + if (isset($this) && isset($this->_default_error_mode)) { + $mode = $this->_default_error_mode; + $options = $this->_default_error_options; + // Global error handler + } elseif (isset($GLOBALS['_PEAR_default_error_mode'])) { + $mode = $GLOBALS['_PEAR_default_error_mode']; + $options = $GLOBALS['_PEAR_default_error_options']; + } + } + + if ($error_class !== null) { + $ec = $error_class; + } elseif (isset($this) && isset($this->_error_class)) { + $ec = $this->_error_class; + } else { + $ec = 'PEAR_Error'; + } + + if (intval(PHP_VERSION) < 5) { + // little non-eval hack to fix bug #12147 + include 'PEAR/FixPHP5PEARWarnings.php'; + return $a; + } + + if ($skipmsg) { + $a = new $ec($code, $mode, $options, $userinfo); + } else { + $a = new $ec($message, $code, $mode, $options, $userinfo); + } + + return $a; + } + + // }}} + // {{{ throwError() + + /** + * Simpler form of raiseError with fewer options. In most cases + * message, code and userinfo are enough. + * + * @param string $message + * + */ + function &throwError($message = null, + $code = null, + $userinfo = null) + { + if (isset($this) && is_a($this, 'PEAR')) { + $a = &$this->raiseError($message, $code, null, null, $userinfo); + return $a; + } + + $a = &PEAR::raiseError($message, $code, null, null, $userinfo); + return $a; + } + + // }}} + function staticPushErrorHandling($mode, $options = null) + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + $def_mode = &$GLOBALS['_PEAR_default_error_mode']; + $def_options = &$GLOBALS['_PEAR_default_error_options']; + $stack[] = array($def_mode, $def_options); + switch ($mode) { + case PEAR_ERROR_EXCEPTION: + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $def_mode = $mode; + $def_options = $options; + break; + + case PEAR_ERROR_CALLBACK: + $def_mode = $mode; + // class/object method callback + if (is_callable($options)) { + $def_options = $options; + } else { + trigger_error("invalid error callback", E_USER_WARNING); + } + break; + + default: + trigger_error("invalid error mode", E_USER_WARNING); + break; + } + $stack[] = array($mode, $options); + return true; + } + + function staticPopErrorHandling() + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + $setmode = &$GLOBALS['_PEAR_default_error_mode']; + $setoptions = &$GLOBALS['_PEAR_default_error_options']; + array_pop($stack); + list($mode, $options) = $stack[sizeof($stack) - 1]; + array_pop($stack); + switch ($mode) { + case PEAR_ERROR_EXCEPTION: + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $setmode = $mode; + $setoptions = $options; + break; + + case PEAR_ERROR_CALLBACK: + $setmode = $mode; + // class/object method callback + if (is_callable($options)) { + $setoptions = $options; + } else { + trigger_error("invalid error callback", E_USER_WARNING); + } + break; + + default: + trigger_error("invalid error mode", E_USER_WARNING); + break; + } + return true; + } + + // {{{ pushErrorHandling() + + /** + * Push a new error handler on top of the error handler options stack. With this + * you can easily override the actual error handler for some code and restore + * it later with popErrorHandling. + * + * @param mixed $mode (same as setErrorHandling) + * @param mixed $options (same as setErrorHandling) + * + * @return bool Always true + * + * @see PEAR::setErrorHandling + */ + function pushErrorHandling($mode, $options = null) + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + if (isset($this) && is_a($this, 'PEAR')) { + $def_mode = &$this->_default_error_mode; + $def_options = &$this->_default_error_options; + } else { + $def_mode = &$GLOBALS['_PEAR_default_error_mode']; + $def_options = &$GLOBALS['_PEAR_default_error_options']; + } + $stack[] = array($def_mode, $def_options); + + if (isset($this) && is_a($this, 'PEAR')) { + $this->setErrorHandling($mode, $options); + } else { + PEAR::setErrorHandling($mode, $options); + } + $stack[] = array($mode, $options); + return true; + } + + // }}} + // {{{ popErrorHandling() + + /** + * Pop the last error handler used + * + * @return bool Always true + * + * @see PEAR::pushErrorHandling + */ + function popErrorHandling() + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + array_pop($stack); + list($mode, $options) = $stack[sizeof($stack) - 1]; + array_pop($stack); + if (isset($this) && is_a($this, 'PEAR')) { + $this->setErrorHandling($mode, $options); + } else { + PEAR::setErrorHandling($mode, $options); + } + return true; + } + + // }}} + // {{{ loadExtension() + + /** + * OS independant PHP extension load. Remember to take care + * on the correct extension name for case sensitive OSes. + * + * @param string $ext The extension name + * @return bool Success or not on the dl() call + */ + function loadExtension($ext) + { + if (!extension_loaded($ext)) { + // if either returns true dl() will produce a FATAL error, stop that + if ((ini_get('enable_dl') != 1) || (ini_get('safe_mode') == 1)) { + return false; + } + + if (OS_WINDOWS) { + $suffix = '.dll'; + } elseif (PHP_OS == 'HP-UX') { + $suffix = '.sl'; + } elseif (PHP_OS == 'AIX') { + $suffix = '.a'; + } elseif (PHP_OS == 'OSX') { + $suffix = '.bundle'; + } else { + $suffix = '.so'; + } + + return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix); + } + + return true; + } + + // }}} +} + +if (PEAR_ZE2) { + include_once 'PEAR5.php'; +} + +// {{{ _PEAR_call_destructors() + +function _PEAR_call_destructors() +{ + global $_PEAR_destructor_object_list; + if (is_array($_PEAR_destructor_object_list) && + sizeof($_PEAR_destructor_object_list)) + { + reset($_PEAR_destructor_object_list); + if (PEAR_ZE2) { + $destructLifoExists = PEAR5::getStaticProperty('PEAR', 'destructlifo'); + } else { + $destructLifoExists = PEAR::getStaticProperty('PEAR', 'destructlifo'); + } + + if ($destructLifoExists) { + $_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list); + } + + while (list($k, $objref) = each($_PEAR_destructor_object_list)) { + $classname = get_class($objref); + while ($classname) { + $destructor = "_$classname"; + if (method_exists($objref, $destructor)) { + $objref->$destructor(); + break; + } else { + $classname = get_parent_class($classname); + } + } + } + // Empty the object list to ensure that destructors are + // not called more than once. + $_PEAR_destructor_object_list = array(); + } + + // Now call the shutdown functions + if (isset($GLOBALS['_PEAR_shutdown_funcs']) AND is_array($GLOBALS['_PEAR_shutdown_funcs']) AND !empty($GLOBALS['_PEAR_shutdown_funcs'])) { + foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) { + call_user_func_array($value[0], $value[1]); + } + } +} + +// }}} +/** + * Standard PEAR error class for PHP 4 + * + * This class is supserseded by {@link PEAR_Exception} in PHP 5 + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Tomas V.V. Cox + * @author Gregory Beaver + * @copyright 1997-2006 The PHP Group + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/manual/en/core.pear.pear-error.php + * @see PEAR::raiseError(), PEAR::throwError() + * @since Class available since PHP 4.0.2 + */ +class PEAR_Error +{ + // {{{ properties + + var $error_message_prefix = ''; + var $mode = PEAR_ERROR_RETURN; + var $level = E_USER_NOTICE; + var $code = -1; + var $message = ''; + var $userinfo = ''; + var $backtrace = null; + + // }}} + // {{{ constructor + + /** + * PEAR_Error constructor + * + * @param string $message message + * + * @param int $code (optional) error code + * + * @param int $mode (optional) error mode, one of: PEAR_ERROR_RETURN, + * PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER, + * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION + * + * @param mixed $options (optional) error level, _OR_ in the case of + * PEAR_ERROR_CALLBACK, the callback function or object/method + * tuple. + * + * @param string $userinfo (optional) additional user/debug info + * + * @access public + * + */ + function PEAR_Error($message = 'unknown error', $code = null, + $mode = null, $options = null, $userinfo = null) + { + if ($mode === null) { + $mode = PEAR_ERROR_RETURN; + } + $this->message = $message; + $this->code = $code; + $this->mode = $mode; + $this->userinfo = $userinfo; + + if (PEAR_ZE2) { + $skiptrace = PEAR5::getStaticProperty('PEAR_Error', 'skiptrace'); + } else { + $skiptrace = PEAR::getStaticProperty('PEAR_Error', 'skiptrace'); + } + + if (!$skiptrace) { + $this->backtrace = debug_backtrace(); + if (isset($this->backtrace[0]) && isset($this->backtrace[0]['object'])) { + unset($this->backtrace[0]['object']); + } + } + + if ($mode & PEAR_ERROR_CALLBACK) { + $this->level = E_USER_NOTICE; + $this->callback = $options; + } else { + if ($options === null) { + $options = E_USER_NOTICE; + } + + $this->level = $options; + $this->callback = null; + } + + if ($this->mode & PEAR_ERROR_PRINT) { + if (is_null($options) || is_int($options)) { + $format = "%s"; + } else { + $format = $options; + } + + printf($format, $this->getMessage()); + } + + if ($this->mode & PEAR_ERROR_TRIGGER) { + trigger_error($this->getMessage(), $this->level); + } + + if ($this->mode & PEAR_ERROR_DIE) { + $msg = $this->getMessage(); + if (is_null($options) || is_int($options)) { + $format = "%s"; + if (substr($msg, -1) != "\n") { + $msg .= "\n"; + } + } else { + $format = $options; + } + die(sprintf($format, $msg)); + } + + if ($this->mode & PEAR_ERROR_CALLBACK) { + if (is_callable($this->callback)) { + call_user_func($this->callback, $this); + } + } + + if ($this->mode & PEAR_ERROR_EXCEPTION) { + trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_Exception for exceptions", E_USER_WARNING); + eval('$e = new Exception($this->message, $this->code);throw($e);'); + } + } + + // }}} + // {{{ getMode() + + /** + * Get the error mode from an error object. + * + * @return int error mode + * @access public + */ + function getMode() { + return $this->mode; + } + + // }}} + // {{{ getCallback() + + /** + * Get the callback function/method from an error object. + * + * @return mixed callback function or object/method array + * @access public + */ + function getCallback() { + return $this->callback; + } + + // }}} + // {{{ getMessage() + + + /** + * Get the error message from an error object. + * + * @return string full error message + * @access public + */ + function getMessage() + { + return ($this->error_message_prefix . $this->message); + } + + + // }}} + // {{{ getCode() + + /** + * Get error code from an error object + * + * @return int error code + * @access public + */ + function getCode() + { + return $this->code; + } + + // }}} + // {{{ getType() + + /** + * Get the name of this error/exception. + * + * @return string error/exception name (type) + * @access public + */ + function getType() + { + return get_class($this); + } + + // }}} + // {{{ getUserInfo() + + /** + * Get additional user-supplied information. + * + * @return string user-supplied information + * @access public + */ + function getUserInfo() + { + return $this->userinfo; + } + + // }}} + // {{{ getDebugInfo() + + /** + * Get additional debug information supplied by the application. + * + * @return string debug information + * @access public + */ + function getDebugInfo() + { + return $this->getUserInfo(); + } + + // }}} + // {{{ getBacktrace() + + /** + * Get the call backtrace from where the error was generated. + * Supported with PHP 4.3.0 or newer. + * + * @param int $frame (optional) what frame to fetch + * @return array Backtrace, or NULL if not available. + * @access public + */ + function getBacktrace($frame = null) + { + if (defined('PEAR_IGNORE_BACKTRACE')) { + return null; + } + if ($frame === null) { + return $this->backtrace; + } + return $this->backtrace[$frame]; + } + + // }}} + // {{{ addUserInfo() + + function addUserInfo($info) + { + if (empty($this->userinfo)) { + $this->userinfo = $info; + } else { + $this->userinfo .= " ** $info"; + } + } + + // }}} + // {{{ toString() + function __toString() + { + return $this->getMessage(); + } + // }}} + // {{{ toString() + + /** + * Make a string representation of this object. + * + * @return string a string with an object summary + * @access public + */ + function toString() { + $modes = array(); + $levels = array(E_USER_NOTICE => 'notice', + E_USER_WARNING => 'warning', + E_USER_ERROR => 'error'); + if ($this->mode & PEAR_ERROR_CALLBACK) { + if (is_array($this->callback)) { + $callback = (is_object($this->callback[0]) ? + strtolower(get_class($this->callback[0])) : + $this->callback[0]) . '::' . + $this->callback[1]; + } else { + $callback = $this->callback; + } + return sprintf('[%s: message="%s" code=%d mode=callback '. + 'callback=%s prefix="%s" info="%s"]', + strtolower(get_class($this)), $this->message, $this->code, + $callback, $this->error_message_prefix, + $this->userinfo); + } + if ($this->mode & PEAR_ERROR_PRINT) { + $modes[] = 'print'; + } + if ($this->mode & PEAR_ERROR_TRIGGER) { + $modes[] = 'trigger'; + } + if ($this->mode & PEAR_ERROR_DIE) { + $modes[] = 'die'; + } + if ($this->mode & PEAR_ERROR_RETURN) { + $modes[] = 'return'; + } + return sprintf('[%s: message="%s" code=%d mode=%s level=%s '. + 'prefix="%s" info="%s"]', + strtolower(get_class($this)), $this->message, $this->code, + implode("|", $modes), $levels[$this->level], + $this->error_message_prefix, + $this->userinfo); + } + + // }}} +} + +/* + * Local Variables: + * mode: php + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ +PEAR-1.9.0/README100664 764 764 2246 100664 6172 PEAR - The PEAR Installer +========================= + +What is the PEAR Installer? What is PEAR? + +PEAR is the PHP Extension and Application Repository, found at +http://pear.php.net. The PEAR Installer is this software, which +contains executable files and PHP code that is used to download +and install PEAR code from pear.php.net. + +PEAR contains useful software libraries and applications such as +MDB2 (database abstraction), HTML_QuickForm (HTML forms management), +PhpDocumentor (auto-documentation generator), DB_DataObject +(Data Access Abstraction), and many hundreds more. Browse all +available packages at http://pear.php.net, the list is constantly +growing and updating to reflect improvements in the PHP language. + +DOCUMENTATION +============= + +Documentation for PEAR can be found at http://pear.php.net/manual/. +Installation documentation can be found in the INSTALL file included +in this tarball. + +WARNING: DO NOT RUN PEAR WITHOUT INSTALLING IT - if you downloaded this +tarball manually, you MUST install it. Read the instructions in INSTALL +prior to use. + + +Happy PHPing, we hope PEAR will be a great tool for your development work! + +$Id: README 220345 2006-09-22 03:31:36Z cellog $PEAR-1.9.0/System.php100664 764 764 46777 100664 7350 + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: System.php 276386 2009-02-24 23:52:56Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * base class + */ +require_once 'PEAR.php'; +require_once 'Console/Getopt.php'; + +$GLOBALS['_System_temp_files'] = array(); + +/** +* System offers cross plattform compatible system functions +* +* Static functions for different operations. Should work under +* Unix and Windows. The names and usage has been taken from its respectively +* GNU commands. The functions will return (bool) false on error and will +* trigger the error with the PHP trigger_error() function (you can silence +* the error by prefixing a '@' sign after the function call, but this +* is not recommended practice. Instead use an error handler with +* {@link set_error_handler()}). +* +* Documentation on this class you can find in: +* http://pear.php.net/manual/ +* +* Example usage: +* if (!@System::rm('-r file1 dir1')) { +* print "could not delete file1 or dir1"; +* } +* +* In case you need to to pass file names with spaces, +* pass the params as an array: +* +* System::rm(array('-r', $file1, $dir1)); +* +* @category pear +* @package System +* @author Tomas V.V. Cox +* @copyright 1997-2006 The PHP Group +* @license http://opensource.org/licenses/bsd-license.php New BSD License +* @version Release: 1.9.0 +* @link http://pear.php.net/package/PEAR +* @since Class available since Release 0.1 +* @static +*/ +class System +{ + /** + * returns the commandline arguments of a function + * + * @param string $argv the commandline + * @param string $short_options the allowed option short-tags + * @param string $long_options the allowed option long-tags + * @return array the given options and there values + * @static + * @access private + */ + function _parseArgs($argv, $short_options, $long_options = null) + { + if (!is_array($argv) && $argv !== null) { + $argv = preg_split('/\s+/', $argv, -1, PREG_SPLIT_NO_EMPTY); + } + return Console_Getopt::getopt2($argv, $short_options); + } + + /** + * Output errors with PHP trigger_error(). You can silence the errors + * with prefixing a "@" sign to the function call: @System::mkdir(..); + * + * @param mixed $error a PEAR error or a string with the error message + * @return bool false + * @static + * @access private + */ + function raiseError($error) + { + if (PEAR::isError($error)) { + $error = $error->getMessage(); + } + trigger_error($error, E_USER_WARNING); + return false; + } + + /** + * Creates a nested array representing the structure of a directory + * + * System::_dirToStruct('dir1', 0) => + * Array + * ( + * [dirs] => Array + * ( + * [0] => dir1 + * ) + * + * [files] => Array + * ( + * [0] => dir1/file2 + * [1] => dir1/file3 + * ) + * ) + * @param string $sPath Name of the directory + * @param integer $maxinst max. deep of the lookup + * @param integer $aktinst starting deep of the lookup + * @param bool $silent if true, do not emit errors. + * @return array the structure of the dir + * @static + * @access private + */ + function _dirToStruct($sPath, $maxinst, $aktinst = 0, $silent = false) + { + $struct = array('dirs' => array(), 'files' => array()); + if (($dir = @opendir($sPath)) === false) { + if (!$silent) { + System::raiseError("Could not open dir $sPath"); + } + return $struct; // XXX could not open error + } + + $struct['dirs'][] = $sPath = realpath($sPath); // XXX don't add if '.' or '..' ? + $list = array(); + while (false !== ($file = readdir($dir))) { + if ($file != '.' && $file != '..') { + $list[] = $file; + } + } + + closedir($dir); + natsort($list); + if ($aktinst < $maxinst || $maxinst == 0) { + foreach ($list as $val) { + $path = $sPath . DIRECTORY_SEPARATOR . $val; + if (is_dir($path) && !is_link($path)) { + $tmp = System::_dirToStruct($path, $maxinst, $aktinst+1, $silent); + $struct = array_merge_recursive($struct, $tmp); + } else { + $struct['files'][] = $path; + } + } + } + + return $struct; + } + + /** + * Creates a nested array representing the structure of a directory and files + * + * @param array $files Array listing files and dirs + * @return array + * @static + * @see System::_dirToStruct() + */ + function _multipleToStruct($files) + { + $struct = array('dirs' => array(), 'files' => array()); + settype($files, 'array'); + foreach ($files as $file) { + if (is_dir($file) && !is_link($file)) { + $tmp = System::_dirToStruct($file, 0); + $struct = array_merge_recursive($tmp, $struct); + } else { + if (!in_array($file, $struct['files'])) { + $struct['files'][] = $file; + } + } + } + return $struct; + } + + /** + * The rm command for removing files. + * Supports multiple files and dirs and also recursive deletes + * + * @param string $args the arguments for rm + * @return mixed PEAR_Error or true for success + * @static + * @access public + */ + function rm($args) + { + $opts = System::_parseArgs($args, 'rf'); // "f" does nothing but I like it :-) + if (PEAR::isError($opts)) { + return System::raiseError($opts); + } + foreach ($opts[0] as $opt) { + if ($opt[0] == 'r') { + $do_recursive = true; + } + } + $ret = true; + if (isset($do_recursive)) { + $struct = System::_multipleToStruct($opts[1]); + foreach ($struct['files'] as $file) { + if (!@unlink($file)) { + $ret = false; + } + } + + rsort($struct['dirs']); + foreach ($struct['dirs'] as $dir) { + if (!@rmdir($dir)) { + $ret = false; + } + } + } else { + foreach ($opts[1] as $file) { + $delete = (is_dir($file)) ? 'rmdir' : 'unlink'; + if (!@$delete($file)) { + $ret = false; + } + } + } + return $ret; + } + + /** + * Make directories. + * + * The -p option will create parent directories + * @param string $args the name of the director(y|ies) to create + * @return bool True for success + * @static + * @access public + */ + function mkDir($args) + { + $opts = System::_parseArgs($args, 'pm:'); + if (PEAR::isError($opts)) { + return System::raiseError($opts); + } + + $mode = 0777; // default mode + foreach ($opts[0] as $opt) { + if ($opt[0] == 'p') { + $create_parents = true; + } elseif ($opt[0] == 'm') { + // if the mode is clearly an octal number (starts with 0) + // convert it to decimal + if (strlen($opt[1]) && $opt[1]{0} == '0') { + $opt[1] = octdec($opt[1]); + } else { + // convert to int + $opt[1] += 0; + } + $mode = $opt[1]; + } + } + + $ret = true; + if (isset($create_parents)) { + foreach ($opts[1] as $dir) { + $dirstack = array(); + while ((!file_exists($dir) || !is_dir($dir)) && + $dir != DIRECTORY_SEPARATOR) { + array_unshift($dirstack, $dir); + $dir = dirname($dir); + } + + while ($newdir = array_shift($dirstack)) { + if (!is_writeable(dirname($newdir))) { + $ret = false; + break; + } + + if (!mkdir($newdir, $mode)) { + $ret = false; + } + } + } + } else { + foreach($opts[1] as $dir) { + if ((@file_exists($dir) || !is_dir($dir)) && !mkdir($dir, $mode)) { + $ret = false; + } + } + } + + return $ret; + } + + /** + * Concatenate files + * + * Usage: + * 1) $var = System::cat('sample.txt test.txt'); + * 2) System::cat('sample.txt test.txt > final.txt'); + * 3) System::cat('sample.txt test.txt >> final.txt'); + * + * Note: as the class use fopen, urls should work also (test that) + * + * @param string $args the arguments + * @return boolean true on success + * @static + * @access public + */ + function &cat($args) + { + $ret = null; + $files = array(); + if (!is_array($args)) { + $args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY); + } + + $count_args = count($args); + for ($i = 0; $i < $count_args; $i++) { + if ($args[$i] == '>') { + $mode = 'wb'; + $outputfile = $args[$i+1]; + break; + } elseif ($args[$i] == '>>') { + $mode = 'ab+'; + $outputfile = $args[$i+1]; + break; + } else { + $files[] = $args[$i]; + } + } + $outputfd = false; + if (isset($mode)) { + if (!$outputfd = fopen($outputfile, $mode)) { + $err = System::raiseError("Could not open $outputfile"); + return $err; + } + $ret = true; + } + foreach ($files as $file) { + if (!$fd = fopen($file, 'r')) { + System::raiseError("Could not open $file"); + continue; + } + while ($cont = fread($fd, 2048)) { + if (is_resource($outputfd)) { + fwrite($outputfd, $cont); + } else { + $ret .= $cont; + } + } + fclose($fd); + } + if (is_resource($outputfd)) { + fclose($outputfd); + } + return $ret; + } + + /** + * Creates temporary files or directories. This function will remove + * the created files when the scripts finish its execution. + * + * Usage: + * 1) $tempfile = System::mktemp("prefix"); + * 2) $tempdir = System::mktemp("-d prefix"); + * 3) $tempfile = System::mktemp(); + * 4) $tempfile = System::mktemp("-t /var/tmp prefix"); + * + * prefix -> The string that will be prepended to the temp name + * (defaults to "tmp"). + * -d -> A temporary dir will be created instead of a file. + * -t -> The target dir where the temporary (file|dir) will be created. If + * this param is missing by default the env vars TMP on Windows or + * TMPDIR in Unix will be used. If these vars are also missing + * c:\windows\temp or /tmp will be used. + * + * @param string $args The arguments + * @return mixed the full path of the created (file|dir) or false + * @see System::tmpdir() + * @static + * @access public + */ + function mktemp($args = null) + { + static $first_time = true; + $opts = System::_parseArgs($args, 't:d'); + if (PEAR::isError($opts)) { + return System::raiseError($opts); + } + + foreach ($opts[0] as $opt) { + if ($opt[0] == 'd') { + $tmp_is_dir = true; + } elseif ($opt[0] == 't') { + $tmpdir = $opt[1]; + } + } + + $prefix = (isset($opts[1][0])) ? $opts[1][0] : 'tmp'; + if (!isset($tmpdir)) { + $tmpdir = System::tmpdir(); + } + + if (!System::mkDir(array('-p', $tmpdir))) { + return false; + } + + $tmp = tempnam($tmpdir, $prefix); + if (isset($tmp_is_dir)) { + unlink($tmp); // be careful possible race condition here + if (!mkdir($tmp, 0700)) { + return System::raiseError("Unable to create temporary directory $tmpdir"); + } + } + + $GLOBALS['_System_temp_files'][] = $tmp; + if (isset($tmp_is_dir)) { + //$GLOBALS['_System_temp_files'][] = dirname($tmp); + } + + if ($first_time) { + PEAR::registerShutdownFunc(array('System', '_removeTmpFiles')); + $first_time = false; + } + + return $tmp; + } + + /** + * Remove temporary files created my mkTemp. This function is executed + * at script shutdown time + * + * @static + * @access private + */ + function _removeTmpFiles() + { + if (count($GLOBALS['_System_temp_files'])) { + $delete = $GLOBALS['_System_temp_files']; + array_unshift($delete, '-r'); + System::rm($delete); + $GLOBALS['_System_temp_files'] = array(); + } + } + + /** + * Get the path of the temporal directory set in the system + * by looking in its environments variables. + * Note: php.ini-recommended removes the "E" from the variables_order setting, + * making unavaible the $_ENV array, that s why we do tests with _ENV + * + * @static + * @return string The temporary directory on the system + */ + function tmpdir() + { + if (OS_WINDOWS) { + if ($var = isset($_ENV['TMP']) ? $_ENV['TMP'] : getenv('TMP')) { + return $var; + } + if ($var = isset($_ENV['TEMP']) ? $_ENV['TEMP'] : getenv('TEMP')) { + return $var; + } + if ($var = isset($_ENV['USERPROFILE']) ? $_ENV['USERPROFILE'] : getenv('USERPROFILE')) { + return $var; + } + if ($var = isset($_ENV['windir']) ? $_ENV['windir'] : getenv('windir')) { + return $var; + } + return getenv('SystemRoot') . '\temp'; + } + if ($var = isset($_ENV['TMPDIR']) ? $_ENV['TMPDIR'] : getenv('TMPDIR')) { + return $var; + } + return realpath('/tmp'); + } + + /** + * The "which" command (show the full path of a command) + * + * @param string $program The command to search for + * @param mixed $fallback Value to return if $program is not found + * + * @return mixed A string with the full path or false if not found + * @static + * @author Stig Bakken + */ + function which($program, $fallback = false) + { + // enforce API + if (!is_string($program) || '' == $program) { + return $fallback; + } + + // full path given + if (basename($program) != $program) { + $path_elements[] = dirname($program); + $program = basename($program); + } else { + // Honor safe mode + if (!ini_get('safe_mode') || !$path = ini_get('safe_mode_exec_dir')) { + $path = getenv('PATH'); + if (!$path) { + $path = getenv('Path'); // some OSes are just stupid enough to do this + } + } + $path_elements = explode(PATH_SEPARATOR, $path); + } + + if (OS_WINDOWS) { + $exe_suffixes = getenv('PATHEXT') + ? explode(PATH_SEPARATOR, getenv('PATHEXT')) + : array('.exe','.bat','.cmd','.com'); + // allow passing a command.exe param + if (strpos($program, '.') !== false) { + array_unshift($exe_suffixes, ''); + } + // is_executable() is not available on windows for PHP4 + $pear_is_executable = (function_exists('is_executable')) ? 'is_executable' : 'is_file'; + } else { + $exe_suffixes = array(''); + $pear_is_executable = 'is_executable'; + } + + foreach ($exe_suffixes as $suff) { + foreach ($path_elements as $dir) { + $file = $dir . DIRECTORY_SEPARATOR . $program . $suff; + if (@$pear_is_executable($file)) { + return $file; + } + } + } + return $fallback; + } + + /** + * The "find" command + * + * Usage: + * + * System::find($dir); + * System::find("$dir -type d"); + * System::find("$dir -type f"); + * System::find("$dir -name *.php"); + * System::find("$dir -name *.php -name *.htm*"); + * System::find("$dir -maxdepth 1"); + * + * Params implmented: + * $dir -> Start the search at this directory + * -type d -> return only directories + * -type f -> return only files + * -maxdepth -> max depth of recursion + * -name -> search pattern (bash style). Multiple -name param allowed + * + * @param mixed Either array or string with the command line + * @return array Array of found files + * @static + * + */ + function find($args) + { + if (!is_array($args)) { + $args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY); + } + $dir = realpath(array_shift($args)); + if (!$dir) { + return array(); + } + $patterns = array(); + $depth = 0; + $do_files = $do_dirs = true; + $args_count = count($args); + for ($i = 0; $i < $args_count; $i++) { + switch ($args[$i]) { + case '-type': + if (in_array($args[$i+1], array('d', 'f'))) { + if ($args[$i+1] == 'd') { + $do_files = false; + } else { + $do_dirs = false; + } + } + $i++; + break; + case '-name': + $name = preg_quote($args[$i+1], '#'); + // our magic characters ? and * have just been escaped, + // so now we change the escaped versions to PCRE operators + $name = strtr($name, array('\?' => '.', '\*' => '.*')); + $patterns[] = '('.$name.')'; + $i++; + break; + case '-maxdepth': + $depth = $args[$i+1]; + break; + } + } + $path = System::_dirToStruct($dir, $depth, 0, true); + if ($do_files && $do_dirs) { + $files = array_merge($path['files'], $path['dirs']); + } elseif ($do_dirs) { + $files = $path['dirs']; + } else { + $files = $path['files']; + } + if (count($patterns)) { + $dsq = preg_quote(DIRECTORY_SEPARATOR, '#'); + $pattern = '#(^|'.$dsq.')'.implode('|', $patterns).'($|'.$dsq.')#'; + $ret = array(); + $files_count = count($files); + for ($i = 0; $i < $files_count; $i++) { + // only search in the part of the file below the current directory + $filepart = basename($files[$i]); + if (preg_match($pattern, $filepart)) { + $ret[] = $files[$i]; + } + } + return $ret; + } + return $files; + } +}PEAR-1.9.0/template.spec100664 764 764 3725 100664 10004 Summary: PEAR: @summary@ +Name: @rpm_package@ +Version: @version@ +Release: 1 +License: @release_license@ +Group: Development/Libraries +Source: http://@master_server@/get/@package@-%{version}.tgz +BuildRoot: %{_tmppath}/%{name}-root +URL: http://@master_server@/package/@package@ +Prefix: %{_prefix} +BuildArchitectures: @arch@ +@extra_headers@ + +%description +@description@ + +%prep +rm -rf %{buildroot}/* +%setup -c -T +# XXX Source files location is missing here in pear cmd +pear -v -c %{buildroot}/pearrc \ + -d php_dir=%{_libdir}/php/pear \ + -d doc_dir=/docs \ + -d bin_dir=%{_bindir} \ + -d data_dir=%{_libdir}/php/pear/data \ + -d test_dir=%{_libdir}/php/pear/tests \ + -d ext_dir=%{_libdir} \@extra_config@ + -s + +%build +echo BuildRoot=%{buildroot} + +%postun +# if refcount = 0 then package has been removed (not upgraded) +if [ "$1" -eq "0" ]; then + pear uninstall --nodeps -r @possible_channel@@package@ + rm @rpm_xml_dir@/@package@.xml +fi + + +%post +# if refcount = 2 then package has been upgraded +if [ "$1" -ge "2" ]; then + pear upgrade --nodeps -r @rpm_xml_dir@/@package@.xml +else + pear install --nodeps -r @rpm_xml_dir@/@package@.xml +fi + +%install +pear -c %{buildroot}/pearrc install --nodeps -R %{buildroot} \ + $RPM_SOURCE_DIR/@package@-%{version}.tgz +rm %{buildroot}/pearrc +rm %{buildroot}/%{_libdir}/php/pear/.filemap +rm %{buildroot}/%{_libdir}/php/pear/.lock +rm -rf %{buildroot}/%{_libdir}/php/pear/.registry +if [ "@doc_files@" != "" ]; then + mv %{buildroot}/docs/@package@/* . + rm -rf %{buildroot}/docs +fi +mkdir -p %{buildroot}@rpm_xml_dir@ +tar -xzf $RPM_SOURCE_DIR/@package@-%{version}.tgz package@package2xml@.xml +cp -p package@package2xml@.xml %{buildroot}@rpm_xml_dir@/@package@.xml + +#rm -rf %{buildroot}/* +#pear -q install -R %{buildroot} -n package@package2xml@.xml +#mkdir -p %{buildroot}@rpm_xml_dir@ +#cp -p package@package2xml@.xml %{buildroot}@rpm_xml_dir@/@package@.xml + +%files + %defattr(-,root,root) + %doc @doc_files@ + / +package.xml100664 764 764 76000 100664 6254 + + + PEAR + PEAR Base System + The PEAR package contains: + * the PEAR installer, for creating, distributing + and installing packages + * the PEAR_Exception PHP5 error handling mechanism + * the PEAR_ErrorStack advanced error handling mechanism + * the PEAR_Error error handling mechanism * the OS_Guess class for retrieving info about the OS where PHP is running on * the System class for quick handling of common operations with files and directories * the PEAR base class - Features in a nutshell: - * full support for channels - * pre-download dependency validation - * new package.xml 2.0 format allows tremendous flexibility while maintaining BC - * support for optional dependency groups and limited support for sub-packaging - * robust dependency support - * full dependency validation on uninstall - * remote install for hosts with only ftp access - no more problems with - restricted host installation - * full support for mirroring - * support for bundling several packages into a single tarball - * support for static dependencies on a url-based package - * support for custom file roles and installation tasks - - - - cellog - Greg Beaver - cellog@php.net - lead - - - pajoye - Pierre-Alain Joye - pierre@php.net - lead - - - ssb - Stig Bakken - stig@php.net - lead - - - cox - Tomas V.V.Cox - cox@idecnet.com - lead - - - dufuz - Helgi Thormar - dufuz@php.net - lead - - - tias - Tias Guns - tias@php.net - developer - - - timj - Tim Jackson - timj@php.net - helper - - - toggg - Bertrand Gugger - toggg@php.net - helper - - - mj - Martin Jansen - mj@php.net - helper - - - - 1.8.0 - 2009-04-10 - New BSD License - stable - * Fix Bug #14792: Bad md5sum for files with replaced content [dufuz] -* Fix Bug #16057:-r is limited to 4 directories in depth [dufuz] -* Fix Bug #16077: PEAR5::getStaticProperty does not return a reference to the property [dufuz] -Remove custom XML_Util class in favor of using upstream XML_Util package as dependency - - - - PEAR - Archive_Tar - Console_Getopt - Structures_Graph - PEAR_Frontend_Web - PEAR_Frontend_Gtk - xml - pcre - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1.8.0alpha1 - 2009-03-09 - New BSD License - alpha - * Implement Request #10373: if pref_state=stable and installed package=beta, allow up to latest beta version [dufuz] -* Implement Request #10581: login / logout should map to channel-login / channel-logout [dufuz] -* Implement Request #10825: Only display the "invalid or missing package file"-error if it makes sense [dufuz] -* Implement Request #11170: script to generate Command/[command].xml [dufuz] -* Implement Request #11176: improve channel ... has updated its protocols message [dufuz] -* Implement Request #12706: pear list -a hard to read [dufuz] -* Implement Request #11353: upgrade-all and upgrade commands to upgrade within the same stability level [dufuz] -* Implement Request #13015: Add https discovery for channel.xml [dufuz / initial patch by Martin Roos] -* Implement Request #13927: install-pear.php should have option to set www_dir [timj] -* Implement Request #14324: Make the pear install command behave similar to apt-get [dufuz] -* Implement Request #14325: make pear upgrade with no params behave like pear upgrade-all [dufuz] - - upgrade-all can be considered deprecated in favor of calling upgrade with no parameters to replicate - better what other package managers are doing. upgrade-all will still work as intended. -* Implement Request #14504: add a channel parameter support to the upgrade function [dufuz] - - Options -c ezc and --channel=ezc got added to upgrade and upgrade-all to allow for - channel specific upgrades -* Implement Request #14556: install-pear-nozlib.phar should get download_dir config and other options [cweiske] -* Implement Request #15566: Add doc.php.net as a default channel [dufuz / saltybeagle] -* Fix PHP Bug #43857: --program-suffix not always reflected everywhere [cellog] -* Fix PHP Bug #47323: strotime warnings in make install [dufuz] -* Fix Bug #13908: pear info command and maintainers inactive not mentioned [dufuz] -* Fix Bug #13926: install-pear.php does not set cfg_dir if -d option set with no -c option [timj] -* Fix Bug #13943: tests fail when php.exe path contains spaces [dufuz / jorrit] -* Fix Bug #13953: config-set/config-show with channel alias fail [cellog] -* Fix Bug #13958: When a phpt tests exit() or die() xdebug coverage is not generated, patch by izi (David Jean Louis) [izi / dufuz] -* Fix Bug #14041: Unpredictable unit test processing sequence [dufuz] -* Fix Bug #14140: Strict warning not suppressed in the shutdown function [dufuz] -* Fix Bug #14210: pear list -ia brings warnings [dufuz] -* Fix Bug #14274: PEAR packager mangles package.xml encoding, then complains about it [dufuz] -* Fix Bug #14287: cannot upgrade from stable to beta via -beta when config is set to stable [dufuz] -* Fix Bug #14300: Package files themselves can not be served over https [dufuz / initial patch by Martin Roos] -* Fix Bug #14437: openbasedir warning when loading config [dufuz] -* Fix Bug #14558: PackageFile.php creates tmp directory outside configured temp_dir [cweiske] -* Fix Bug #14947: downloadHttp() is missing Host part of the HTTP Request when using Proxy [ifeghali] -* Fix Bug #14977: PEAR/Frontend.php doesn't require_once PEAR.php [dufuz] -* Fix Bug #15750: Unreachable code in PEAR_Downloader [dufuz] -* Fix Bug #15979: Package files incorrectly removed when splitting a package into multiple pkgs [dufuz] -* Fix Bug #15914: pear upgrade installs different version if desired version not found [dufuz] -NOTE! -Functions that have been deprecated for 3+ years in PEAR_Common, please take a moment -to migrate over to one of the alternatives that have ben provided: -* PEAR_Common->downloadHttp (use PEAR_Downloader->downloadHttp instead) -* PEAR_Common->infoFromTgzFile (use PEAR_PackageFile->fromTgzFile instead) -* PEAR_Common->infoFromDescriptionFile (use PEAR_PackageFile->fromPackageFile instead) -* PEAR_Common->infoFromString (use PEAR_PackageFile->fromXmlstring instead) -* PEAR_Common->infoFromArray (use PEAR_PackageFile->fromAnyFile instead) -* PEAR_Common->xmlFromInfo (use a PEAR_PackageFile_v* object's generator instead) -* PEAR_Common->validatePackageInfo (use the validation of PEAR_PackageFile objects) -* PEAR_Common->analyzeSourceCode (use a PEAR_PackageFile_v* object instead) -* PEAR_Common->detectDependencies (use PEAR_Downloader_Package->detectDependencies instead) -* PEAR_Common->buildProvidesArray (use PEAR_PackageFile_v1->_buildProvidesArray or - PEAR_PackageFile_v2_Validator->_buildProvidesArray) -PHP 4.4 and 5.1.6 are now the minimum PHP requirements, for brave souls -pear upgrade -f PEAR will allow people with lower versions -to upgrade to this release but no guarantees will be made that it will work properly. -Support for XML RPC channels has been dropped - The only ones that used it -(pear.php.net and pecl.php.net) have used the REST interface for years now. -SOAP support also removed as it was only proof of concept. -Move codebase from the PHP License to New BSD 2 clause license - - - - 1.8.0RC1 - 2009-03-27 - New BSD License - beta - * Fix Bug #14331: pear cvstag only works from inside the package directory [dufuz] -* Fix Bug #16045: E_Notice: Undefined index: channel in PEAR/DependencyDB.php [dufuz] -* Implemented Request #11230: better error message when mirror not in channel.xml file [dufuz] -* Implemented Request #13150: Add support for following HTTP 302 redirects [dufuz] - - - - - - New BSD License - Changes since RC1: - * Fix Bug #14792: Bad md5sum for files with replaced content [dufuz] - * Fix Bug #16057:-r is limited to 4 directories in depth [dufuz] - * Fix Bug #16077: PEAR5::getStaticProperty does not return a reference to the property [dufuz] + Features in a nutshell: + * full support for channels + * pre-download dependency validation + * new package.xml 2.0 format allows tremendous flexibility while maintaining BC + * support for optional dependency groups and limited support for sub-packaging + * robust dependency support + * full dependency validation on uninstall + * remote install for hosts with only ftp access - no more problems with + restricted host installation + * full support for mirroring + * support for bundling several packages into a single tarball + * support for static dependencies on a url-based package + * support for custom file roles and installation tasks + + + + cellog + Greg Beaver + cellog@php.net + lead + + + pajoye + Pierre-Alain Joye + pierre@php.net + lead + + + ssb + Stig Bakken + stig@php.net + lead + + + cox + Tomas V.V.Cox + cox@idecnet.com + lead + + + dufuz + Helgi Thormar + dufuz@php.net + lead + + + tias + Tias Guns + tias@php.net + developer + + + timj + Tim Jackson + timj@php.net + helper + + + toggg + Bertrand Gugger + toggg@php.net + helper + + + mj + Martin Jansen + mj@php.net + helper + + + + 1.9.0 + 2009-09-03 + New BSD License + stable + * Fix Bug #16547: The phar for PEAR installer uses ereg() which is deprecated [dufuz] + + + + PEAR + Archive_Tar + Console_Getopt + Structures_Graph + PEAR_Frontend_Web + PEAR_Frontend_Gtk + xml + pcre + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1.8.0alpha1 + 2009-03-09 + New BSD License + alpha + * Implement Request #10373: if pref_state=stable and installed package=beta, allow up to latest beta version [dufuz] +* Implement Request #10581: login / logout should map to channel-login / channel-logout [dufuz] +* Implement Request #10825: Only display the "invalid or missing package file"-error if it makes sense [dufuz] +* Implement Request #11170: script to generate Command/[command].xml [dufuz] +* Implement Request #11176: improve channel ... has updated its protocols message [dufuz] +* Implement Request #12706: pear list -a hard to read [dufuz] +* Implement Request #11353: upgrade-all and upgrade commands to upgrade within the same stability level [dufuz] +* Implement Request #13015: Add https discovery for channel.xml [dufuz / initial patch by Martin Roos] +* Implement Request #13927: install-pear.php should have option to set www_dir [timj] +* Implement Request #14324: Make the pear install command behave similar to apt-get [dufuz] +* Implement Request #14325: make pear upgrade with no params behave like pear upgrade-all [dufuz] + - upgrade-all can be considered deprecated in favor of calling upgrade with no parameters to replicate + better what other package managers are doing. upgrade-all will still work as intended. +* Implement Request #14504: add a channel parameter support to the upgrade function [dufuz] + - Options -c ezc and --channel=ezc got added to upgrade and upgrade-all to allow for + channel specific upgrades +* Implement Request #14556: install-pear-nozlib.phar should get download_dir config and other options [cweiske] +* Implement Request #15566: Add doc.php.net as a default channel [dufuz / saltybeagle] +* Fix PHP Bug #43857: --program-suffix not always reflected everywhere [cellog] +* Fix PHP Bug #47323: strotime warnings in make install [dufuz] +* Fix Bug #13908: pear info command and maintainers inactive not mentioned [dufuz] +* Fix Bug #13926: install-pear.php does not set cfg_dir if -d option set with no -c option [timj] +* Fix Bug #13943: tests fail when php.exe path contains spaces [dufuz / jorrit] +* Fix Bug #13953: config-set/config-show with channel alias fail [cellog] +* Fix Bug #13958: When a phpt tests exit() or die() xdebug coverage is not generated, patch by izi (David Jean Louis) [izi / dufuz] +* Fix Bug #14041: Unpredictable unit test processing sequence [dufuz] +* Fix Bug #14140: Strict warning not suppressed in the shutdown function [dufuz] +* Fix Bug #14210: pear list -ia brings warnings [dufuz] +* Fix Bug #14274: PEAR packager mangles package.xml encoding, then complains about it [dufuz] +* Fix Bug #14287: cannot upgrade from stable to beta via -beta when config is set to stable [dufuz] +* Fix Bug #14300: Package files themselves can not be served over https [dufuz / initial patch by Martin Roos] +* Fix Bug #14437: openbasedir warning when loading config [dufuz] +* Fix Bug #14558: PackageFile.php creates tmp directory outside configured temp_dir [cweiske] +* Fix Bug #14947: downloadHttp() is missing Host part of the HTTP Request when using Proxy [ifeghali] +* Fix Bug #14977: PEAR/Frontend.php doesn't require_once PEAR.php [dufuz] +* Fix Bug #15750: Unreachable code in PEAR_Downloader [dufuz] +* Fix Bug #15979: Package files incorrectly removed when splitting a package into multiple pkgs [dufuz] +* Fix Bug #15914: pear upgrade installs different version if desired version not found [dufuz] +NOTE! +Functions that have been deprecated for 3+ years in PEAR_Common, please take a moment +to migrate over to one of the alternatives that have ben provided: +* PEAR_Common->downloadHttp (use PEAR_Downloader->downloadHttp instead) +* PEAR_Common->infoFromTgzFile (use PEAR_PackageFile->fromTgzFile instead) +* PEAR_Common->infoFromDescriptionFile (use PEAR_PackageFile->fromPackageFile instead) +* PEAR_Common->infoFromString (use PEAR_PackageFile->fromXmlstring instead) +* PEAR_Common->infoFromArray (use PEAR_PackageFile->fromAnyFile instead) +* PEAR_Common->xmlFromInfo (use a PEAR_PackageFile_v* object's generator instead) +* PEAR_Common->validatePackageInfo (use the validation of PEAR_PackageFile objects) +* PEAR_Common->analyzeSourceCode (use a PEAR_PackageFile_v* object instead) +* PEAR_Common->detectDependencies (use PEAR_Downloader_Package->detectDependencies instead) +* PEAR_Common->buildProvidesArray (use PEAR_PackageFile_v1->_buildProvidesArray or + PEAR_PackageFile_v2_Validator->_buildProvidesArray) +PHP 4.4 and 5.1.6 are now the minimum PHP requirements, for brave souls +pear upgrade -f PEAR will allow people with lower versions +to upgrade to this release but no guarantees will be made that it will work properly. +Support for XML RPC channels has been dropped - The only ones that used it +(pear.php.net and pecl.php.net) have used the REST interface for years now. +SOAP support also removed as it was only proof of concept. +Move codebase from the PHP License to New BSD 2 clause license + + + + 1.8.0RC1 + 2009-03-27 + New BSD License + beta + * Fix Bug #14331: pear cvstag only works from inside the package directory [dufuz] +* Fix Bug #16045: E_Notice: Undefined index: channel in PEAR/DependencyDB.php [dufuz] +* Implemented Request #11230: better error message when mirror not in channel.xml file [dufuz] +* Implemented Request #13150: Add support for following HTTP 302 redirects [dufuz] + + + + + + New BSD License + Changes since RC1: + * Fix Bug #14792: Bad md5sum for files with replaced content [dufuz] + * Fix Bug #16057:-r is limited to 4 directories in depth [dufuz] + * Fix Bug #16077: PEAR5::getStaticProperty does not return a reference to the property [dufuz] + + Remove custom XML_Util class in favor of using upstream XML_Util package as dependency + +RC1 Release Notes: + * Fix Bug #14331: pear cvstag only works from inside the package directory [dufuz] + * Fix Bug #16045: E_Notice: Undefined index: channel in PEAR/DependencyDB.php [dufuz] + + * Implemented Request #11230: better error message when mirror not in channel.xml file [dufuz] + * Implemented Request #13150: Add support for following HTTP 302 redirects [dufuz] + +Alpha1 Release Notes: + * Implement Request #10373: if pref_state=stable and installed package=beta, allow up to latest beta version [dufuz] + * Implement Request #10581: login / logout should map to channel-login / channel-logout [dufuz] + * Implement Request #10825: Only display the "invalid or missing package file"-error if it makes sense [dufuz] + * Implement Request #11170: script to generate Command/[command].xml [dufuz] + * Implement Request #11176: improve channel ... has updated its protocols message [dufuz] + * Implement Request #12706: pear list -a hard to read [dufuz] + * Implement Request #11353: upgrade-all and upgrade commands to upgrade within the same stability level [dufuz] + * Implement Request #13015: Add https discovery for channel.xml [dufuz / initial patch by Martin Roos] + * Implement Request #13927: install-pear.php should have option to set www_dir [timj] + * Implement Request #14324: Make the pear install command behave similar to apt-get [dufuz] + * Implement Request #14325: make pear upgrade with no params behave like pear upgrade-all [dufuz] + - upgrade-all can be considered deprecated in favor of calling upgrade with no parameters to replicate + better what other package managers are doing. upgrade-all will still work as intended. + * Implement Request #14504: add a channel parameter support to the upgrade function [dufuz] + - Options -c ezc and --channel=ezc got added to upgrade and upgrade-all to allow for + channel specific upgrades + * Implement Request #14556: install-pear-nozlib.phar should get download_dir config and other options [cweiske] + * Implement Request #15566: Add doc.php.net as a default channel [dufuz / saltybeagle] + + * Fix PHP Bug #43857: --program-suffix not always reflected everywhere [cellog] + * Fix PHP Bug #47323: strotime warnings in make install [dufuz] + + * Fix Bug #13908: pear info command and maintainers inactive not mentioned [dufuz] + * Fix Bug #13926: install-pear.php does not set cfg_dir if -d option set with no -c option [timj] + * Fix Bug #13943: tests fail when php.exe path contains spaces [dufuz / jorrit] + * Fix Bug #13953: config-set/config-show with channel alias fail [cellog] + * Fix Bug #13958: When a phpt tests exit() or die() xdebug coverage is not generated, patch by izi (David Jean Louis) [izi / dufuz] + * Fix Bug #14041: Unpredictable unit test processing sequence [dufuz] + * Fix Bug #14140: Strict warning not suppressed in the shutdown function [dufuz] + * Fix Bug #14210: pear list -ia brings warnings [dufuz] + * Fix Bug #14274: PEAR packager mangles package.xml encoding, then complains about it [dufuz] + * Fix Bug #14287: cannot upgrade from stable to beta via -beta when config is set to stable [dufuz] + * Fix Bug #14300: Package files themselves can not be served over https [dufuz / initial patch by Martin Roos] + * Fix Bug #14437: openbasedir warning when loading config [dufuz] + * Fix Bug #14558: PackageFile.php creates tmp directory outside configured temp_dir [cweiske] + * Fix Bug #14947: downloadHttp() is missing Host part of the HTTP Request when using Proxy [ifeghali] + * Fix Bug #14977: PEAR/Frontend.php doesn't require_once PEAR.php [dufuz] + * Fix Bug #15750: Unreachable code in PEAR_Downloader [dufuz] + * Fix Bug #15979: Package files incorrectly removed when splitting a package into multiple pkgs [dufuz] + * Fix Bug #15914: pear upgrade installs different version if desired version not found [dufuz] + + NOTE! + Functions that have been deprecated for 3+ years in PEAR_Common, please take a moment + to migrate over to one of the alternatives that have ben provided: + * PEAR_Common->downloadHttp (use PEAR_Downloader->downloadHttp instead) + * PEAR_Common->infoFromTgzFile (use PEAR_PackageFile->fromTgzFile instead) + * PEAR_Common->infoFromDescriptionFile (use PEAR_PackageFile->fromPackageFile instead) + * PEAR_Common->infoFromString (use PEAR_PackageFile->fromXmlstring instead) + * PEAR_Common->infoFromArray (use PEAR_PackageFile->fromAnyFile instead) + * PEAR_Common->xmlFromInfo (use a PEAR_PackageFile_v* object's generator instead) + * PEAR_Common->validatePackageInfo (use the validation of PEAR_PackageFile objects) + * PEAR_Common->analyzeSourceCode (use a PEAR_PackageFile_v* object instead) + * PEAR_Common->detectDependencies (use PEAR_Downloader_Package->detectDependencies instead) + * PEAR_Common->buildProvidesArray (use PEAR_PackageFile_v1->_buildProvidesArray or + PEAR_PackageFile_v2_Validator->_buildProvidesArray) + + PHP 4.4 and 5.1.6 are now the minimum PHP requirements, for brave souls + pear upgrade -f PEAR will allow people with lower versions + to upgrade to this release but no guarantees will be made that it will work properly. + + Support for XML RPC channels has been dropped - The only ones that used it + (pear.php.net and pecl.php.net) have used the REST interface for years now. + SOAP support also removed as it was only proof of concept. + + Move codebase from the PHP License to New BSD 2 clause license + + + + 1.8.1 + 2009-04-15 + New BSD License + stable + * Fix Bug #16099 PEAR crash on PHP4 (parse error) [dufuz] + + + + 1.9.0RC1 + 2009-08-18 + New BSD License + beta + * Implement Request #16213: add alias to list-channels output [dufuz] +* Implement Request #16378: pear svntag [dufuz] +* Implement Request #16386: PEAR_Config::remove() does not support specifying a channel [timj] +* Implement Request #16396: package-dependencies should allow package names [dufuz] +* Fix Bug #11181: pear requests channel.xml from main server instead from mirror [dufuz] +* Fix Bug #14493: pear install --offline doesn't print out errors [dufuz] +* Fix Bug #11348: pear package-dependencies isn't well explained [dufuz] +* Fix Bug #16108: PEAR_PackageFile_Generator_v2 PHP4 parse error when running upgrade-all [dufuz] +* Fix Bug #16113: Installing certain packages fails due incorrect encoding handling [dufuz] +* Fix Bug #16122: PEAR RunTest failed to run as expected [dufuz] +* Fix Bug #16366: compiling 5.2.10 leads to non-functioning pear [dufuz] +* Fix Bug #16387: channel-logout does not support logging out from a non-default channel [timj] +* Fix Bug #16444: Setting preferred mirror fails [dufuz] +* Fix the shutdown functions where a index might not exist and thus raise a notice [derick] + + + + 1.9.0RC2 + 2009-08-20 + New BSD License + beta + * REST 1.4 file was occasionally being included but REST 1.4 is not intended for this release cycle [dufuz] + + + + 1.9.0RC3 + 2009-08-21 + New BSD License + beta + * Improved svntag support to handle packages like PEAR it self [dufuz] + + + + 1.9.0RC4 + 2009-08-23 + New BSD License + beta + * Fixed a problem where the original channel could not be set as a preferred_mirror again [dufuz] +* Make sure channel aliases can't be made to start with - [dufuz] +* Output issues with pear search [dufuz] +* Fixed couple of stray notices [dufuz] + + + + 1.9.0 + 2009-09-03 + New BSD License + stable + * Fix Bug #16547: The phar for PEAR installer uses ereg() which is deprecated [dufuz] + + + + + + * @author Stig Bakken + * @author Tomas V.V.Cox + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: PEAR.php 286670 2009-08-02 14:16:06Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/**#@+ + * ERROR constants + */ +define('PEAR_ERROR_RETURN', 1); +define('PEAR_ERROR_PRINT', 2); +define('PEAR_ERROR_TRIGGER', 4); +define('PEAR_ERROR_DIE', 8); +define('PEAR_ERROR_CALLBACK', 16); +/** + * WARNING: obsolete + * @deprecated + */ +define('PEAR_ERROR_EXCEPTION', 32); +/**#@-*/ +define('PEAR_ZE2', (function_exists('version_compare') && + version_compare(zend_version(), "2-dev", "ge"))); + +if (substr(PHP_OS, 0, 3) == 'WIN') { + define('OS_WINDOWS', true); + define('OS_UNIX', false); + define('PEAR_OS', 'Windows'); +} else { + define('OS_WINDOWS', false); + define('OS_UNIX', true); + define('PEAR_OS', 'Unix'); // blatant assumption +} + +$GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_RETURN; +$GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE; +$GLOBALS['_PEAR_destructor_object_list'] = array(); +$GLOBALS['_PEAR_shutdown_funcs'] = array(); +$GLOBALS['_PEAR_error_handler_stack'] = array(); + +@ini_set('track_errors', true); + +/** + * Base class for other PEAR classes. Provides rudimentary + * emulation of destructors. + * + * If you want a destructor in your class, inherit PEAR and make a + * destructor method called _yourclassname (same name as the + * constructor, but with a "_" prefix). Also, in your constructor you + * have to call the PEAR constructor: $this->PEAR();. + * The destructor method will be called without parameters. Note that + * at in some SAPI implementations (such as Apache), any output during + * the request shutdown (in which destructors are called) seems to be + * discarded. If you need to get any debug information from your + * destructor, use error_log(), syslog() or something similar. + * + * IMPORTANT! To use the emulated destructors you need to create the + * objects by reference: $obj =& new PEAR_child; + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Tomas V.V. Cox + * @author Greg Beaver + * @copyright 1997-2006 The PHP Group + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @see PEAR_Error + * @since Class available since PHP 4.0.2 + * @link http://pear.php.net/manual/en/core.pear.php#core.pear.pear + */ +class PEAR +{ + // {{{ properties + + /** + * Whether to enable internal debug messages. + * + * @var bool + * @access private + */ + var $_debug = false; + + /** + * Default error mode for this object. + * + * @var int + * @access private + */ + var $_default_error_mode = null; + + /** + * Default error options used for this object when error mode + * is PEAR_ERROR_TRIGGER. + * + * @var int + * @access private + */ + var $_default_error_options = null; + + /** + * Default error handler (callback) for this object, if error mode is + * PEAR_ERROR_CALLBACK. + * + * @var string + * @access private + */ + var $_default_error_handler = ''; + + /** + * Which class to use for error objects. + * + * @var string + * @access private + */ + var $_error_class = 'PEAR_Error'; + + /** + * An array of expected errors. + * + * @var array + * @access private + */ + var $_expected_errors = array(); + + // }}} + + // {{{ constructor + + /** + * Constructor. Registers this object in + * $_PEAR_destructor_object_list for destructor emulation if a + * destructor object exists. + * + * @param string $error_class (optional) which class to use for + * error objects, defaults to PEAR_Error. + * @access public + * @return void + */ + function PEAR($error_class = null) + { + $classname = strtolower(get_class($this)); + if ($this->_debug) { + print "PEAR constructor called, class=$classname\n"; + } + if ($error_class !== null) { + $this->_error_class = $error_class; + } + while ($classname && strcasecmp($classname, "pear")) { + $destructor = "_$classname"; + if (method_exists($this, $destructor)) { + global $_PEAR_destructor_object_list; + $_PEAR_destructor_object_list[] = &$this; + if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { + register_shutdown_function("_PEAR_call_destructors"); + $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; + } + break; + } else { + $classname = get_parent_class($classname); + } + } + } + + // }}} + // {{{ destructor + + /** + * Destructor (the emulated type of...). Does nothing right now, + * but is included for forward compatibility, so subclass + * destructors should always call it. + * + * See the note in the class desciption about output from + * destructors. + * + * @access public + * @return void + */ + function _PEAR() { + if ($this->_debug) { + printf("PEAR destructor called, class=%s\n", strtolower(get_class($this))); + } + } + + // }}} + // {{{ getStaticProperty() + + /** + * If you have a class that's mostly/entirely static, and you need static + * properties, you can use this method to simulate them. Eg. in your method(s) + * do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar'); + * You MUST use a reference, or they will not persist! + * + * @access public + * @param string $class The calling classname, to prevent clashes + * @param string $var The variable to retrieve. + * @return mixed A reference to the variable. If not set it will be + * auto initialised to NULL. + */ + function &getStaticProperty($class, $var) + { + static $properties; + if (!isset($properties[$class])) { + $properties[$class] = array(); + } + + if (!array_key_exists($var, $properties[$class])) { + $properties[$class][$var] = null; + } + + return $properties[$class][$var]; + } + + // }}} + // {{{ registerShutdownFunc() + + /** + * Use this function to register a shutdown method for static + * classes. + * + * @access public + * @param mixed $func The function name (or array of class/method) to call + * @param mixed $args The arguments to pass to the function + * @return void + */ + function registerShutdownFunc($func, $args = array()) + { + // if we are called statically, there is a potential + // that no shutdown func is registered. Bug #6445 + if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { + register_shutdown_function("_PEAR_call_destructors"); + $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; + } + $GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args); + } + + // }}} + // {{{ isError() + + /** + * Tell whether a value is a PEAR error. + * + * @param mixed $data the value to test + * @param int $code if $data is an error object, return true + * only if $code is a string and + * $obj->getMessage() == $code or + * $code is an integer and $obj->getCode() == $code + * @access public + * @return bool true if parameter is an error + */ + function isError($data, $code = null) + { + if (!is_a($data, 'PEAR_Error')) { + return false; + } + + if (is_null($code)) { + return true; + } elseif (is_string($code)) { + return $data->getMessage() == $code; + } + + return $data->getCode() == $code; + } + + // }}} + // {{{ setErrorHandling() + + /** + * Sets how errors generated by this object should be handled. + * Can be invoked both in objects and statically. If called + * statically, setErrorHandling sets the default behaviour for all + * PEAR objects. If called in an object, setErrorHandling sets + * the default behaviour for that object. + * + * @param int $mode + * One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, + * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, + * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION. + * + * @param mixed $options + * When $mode is PEAR_ERROR_TRIGGER, this is the error level (one + * of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). + * + * When $mode is PEAR_ERROR_CALLBACK, this parameter is expected + * to be the callback function or method. A callback + * function is a string with the name of the function, a + * callback method is an array of two elements: the element + * at index 0 is the object, and the element at index 1 is + * the name of the method to call in the object. + * + * When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is + * a printf format string used when printing the error + * message. + * + * @access public + * @return void + * @see PEAR_ERROR_RETURN + * @see PEAR_ERROR_PRINT + * @see PEAR_ERROR_TRIGGER + * @see PEAR_ERROR_DIE + * @see PEAR_ERROR_CALLBACK + * @see PEAR_ERROR_EXCEPTION + * + * @since PHP 4.0.5 + */ + + function setErrorHandling($mode = null, $options = null) + { + if (isset($this) && is_a($this, 'PEAR')) { + $setmode = &$this->_default_error_mode; + $setoptions = &$this->_default_error_options; + } else { + $setmode = &$GLOBALS['_PEAR_default_error_mode']; + $setoptions = &$GLOBALS['_PEAR_default_error_options']; + } + + switch ($mode) { + case PEAR_ERROR_EXCEPTION: + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $setmode = $mode; + $setoptions = $options; + break; + + case PEAR_ERROR_CALLBACK: + $setmode = $mode; + // class/object method callback + if (is_callable($options)) { + $setoptions = $options; + } else { + trigger_error("invalid error callback", E_USER_WARNING); + } + break; + + default: + trigger_error("invalid error mode", E_USER_WARNING); + break; + } + } + + // }}} + // {{{ expectError() + + /** + * This method is used to tell which errors you expect to get. + * Expected errors are always returned with error mode + * PEAR_ERROR_RETURN. Expected error codes are stored in a stack, + * and this method pushes a new element onto it. The list of + * expected errors are in effect until they are popped off the + * stack with the popExpect() method. + * + * Note that this method can not be called statically + * + * @param mixed $code a single error code or an array of error codes to expect + * + * @return int the new depth of the "expected errors" stack + * @access public + */ + function expectError($code = '*') + { + if (is_array($code)) { + array_push($this->_expected_errors, $code); + } else { + array_push($this->_expected_errors, array($code)); + } + return sizeof($this->_expected_errors); + } + + // }}} + // {{{ popExpect() + + /** + * This method pops one element off the expected error codes + * stack. + * + * @return array the list of error codes that were popped + */ + function popExpect() + { + return array_pop($this->_expected_errors); + } + + // }}} + // {{{ _checkDelExpect() + + /** + * This method checks unsets an error code if available + * + * @param mixed error code + * @return bool true if the error code was unset, false otherwise + * @access private + * @since PHP 4.3.0 + */ + function _checkDelExpect($error_code) + { + $deleted = false; + + foreach ($this->_expected_errors AS $key => $error_array) { + if (in_array($error_code, $error_array)) { + unset($this->_expected_errors[$key][array_search($error_code, $error_array)]); + $deleted = true; + } + + // clean up empty arrays + if (0 == count($this->_expected_errors[$key])) { + unset($this->_expected_errors[$key]); + } + } + return $deleted; + } + + // }}} + // {{{ delExpect() + + /** + * This method deletes all occurences of the specified element from + * the expected error codes stack. + * + * @param mixed $error_code error code that should be deleted + * @return mixed list of error codes that were deleted or error + * @access public + * @since PHP 4.3.0 + */ + function delExpect($error_code) + { + $deleted = false; + if ((is_array($error_code) && (0 != count($error_code)))) { + // $error_code is a non-empty array here; + // we walk through it trying to unset all + // values + foreach($error_code as $key => $error) { + if ($this->_checkDelExpect($error)) { + $deleted = true; + } else { + $deleted = false; + } + } + return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME + } elseif (!empty($error_code)) { + // $error_code comes alone, trying to unset it + if ($this->_checkDelExpect($error_code)) { + return true; + } else { + return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME + } + } + + // $error_code is empty + return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME + } + + // }}} + // {{{ raiseError() + + /** + * This method is a wrapper that returns an instance of the + * configured error class with this object's default error + * handling applied. If the $mode and $options parameters are not + * specified, the object's defaults are used. + * + * @param mixed $message a text error message or a PEAR error object + * + * @param int $code a numeric error code (it is up to your class + * to define these if you want to use codes) + * + * @param int $mode One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, + * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, + * PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION. + * + * @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter + * specifies the PHP-internal error level (one of + * E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). + * If $mode is PEAR_ERROR_CALLBACK, this + * parameter specifies the callback function or + * method. In other error modes this parameter + * is ignored. + * + * @param string $userinfo If you need to pass along for example debug + * information, this parameter is meant for that. + * + * @param string $error_class The returned error object will be + * instantiated from this class, if specified. + * + * @param bool $skipmsg If true, raiseError will only pass error codes, + * the error message parameter will be dropped. + * + * @access public + * @return object a PEAR error object + * @see PEAR::setErrorHandling + * @since PHP 4.0.5 + */ + function &raiseError($message = null, + $code = null, + $mode = null, + $options = null, + $userinfo = null, + $error_class = null, + $skipmsg = false) + { + // The error is yet a PEAR error object + if (is_object($message)) { + $code = $message->getCode(); + $userinfo = $message->getUserInfo(); + $error_class = $message->getType(); + $message->error_message_prefix = ''; + $message = $message->getMessage(); + } + + if (isset($this) && isset($this->_expected_errors) && sizeof($this->_expected_errors) > 0 && sizeof($exp = end($this->_expected_errors))) { + if ($exp[0] == "*" || + (is_int(reset($exp)) && in_array($code, $exp)) || + (is_string(reset($exp)) && in_array($message, $exp))) { + $mode = PEAR_ERROR_RETURN; + } + } + + // No mode given, try global ones + if ($mode === null) { + // Class error handler + if (isset($this) && isset($this->_default_error_mode)) { + $mode = $this->_default_error_mode; + $options = $this->_default_error_options; + // Global error handler + } elseif (isset($GLOBALS['_PEAR_default_error_mode'])) { + $mode = $GLOBALS['_PEAR_default_error_mode']; + $options = $GLOBALS['_PEAR_default_error_options']; + } + } + + if ($error_class !== null) { + $ec = $error_class; + } elseif (isset($this) && isset($this->_error_class)) { + $ec = $this->_error_class; + } else { + $ec = 'PEAR_Error'; + } + + if (intval(PHP_VERSION) < 5) { + // little non-eval hack to fix bug #12147 + include 'phar://install-pear-nozlib.phar/' . 'PEAR/FixPHP5PEARWarnings.php'; + return $a; + } + + if ($skipmsg) { + $a = new $ec($code, $mode, $options, $userinfo); + } else { + $a = new $ec($message, $code, $mode, $options, $userinfo); + } + + return $a; + } + + // }}} + // {{{ throwError() + + /** + * Simpler form of raiseError with fewer options. In most cases + * message, code and userinfo are enough. + * + * @param string $message + * + */ + function &throwError($message = null, + $code = null, + $userinfo = null) + { + if (isset($this) && is_a($this, 'PEAR')) { + $a = &$this->raiseError($message, $code, null, null, $userinfo); + return $a; + } + + $a = &PEAR::raiseError($message, $code, null, null, $userinfo); + return $a; + } + + // }}} + function staticPushErrorHandling($mode, $options = null) + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + $def_mode = &$GLOBALS['_PEAR_default_error_mode']; + $def_options = &$GLOBALS['_PEAR_default_error_options']; + $stack[] = array($def_mode, $def_options); + switch ($mode) { + case PEAR_ERROR_EXCEPTION: + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $def_mode = $mode; + $def_options = $options; + break; + + case PEAR_ERROR_CALLBACK: + $def_mode = $mode; + // class/object method callback + if (is_callable($options)) { + $def_options = $options; + } else { + trigger_error("invalid error callback", E_USER_WARNING); + } + break; + + default: + trigger_error("invalid error mode", E_USER_WARNING); + break; + } + $stack[] = array($mode, $options); + return true; + } + + function staticPopErrorHandling() + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + $setmode = &$GLOBALS['_PEAR_default_error_mode']; + $setoptions = &$GLOBALS['_PEAR_default_error_options']; + array_pop($stack); + list($mode, $options) = $stack[sizeof($stack) - 1]; + array_pop($stack); + switch ($mode) { + case PEAR_ERROR_EXCEPTION: + case PEAR_ERROR_RETURN: + case PEAR_ERROR_PRINT: + case PEAR_ERROR_TRIGGER: + case PEAR_ERROR_DIE: + case null: + $setmode = $mode; + $setoptions = $options; + break; + + case PEAR_ERROR_CALLBACK: + $setmode = $mode; + // class/object method callback + if (is_callable($options)) { + $setoptions = $options; + } else { + trigger_error("invalid error callback", E_USER_WARNING); + } + break; + + default: + trigger_error("invalid error mode", E_USER_WARNING); + break; + } + return true; + } + + // {{{ pushErrorHandling() + + /** + * Push a new error handler on top of the error handler options stack. With this + * you can easily override the actual error handler for some code and restore + * it later with popErrorHandling. + * + * @param mixed $mode (same as setErrorHandling) + * @param mixed $options (same as setErrorHandling) + * + * @return bool Always true + * + * @see PEAR::setErrorHandling + */ + function pushErrorHandling($mode, $options = null) + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + if (isset($this) && is_a($this, 'PEAR')) { + $def_mode = &$this->_default_error_mode; + $def_options = &$this->_default_error_options; + } else { + $def_mode = &$GLOBALS['_PEAR_default_error_mode']; + $def_options = &$GLOBALS['_PEAR_default_error_options']; + } + $stack[] = array($def_mode, $def_options); + + if (isset($this) && is_a($this, 'PEAR')) { + $this->setErrorHandling($mode, $options); + } else { + PEAR::setErrorHandling($mode, $options); + } + $stack[] = array($mode, $options); + return true; + } + + // }}} + // {{{ popErrorHandling() + + /** + * Pop the last error handler used + * + * @return bool Always true + * + * @see PEAR::pushErrorHandling + */ + function popErrorHandling() + { + $stack = &$GLOBALS['_PEAR_error_handler_stack']; + array_pop($stack); + list($mode, $options) = $stack[sizeof($stack) - 1]; + array_pop($stack); + if (isset($this) && is_a($this, 'PEAR')) { + $this->setErrorHandling($mode, $options); + } else { + PEAR::setErrorHandling($mode, $options); + } + return true; + } + + // }}} + // {{{ loadExtension() + + /** + * OS independant PHP extension load. Remember to take care + * on the correct extension name for case sensitive OSes. + * + * @param string $ext The extension name + * @return bool Success or not on the dl() call + */ + function loadExtension($ext) + { + if (!extension_loaded($ext)) { + // if either returns true dl() will produce a FATAL error, stop that + if ((ini_get('enable_dl') != 1) || (ini_get('safe_mode') == 1)) { + return false; + } + + if (OS_WINDOWS) { + $suffix = '.dll'; + } elseif (PHP_OS == 'HP-UX') { + $suffix = '.sl'; + } elseif (PHP_OS == 'AIX') { + $suffix = '.a'; + } elseif (PHP_OS == 'OSX') { + $suffix = '.bundle'; + } else { + $suffix = '.so'; + } + + return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix); + } + + return true; + } + + // }}} +} + +if (PEAR_ZE2) { + include_once 'phar://install-pear-nozlib.phar/' . 'PEAR5.php'; +} + +// {{{ _PEAR_call_destructors() + +function _PEAR_call_destructors() +{ + global $_PEAR_destructor_object_list; + if (is_array($_PEAR_destructor_object_list) && + sizeof($_PEAR_destructor_object_list)) + { + reset($_PEAR_destructor_object_list); + if (PEAR_ZE2) { + $destructLifoExists = PEAR5::getStaticProperty('PEAR', 'destructlifo'); + } else { + $destructLifoExists = PEAR::getStaticProperty('PEAR', 'destructlifo'); + } + + if ($destructLifoExists) { + $_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list); + } + + while (list($k, $objref) = each($_PEAR_destructor_object_list)) { + $classname = get_class($objref); + while ($classname) { + $destructor = "_$classname"; + if (method_exists($objref, $destructor)) { + $objref->$destructor(); + break; + } else { + $classname = get_parent_class($classname); + } + } + } + // Empty the object list to ensure that destructors are + // not called more than once. + $_PEAR_destructor_object_list = array(); + } + + // Now call the shutdown functions + if (isset($GLOBALS['_PEAR_shutdown_funcs']) AND is_array($GLOBALS['_PEAR_shutdown_funcs']) AND !empty($GLOBALS['_PEAR_shutdown_funcs'])) { + foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) { + call_user_func_array($value[0], $value[1]); + } + } +} + +// }}} +/** + * Standard PEAR error class for PHP 4 + * + * This class is supserseded by {@link PEAR_Exception} in PHP 5 + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Tomas V.V. Cox + * @author Gregory Beaver + * @copyright 1997-2006 The PHP Group + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/manual/en/core.pear.pear-error.php + * @see PEAR::raiseError(), PEAR::throwError() + * @since Class available since PHP 4.0.2 + */ +class PEAR_Error +{ + // {{{ properties + + var $error_message_prefix = ''; + var $mode = PEAR_ERROR_RETURN; + var $level = E_USER_NOTICE; + var $code = -1; + var $message = ''; + var $userinfo = ''; + var $backtrace = null; + + // }}} + // {{{ constructor + + /** + * PEAR_Error constructor + * + * @param string $message message + * + * @param int $code (optional) error code + * + * @param int $mode (optional) error mode, one of: PEAR_ERROR_RETURN, + * PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER, + * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION + * + * @param mixed $options (optional) error level, _OR_ in the case of + * PEAR_ERROR_CALLBACK, the callback function or object/method + * tuple. + * + * @param string $userinfo (optional) additional user/debug info + * + * @access public + * + */ + function PEAR_Error($message = 'unknown error', $code = null, + $mode = null, $options = null, $userinfo = null) + { + if ($mode === null) { + $mode = PEAR_ERROR_RETURN; + } + $this->message = $message; + $this->code = $code; + $this->mode = $mode; + $this->userinfo = $userinfo; + + if (PEAR_ZE2) { + $skiptrace = PEAR5::getStaticProperty('PEAR_Error', 'skiptrace'); + } else { + $skiptrace = PEAR::getStaticProperty('PEAR_Error', 'skiptrace'); + } + + if (!$skiptrace) { + $this->backtrace = debug_backtrace(); + if (isset($this->backtrace[0]) && isset($this->backtrace[0]['object'])) { + unset($this->backtrace[0]['object']); + } + } + + if ($mode & PEAR_ERROR_CALLBACK) { + $this->level = E_USER_NOTICE; + $this->callback = $options; + } else { + if ($options === null) { + $options = E_USER_NOTICE; + } + + $this->level = $options; + $this->callback = null; + } + + if ($this->mode & PEAR_ERROR_PRINT) { + if (is_null($options) || is_int($options)) { + $format = "%s"; + } else { + $format = $options; + } + + printf($format, $this->getMessage()); + } + + if ($this->mode & PEAR_ERROR_TRIGGER) { + trigger_error($this->getMessage(), $this->level); + } + + if ($this->mode & PEAR_ERROR_DIE) { + $msg = $this->getMessage(); + if (is_null($options) || is_int($options)) { + $format = "%s"; + if (substr($msg, -1) != "\n") { + $msg .= "\n"; + } + } else { + $format = $options; + } + die(sprintf($format, $msg)); + } + + if ($this->mode & PEAR_ERROR_CALLBACK) { + if (is_callable($this->callback)) { + call_user_func($this->callback, $this); + } + } + + if ($this->mode & PEAR_ERROR_EXCEPTION) { + trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_Exception for exceptions", E_USER_WARNING); + eval('$e = new Exception($this->message, $this->code);throw($e);'); + } + } + + // }}} + // {{{ getMode() + + /** + * Get the error mode from an error object. + * + * @return int error mode + * @access public + */ + function getMode() { + return $this->mode; + } + + // }}} + // {{{ getCallback() + + /** + * Get the callback function/method from an error object. + * + * @return mixed callback function or object/method array + * @access public + */ + function getCallback() { + return $this->callback; + } + + // }}} + // {{{ getMessage() + + + /** + * Get the error message from an error object. + * + * @return string full error message + * @access public + */ + function getMessage() + { + return ($this->error_message_prefix . $this->message); + } + + + // }}} + // {{{ getCode() + + /** + * Get error code from an error object + * + * @return int error code + * @access public + */ + function getCode() + { + return $this->code; + } + + // }}} + // {{{ getType() + + /** + * Get the name of this error/exception. + * + * @return string error/exception name (type) + * @access public + */ + function getType() + { + return get_class($this); + } + + // }}} + // {{{ getUserInfo() + + /** + * Get additional user-supplied information. + * + * @return string user-supplied information + * @access public + */ + function getUserInfo() + { + return $this->userinfo; + } + + // }}} + // {{{ getDebugInfo() + + /** + * Get additional debug information supplied by the application. + * + * @return string debug information + * @access public + */ + function getDebugInfo() + { + return $this->getUserInfo(); + } + + // }}} + // {{{ getBacktrace() + + /** + * Get the call backtrace from where the error was generated. + * Supported with PHP 4.3.0 or newer. + * + * @param int $frame (optional) what frame to fetch + * @return array Backtrace, or NULL if not available. + * @access public + */ + function getBacktrace($frame = null) + { + if (defined('PEAR_IGNORE_BACKTRACE')) { + return null; + } + if ($frame === null) { + return $this->backtrace; + } + return $this->backtrace[$frame]; + } + + // }}} + // {{{ addUserInfo() + + function addUserInfo($info) + { + if (empty($this->userinfo)) { + $this->userinfo = $info; + } else { + $this->userinfo .= " ** $info"; + } + } + + // }}} + // {{{ toString() + function __toString() + { + return $this->getMessage(); + } + // }}} + // {{{ toString() + + /** + * Make a string representation of this object. + * + * @return string a string with an object summary + * @access public + */ + function toString() { + $modes = array(); + $levels = array(E_USER_NOTICE => 'notice', + E_USER_WARNING => 'warning', + E_USER_ERROR => 'error'); + if ($this->mode & PEAR_ERROR_CALLBACK) { + if (is_array($this->callback)) { + $callback = (is_object($this->callback[0]) ? + strtolower(get_class($this->callback[0])) : + $this->callback[0]) . '::' . + $this->callback[1]; + } else { + $callback = $this->callback; + } + return sprintf('[%s: message="%s" code=%d mode=callback '. + 'callback=%s prefix="%s" info="%s"]', + strtolower(get_class($this)), $this->message, $this->code, + $callback, $this->error_message_prefix, + $this->userinfo); + } + if ($this->mode & PEAR_ERROR_PRINT) { + $modes[] = 'print'; + } + if ($this->mode & PEAR_ERROR_TRIGGER) { + $modes[] = 'trigger'; + } + if ($this->mode & PEAR_ERROR_DIE) { + $modes[] = 'die'; + } + if ($this->mode & PEAR_ERROR_RETURN) { + $modes[] = 'return'; + } + return sprintf('[%s: message="%s" code=%d mode=%s level=%s '. + 'prefix="%s" info="%s"]', + strtolower(get_class($this)), $this->message, $this->code, + implode("|", $modes), $levels[$this->level], + $this->error_message_prefix, + $this->userinfo); + } + + // }}} +} + +/* + * Local Variables: + * mode: php + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: ChannelFile.php 286951 2009-08-09 14:41:22Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * Needed for error handling + */ +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/ErrorStack.php'; +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/XMLParser.php'; +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Common.php'; + +/** + * Error code if the channel.xml tag does not contain a valid version + */ +define('PEAR_CHANNELFILE_ERROR_NO_VERSION', 1); +/** + * Error code if the channel.xml tag version is not supported (version 1.0 is the only supported version, + * currently + */ +define('PEAR_CHANNELFILE_ERROR_INVALID_VERSION', 2); + +/** + * Error code if parsing is attempted with no xml extension + */ +define('PEAR_CHANNELFILE_ERROR_NO_XML_EXT', 3); + +/** + * Error code if creating the xml parser resource fails + */ +define('PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER', 4); + +/** + * Error code used for all sax xml parsing errors + */ +define('PEAR_CHANNELFILE_ERROR_PARSER_ERROR', 5); + +/**#@+ + * Validation errors + */ +/** + * Error code when channel name is missing + */ +define('PEAR_CHANNELFILE_ERROR_NO_NAME', 6); +/** + * Error code when channel name is invalid + */ +define('PEAR_CHANNELFILE_ERROR_INVALID_NAME', 7); +/** + * Error code when channel summary is missing + */ +define('PEAR_CHANNELFILE_ERROR_NO_SUMMARY', 8); +/** + * Error code when channel summary is multi-line + */ +define('PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY', 9); +/** + * Error code when channel server is missing for protocol + */ +define('PEAR_CHANNELFILE_ERROR_NO_HOST', 10); +/** + * Error code when channel server is invalid for protocol + */ +define('PEAR_CHANNELFILE_ERROR_INVALID_HOST', 11); +/** + * Error code when a mirror name is invalid + */ +define('PEAR_CHANNELFILE_ERROR_INVALID_MIRROR', 21); +/** + * Error code when a mirror type is invalid + */ +define('PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE', 22); +/** + * Error code when an attempt is made to generate xml, but the parsed content is invalid + */ +define('PEAR_CHANNELFILE_ERROR_INVALID', 23); +/** + * Error code when an empty package name validate regex is passed in + */ +define('PEAR_CHANNELFILE_ERROR_EMPTY_REGEX', 24); +/** + * Error code when a tag has no version + */ +define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION', 25); +/** + * Error code when a tag has no name + */ +define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME', 26); +/** + * Error code when a tag has no name + */ +define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME', 27); +/** + * Error code when a tag has no version attribute + */ +define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION', 28); +/** + * Error code when a mirror does not exist but is called for in one of the set* + * methods. + */ +define('PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND', 32); +/** + * Error code when a server port is not numeric + */ +define('PEAR_CHANNELFILE_ERROR_INVALID_PORT', 33); +/** + * Error code when contains no version attribute + */ +define('PEAR_CHANNELFILE_ERROR_NO_STATICVERSION', 34); +/** + * Error code when contains no type attribute in a protocol definition + */ +define('PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE', 35); +/** + * Error code when a mirror is defined and the channel.xml represents the __uri pseudo-channel + */ +define('PEAR_CHANNELFILE_URI_CANT_MIRROR', 36); +/** + * Error code when ssl attribute is present and is not "yes" + */ +define('PEAR_CHANNELFILE_ERROR_INVALID_SSL', 37); +/**#@-*/ + +/** + * Mirror types allowed. Currently only internet servers are recognized. + */ +$GLOBALS['_PEAR_CHANNELS_MIRROR_TYPES'] = array('server'); + + +/** + * The Channel handling class + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_ChannelFile +{ + /** + * @access private + * @var PEAR_ErrorStack + * @access private + */ + var $_stack; + + /** + * Supported channel.xml versions, for parsing + * @var array + * @access private + */ + var $_supportedVersions = array('1.0'); + + /** + * Parsed channel information + * @var array + * @access private + */ + var $_channelInfo; + + /** + * index into the subchannels array, used for parsing xml + * @var int + * @access private + */ + var $_subchannelIndex; + + /** + * index into the mirrors array, used for parsing xml + * @var int + * @access private + */ + var $_mirrorIndex; + + /** + * Flag used to determine the validity of parsed content + * @var boolean + * @access private + */ + var $_isValid = false; + + function PEAR_ChannelFile() + { + $this->_stack = &new PEAR_ErrorStack('PEAR_ChannelFile'); + $this->_stack->setErrorMessageTemplate($this->_getErrorMessage()); + $this->_isValid = false; + } + + /** + * @return array + * @access protected + */ + function _getErrorMessage() + { + return + array( + PEAR_CHANNELFILE_ERROR_INVALID_VERSION => + 'While parsing channel.xml, an invalid version number "%version% was passed in, expecting one of %versions%', + PEAR_CHANNELFILE_ERROR_NO_VERSION => + 'No version number found in tag', + PEAR_CHANNELFILE_ERROR_NO_XML_EXT => + '%error%', + PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER => + 'Unable to create XML parser', + PEAR_CHANNELFILE_ERROR_PARSER_ERROR => + '%error%', + PEAR_CHANNELFILE_ERROR_NO_NAME => + 'Missing channel name', + PEAR_CHANNELFILE_ERROR_INVALID_NAME => + 'Invalid channel %tag% "%name%"', + PEAR_CHANNELFILE_ERROR_NO_SUMMARY => + 'Missing channel summary', + PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY => + 'Channel summary should be on one line, but is multi-line', + PEAR_CHANNELFILE_ERROR_NO_HOST => + 'Missing channel server for %type% server', + PEAR_CHANNELFILE_ERROR_INVALID_HOST => + 'Server name "%server%" is invalid for %type% server', + PEAR_CHANNELFILE_ERROR_INVALID_MIRROR => + 'Invalid mirror name "%name%", mirror type %type%', + PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE => + 'Invalid mirror type "%type%"', + PEAR_CHANNELFILE_ERROR_INVALID => + 'Cannot generate xml, contents are invalid', + PEAR_CHANNELFILE_ERROR_EMPTY_REGEX => + 'packagenameregex cannot be empty', + PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION => + '%parent% %protocol% function has no version', + PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME => + '%parent% %protocol% function has no name', + PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE => + '%parent% rest baseurl has no type', + PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME => + 'Validation package has no name in tag', + PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION => + 'Validation package "%package%" has no version', + PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND => + 'Mirror "%mirror%" does not exist', + PEAR_CHANNELFILE_ERROR_INVALID_PORT => + 'Port "%port%" must be numeric', + PEAR_CHANNELFILE_ERROR_NO_STATICVERSION => + ' tag must contain version attribute', + PEAR_CHANNELFILE_URI_CANT_MIRROR => + 'The __uri pseudo-channel cannot have mirrors', + PEAR_CHANNELFILE_ERROR_INVALID_SSL => + '%server% has invalid ssl attribute "%ssl%" can only be yes or not present', + ); + } + + /** + * @param string contents of package.xml file + * @return bool success of parsing + */ + function fromXmlString($data) + { + if (preg_match('/_supportedVersions)) { + $this->_stack->push(PEAR_CHANNELFILE_ERROR_INVALID_VERSION, 'error', + array('version' => $channelversion[1])); + return false; + } + $parser = new PEAR_XMLParser; + $result = $parser->parse($data); + if ($result !== true) { + if ($result->getCode() == 1) { + $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_XML_EXT, 'error', + array('error' => $result->getMessage())); + } else { + $this->_stack->push(PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER, 'error'); + } + return false; + } + $this->_channelInfo = $parser->getData(); + return true; + } else { + $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_VERSION, 'error', array('xml' => $data)); + return false; + } + } + + /** + * @return array + */ + function toArray() + { + if (!$this->_isValid && !$this->validate()) { + return false; + } + return $this->_channelInfo; + } + + /** + * @param array + * @static + * @return PEAR_ChannelFile|false false if invalid + */ + function &fromArray($data, $compatibility = false, $stackClass = 'PEAR_ErrorStack') + { + $a = new PEAR_ChannelFile($compatibility, $stackClass); + $a->_fromArray($data); + if (!$a->validate()) { + $a = false; + return $a; + } + return $a; + } + + /** + * Unlike {@link fromArray()} this does not do any validation + * @param array + * @static + * @return PEAR_ChannelFile + */ + function &fromArrayWithErrors($data, $compatibility = false, + $stackClass = 'PEAR_ErrorStack') + { + $a = new PEAR_ChannelFile($compatibility, $stackClass); + $a->_fromArray($data); + return $a; + } + + /** + * @param array + * @access private + */ + function _fromArray($data) + { + $this->_channelInfo = $data; + } + + /** + * Wrapper to {@link PEAR_ErrorStack::getErrors()} + * @param boolean determines whether to purge the error stack after retrieving + * @return array + */ + function getErrors($purge = false) + { + return $this->_stack->getErrors($purge); + } + + /** + * Unindent given string (?) + * + * @param string $str The string that has to be unindented. + * @return string + * @access private + */ + function _unIndent($str) + { + // remove leading newlines + $str = preg_replace('/^[\r\n]+/', '', $str); + // find whitespace at the beginning of the first line + $indent_len = strspn($str, " \t"); + $indent = substr($str, 0, $indent_len); + $data = ''; + // remove the same amount of whitespace from following lines + foreach (explode("\n", $str) as $line) { + if (substr($line, 0, $indent_len) == $indent) { + $data .= substr($line, $indent_len) . "\n"; + } + } + return $data; + } + + /** + * Parse a channel.xml file. Expects the name of + * a channel xml file as input. + * + * @param string $descfile name of channel xml file + * @return bool success of parsing + */ + function fromXmlFile($descfile) + { + if (!file_exists($descfile) || !is_file($descfile) || !is_readable($descfile) || + (!$fp = fopen($descfile, 'r'))) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR.php'; + return PEAR::raiseError("Unable to open $descfile"); + } + + // read the whole thing so we only get one cdata callback + // for each block of cdata + fclose($fp); + $data = file_get_contents($descfile); + return $this->fromXmlString($data); + } + + /** + * Parse channel information from different sources + * + * This method is able to extract information about a channel + * from an .xml file or a string + * + * @access public + * @param string Filename of the source or the source itself + * @return bool + */ + function fromAny($info) + { + if (is_string($info) && file_exists($info) && strlen($info) < 255) { + $tmp = substr($info, -4); + if ($tmp == '.xml') { + $info = $this->fromXmlFile($info); + } else { + $fp = fopen($info, "r"); + $test = fread($fp, 5); + fclose($fp); + if ($test == "fromXmlFile($info); + } + } + if (PEAR::isError($info)) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR.php'; + return PEAR::raiseError($info); + } + } + if (is_string($info)) { + $info = $this->fromXmlString($info); + } + return $info; + } + + /** + * Return an XML document based on previous parsing and modifications + * + * @return string XML data + * + * @access public + */ + function toXml() + { + if (!$this->_isValid && !$this->validate()) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID); + return false; + } + if (!isset($this->_channelInfo['attribs']['version'])) { + $this->_channelInfo['attribs']['version'] = '1.0'; + } + $channelInfo = $this->_channelInfo; + $ret = "\n"; + $ret .= " + $channelInfo[name] + " . htmlspecialchars($channelInfo['summary'])." +"; + if (isset($channelInfo['suggestedalias'])) { + $ret .= ' ' . $channelInfo['suggestedalias'] . "\n"; + } + if (isset($channelInfo['validatepackage'])) { + $ret .= ' ' . + htmlspecialchars($channelInfo['validatepackage']['_content']) . + "\n"; + } + $ret .= " \n"; + $ret .= ' _makeRestXml($channelInfo['servers']['primary']['rest'], ' '); + } + $ret .= " \n"; + if (isset($channelInfo['servers']['mirror'])) { + $ret .= $this->_makeMirrorsXml($channelInfo); + } + $ret .= " \n"; + $ret .= ""; + return str_replace("\r", "\n", str_replace("\r\n", "\n", $ret)); + } + + /** + * Generate the tag + * @access private + */ + function _makeRestXml($info, $indent) + { + $ret = $indent . "\n"; + if (isset($info['baseurl']) && !isset($info['baseurl'][0])) { + $info['baseurl'] = array($info['baseurl']); + } + + if (isset($info['baseurl'])) { + foreach ($info['baseurl'] as $url) { + $ret .= "$indent \n"; + } + } + $ret .= $indent . "\n"; + return $ret; + } + + /** + * Generate the tag + * @access private + */ + function _makeMirrorsXml($channelInfo) + { + $ret = ""; + if (!isset($channelInfo['servers']['mirror'][0])) { + $channelInfo['servers']['mirror'] = array($channelInfo['servers']['mirror']); + } + foreach ($channelInfo['servers']['mirror'] as $mirror) { + $ret .= ' _makeRestXml($mirror['rest'], ' '); + } + $ret .= " \n"; + } else { + $ret .= "/>\n"; + } + } + return $ret; + } + + /** + * Generate the tag + * @access private + */ + function _makeFunctionsXml($functions, $indent, $rest = false) + { + $ret = ''; + if (!isset($functions[0])) { + $functions = array($functions); + } + foreach ($functions as $function) { + $ret .= "$indent\n"; + } + return $ret; + } + + /** + * Validation error. Also marks the object contents as invalid + * @param error code + * @param array error information + * @access private + */ + function _validateError($code, $params = array()) + { + $this->_stack->push($code, 'error', $params); + $this->_isValid = false; + } + + /** + * Validation warning. Does not mark the object contents invalid. + * @param error code + * @param array error information + * @access private + */ + function _validateWarning($code, $params = array()) + { + $this->_stack->push($code, 'warning', $params); + } + + /** + * Validate parsed file. + * + * @access public + * @return boolean + */ + function validate() + { + $this->_isValid = true; + $info = $this->_channelInfo; + if (empty($info['name'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_NAME); + } elseif (!$this->validChannelServer($info['name'])) { + if ($info['name'] != '__uri') { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, array('tag' => 'name', + 'name' => $info['name'])); + } + } + if (empty($info['summary'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY); + } elseif (strpos(trim($info['summary']), "\n") !== false) { + $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY, + array('summary' => $info['summary'])); + } + if (isset($info['suggestedalias'])) { + if (!$this->validChannelServer($info['suggestedalias'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, + array('tag' => 'suggestedalias', 'name' =>$info['suggestedalias'])); + } + } + if (isset($info['localalias'])) { + if (!$this->validChannelServer($info['localalias'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, + array('tag' => 'localalias', 'name' =>$info['localalias'])); + } + } + if (isset($info['validatepackage'])) { + if (!isset($info['validatepackage']['_content'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME); + } + if (!isset($info['validatepackage']['attribs']['version'])) { + $content = isset($info['validatepackage']['_content']) ? + $info['validatepackage']['_content'] : + null; + $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION, + array('package' => $content)); + } + } + + if (isset($info['servers']['primary']['attribs'], $info['servers']['primary']['attribs']['port']) && + !is_numeric($info['servers']['primary']['attribs']['port'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_PORT, + array('port' => $info['servers']['primary']['attribs']['port'])); + } + + if (isset($info['servers']['primary']['attribs'], $info['servers']['primary']['attribs']['ssl']) && + $info['servers']['primary']['attribs']['ssl'] != 'yes') { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL, + array('ssl' => $info['servers']['primary']['attribs']['ssl'], + 'server' => $info['name'])); + } + + if (isset($info['servers']['primary']['rest']) && + isset($info['servers']['primary']['rest']['baseurl'])) { + $this->_validateFunctions('rest', $info['servers']['primary']['rest']['baseurl']); + } + if (isset($info['servers']['mirror'])) { + if ($this->_channelInfo['name'] == '__uri') { + $this->_validateError(PEAR_CHANNELFILE_URI_CANT_MIRROR); + } + if (!isset($info['servers']['mirror'][0])) { + $info['servers']['mirror'] = array($info['servers']['mirror']); + } + foreach ($info['servers']['mirror'] as $mirror) { + if (!isset($mirror['attribs']['host'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_HOST, + array('type' => 'mirror')); + } elseif (!$this->validChannelServer($mirror['attribs']['host'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_HOST, + array('server' => $mirror['attribs']['host'], 'type' => 'mirror')); + } + if (isset($mirror['attribs']['ssl']) && $mirror['attribs']['ssl'] != 'yes') { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL, + array('ssl' => $info['ssl'], 'server' => $mirror['attribs']['host'])); + } + if (isset($mirror['rest'])) { + $this->_validateFunctions('rest', $mirror['rest']['baseurl'], + $mirror['attribs']['host']); + } + } + } + return $this->_isValid; + } + + /** + * @param string rest - protocol name this function applies to + * @param array the functions + * @param string the name of the parent element (mirror name, for instance) + */ + function _validateFunctions($protocol, $functions, $parent = '') + { + if (!isset($functions[0])) { + $functions = array($functions); + } + + foreach ($functions as $function) { + if (!isset($function['_content']) || empty($function['_content'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME, + array('parent' => $parent, 'protocol' => $protocol)); + } + + if ($protocol == 'rest') { + if (!isset($function['attribs']['type']) || + empty($function['attribs']['type'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE, + array('parent' => $parent, 'protocol' => $protocol)); + } + } else { + if (!isset($function['attribs']['version']) || + empty($function['attribs']['version'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION, + array('parent' => $parent, 'protocol' => $protocol)); + } + } + } + } + + /** + * Test whether a string contains a valid channel server. + * @param string $ver the package version to test + * @return bool + */ + function validChannelServer($server) + { + if ($server == '__uri') { + return true; + } + return (bool) preg_match(PEAR_CHANNELS_SERVER_PREG, $server); + } + + /** + * @return string|false + */ + function getName() + { + if (isset($this->_channelInfo['name'])) { + return $this->_channelInfo['name']; + } + + return false; + } + + /** + * @return string|false + */ + function getServer() + { + if (isset($this->_channelInfo['name'])) { + return $this->_channelInfo['name']; + } + + return false; + } + + /** + * @return int|80 port number to connect to + */ + function getPort($mirror = false) + { + if ($mirror) { + if ($mir = $this->getMirror($mirror)) { + if (isset($mir['attribs']['port'])) { + return $mir['attribs']['port']; + } + + if ($this->getSSL($mirror)) { + return 443; + } + + return 80; + } + + return false; + } + + if (isset($this->_channelInfo['servers']['primary']['attribs']['port'])) { + return $this->_channelInfo['servers']['primary']['attribs']['port']; + } + + if ($this->getSSL()) { + return 443; + } + + return 80; + } + + /** + * @return bool Determines whether secure sockets layer (SSL) is used to connect to this channel + */ + function getSSL($mirror = false) + { + if ($mirror) { + if ($mir = $this->getMirror($mirror)) { + if (isset($mir['attribs']['ssl'])) { + return true; + } + + return false; + } + + return false; + } + + if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) { + return true; + } + + return false; + } + + /** + * @return string|false + */ + function getSummary() + { + if (isset($this->_channelInfo['summary'])) { + return $this->_channelInfo['summary']; + } + + return false; + } + + /** + * @param string protocol type + * @param string Mirror name + * @return array|false + */ + function getFunctions($protocol, $mirror = false) + { + if ($this->getName() == '__uri') { + return false; + } + + $function = $protocol == 'rest' ? 'baseurl' : 'function'; + if ($mirror) { + if ($mir = $this->getMirror($mirror)) { + if (isset($mir[$protocol][$function])) { + return $mir[$protocol][$function]; + } + } + + return false; + } + + if (isset($this->_channelInfo['servers']['primary'][$protocol][$function])) { + return $this->_channelInfo['servers']['primary'][$protocol][$function]; + } + + return false; + } + + /** + * @param string Protocol type + * @param string Function name (null to return the + * first protocol of the type requested) + * @param string Mirror name, if any + * @return array + */ + function getFunction($type, $name = null, $mirror = false) + { + $protocols = $this->getFunctions($type, $mirror); + if (!$protocols) { + return false; + } + + foreach ($protocols as $protocol) { + if ($name === null) { + return $protocol; + } + + if ($protocol['_content'] != $name) { + continue; + } + + return $protocol; + } + + return false; + } + + /** + * @param string protocol type + * @param string protocol name + * @param string version + * @param string mirror name + * @return boolean + */ + function supports($type, $name = null, $mirror = false, $version = '1.0') + { + $protocols = $this->getFunctions($type, $mirror); + if (!$protocols) { + return false; + } + + foreach ($protocols as $protocol) { + if ($protocol['attribs']['version'] != $version) { + continue; + } + + if ($name === null) { + return true; + } + + if ($protocol['_content'] != $name) { + continue; + } + + return true; + } + + return false; + } + + /** + * Determines whether a channel supports Representational State Transfer (REST) protocols + * for retrieving channel information + * @param string + * @return bool + */ + function supportsREST($mirror = false) + { + if ($mirror == $this->_channelInfo['name']) { + $mirror = false; + } + + if ($mirror) { + if ($mir = $this->getMirror($mirror)) { + return isset($mir['rest']); + } + + return false; + } + + return isset($this->_channelInfo['servers']['primary']['rest']); + } + + /** + * Get the URL to access a base resource. + * + * Hyperlinks in the returned xml will be used to retrieve the proper information + * needed. This allows extreme extensibility and flexibility in implementation + * @param string Resource Type to retrieve + */ + function getBaseURL($resourceType, $mirror = false) + { + if ($mirror == $this->_channelInfo['name']) { + $mirror = false; + } + + if ($mirror) { + $mir = $this->getMirror($mirror); + if (!$mir) { + return false; + } + + $rest = $mir['rest']; + } else { + $rest = $this->_channelInfo['servers']['primary']['rest']; + } + + if (!isset($rest['baseurl'][0])) { + $rest['baseurl'] = array($rest['baseurl']); + } + + foreach ($rest['baseurl'] as $baseurl) { + if (strtolower($baseurl['attribs']['type']) == strtolower($resourceType)) { + return $baseurl['_content']; + } + } + + return false; + } + + /** + * Since REST does not implement RPC, provide this as a logical wrapper around + * resetFunctions for REST + * @param string|false mirror name, if any + */ + function resetREST($mirror = false) + { + return $this->resetFunctions('rest', $mirror); + } + + /** + * Empty all protocol definitions + * @param string protocol type + * @param string|false mirror name, if any + */ + function resetFunctions($type, $mirror = false) + { + if ($mirror) { + if (isset($this->_channelInfo['servers']['mirror'])) { + $mirrors = $this->_channelInfo['servers']['mirror']; + if (!isset($mirrors[0])) { + $mirrors = array($mirrors); + } + + foreach ($mirrors as $i => $mir) { + if ($mir['attribs']['host'] == $mirror) { + if (isset($this->_channelInfo['servers']['mirror'][$i][$type])) { + unset($this->_channelInfo['servers']['mirror'][$i][$type]); + } + + return true; + } + } + + return false; + } + + return false; + } + + if (isset($this->_channelInfo['servers']['primary'][$type])) { + unset($this->_channelInfo['servers']['primary'][$type]); + } + + return true; + } + + /** + * Set a channel's protocols to the protocols supported by pearweb + */ + function setDefaultPEARProtocols($version = '1.0', $mirror = false) + { + switch ($version) { + case '1.0' : + $this->resetREST($mirror); + + if (!isset($this->_channelInfo['servers'])) { + $this->_channelInfo['servers'] = array('primary' => + array('rest' => array())); + } elseif (!isset($this->_channelInfo['servers']['primary'])) { + $this->_channelInfo['servers']['primary'] = array('rest' => array()); + } + + return true; + break; + default : + return false; + break; + } + } + + /** + * @return array + */ + function getMirrors() + { + if (isset($this->_channelInfo['servers']['mirror'])) { + $mirrors = $this->_channelInfo['servers']['mirror']; + if (!isset($mirrors[0])) { + $mirrors = array($mirrors); + } + + return $mirrors; + } + + return array(); + } + + /** + * Get the unserialized XML representing a mirror + * @return array|false + */ + function getMirror($server) + { + foreach ($this->getMirrors() as $mirror) { + if ($mirror['attribs']['host'] == $server) { + return $mirror; + } + } + + return false; + } + + /** + * @param string + * @return string|false + * @error PEAR_CHANNELFILE_ERROR_NO_NAME + * @error PEAR_CHANNELFILE_ERROR_INVALID_NAME + */ + function setName($name) + { + return $this->setServer($name); + } + + /** + * Set the socket number (port) that is used to connect to this channel + * @param integer + * @param string|false name of the mirror server, or false for the primary + */ + function setPort($port, $mirror = false) + { + if ($mirror) { + if (!isset($this->_channelInfo['servers']['mirror'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, + array('mirror' => $mirror)); + return false; + } + + if (isset($this->_channelInfo['servers']['mirror'][0])) { + foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { + if ($mirror == $mir['attribs']['host']) { + $this->_channelInfo['servers']['mirror'][$i]['attribs']['port'] = $port; + return true; + } + } + + return false; + } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { + $this->_channelInfo['servers']['mirror']['attribs']['port'] = $port; + $this->_isValid = false; + return true; + } + } + + $this->_channelInfo['servers']['primary']['attribs']['port'] = $port; + $this->_isValid = false; + return true; + } + + /** + * Set the socket number (port) that is used to connect to this channel + * @param bool Determines whether to turn on SSL support or turn it off + * @param string|false name of the mirror server, or false for the primary + */ + function setSSL($ssl = true, $mirror = false) + { + if ($mirror) { + if (!isset($this->_channelInfo['servers']['mirror'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, + array('mirror' => $mirror)); + return false; + } + + if (isset($this->_channelInfo['servers']['mirror'][0])) { + foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { + if ($mirror == $mir['attribs']['host']) { + if (!$ssl) { + if (isset($this->_channelInfo['servers']['mirror'][$i] + ['attribs']['ssl'])) { + unset($this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl']); + } + } else { + $this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl'] = 'yes'; + } + + return true; + } + } + + return false; + } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { + if (!$ssl) { + if (isset($this->_channelInfo['servers']['mirror']['attribs']['ssl'])) { + unset($this->_channelInfo['servers']['mirror']['attribs']['ssl']); + } + } else { + $this->_channelInfo['servers']['mirror']['attribs']['ssl'] = 'yes'; + } + + $this->_isValid = false; + return true; + } + } + + if ($ssl) { + $this->_channelInfo['servers']['primary']['attribs']['ssl'] = 'yes'; + } else { + if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) { + unset($this->_channelInfo['servers']['primary']['attribs']['ssl']); + } + } + + $this->_isValid = false; + return true; + } + + /** + * @param string + * @return string|false + * @error PEAR_CHANNELFILE_ERROR_NO_SERVER + * @error PEAR_CHANNELFILE_ERROR_INVALID_SERVER + */ + function setServer($server, $mirror = false) + { + if (empty($server)) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SERVER); + return false; + } elseif (!$this->validChannelServer($server)) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, + array('tag' => 'name', 'name' => $server)); + return false; + } + + if ($mirror) { + $found = false; + foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { + if ($mirror == $mir['attribs']['host']) { + $found = true; + break; + } + } + + if (!$found) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, + array('mirror' => $mirror)); + return false; + } + + $this->_channelInfo['mirror'][$i]['attribs']['host'] = $server; + return true; + } + + $this->_channelInfo['name'] = $server; + return true; + } + + /** + * @param string + * @return boolean success + * @error PEAR_CHANNELFILE_ERROR_NO_SUMMARY + * @warning PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY + */ + function setSummary($summary) + { + if (empty($summary)) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY); + return false; + } elseif (strpos(trim($summary), "\n") !== false) { + $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY, + array('summary' => $summary)); + } + + $this->_channelInfo['summary'] = $summary; + return true; + } + + /** + * @param string + * @param boolean determines whether the alias is in channel.xml or local + * @return boolean success + */ + function setAlias($alias, $local = false) + { + if (!$this->validChannelServer($alias)) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, + array('tag' => 'suggestedalias', 'name' => $alias)); + return false; + } + + if ($local) { + $this->_channelInfo['localalias'] = $alias; + } else { + $this->_channelInfo['suggestedalias'] = $alias; + } + + return true; + } + + /** + * @return string + */ + function getAlias() + { + if (isset($this->_channelInfo['localalias'])) { + return $this->_channelInfo['localalias']; + } + if (isset($this->_channelInfo['suggestedalias'])) { + return $this->_channelInfo['suggestedalias']; + } + if (isset($this->_channelInfo['name'])) { + return $this->_channelInfo['name']; + } + return ''; + } + + /** + * Set the package validation object if it differs from PEAR's default + * The class must be includeable via changing _ in the classname to path separator, + * but no checking of this is made. + * @param string|false pass in false to reset to the default packagename regex + * @return boolean success + */ + function setValidationPackage($validateclass, $version) + { + if (empty($validateclass)) { + unset($this->_channelInfo['validatepackage']); + } + $this->_channelInfo['validatepackage'] = array('_content' => $validateclass); + $this->_channelInfo['validatepackage']['attribs'] = array('version' => $version); + } + + /** + * Add a protocol to the provides section + * @param string protocol type + * @param string protocol version + * @param string protocol name, if any + * @param string mirror name, if this is a mirror's protocol + * @return bool + */ + function addFunction($type, $version, $name = '', $mirror = false) + { + if ($mirror) { + return $this->addMirrorFunction($mirror, $type, $version, $name); + } + + $set = array('attribs' => array('version' => $version), '_content' => $name); + if (!isset($this->_channelInfo['servers']['primary'][$type]['function'])) { + if (!isset($this->_channelInfo['servers'])) { + $this->_channelInfo['servers'] = array('primary' => + array($type => array())); + } elseif (!isset($this->_channelInfo['servers']['primary'])) { + $this->_channelInfo['servers']['primary'] = array($type => array()); + } + + $this->_channelInfo['servers']['primary'][$type]['function'] = $set; + $this->_isValid = false; + return true; + } elseif (!isset($this->_channelInfo['servers']['primary'][$type]['function'][0])) { + $this->_channelInfo['servers']['primary'][$type]['function'] = array( + $this->_channelInfo['servers']['primary'][$type]['function']); + } + + $this->_channelInfo['servers']['primary'][$type]['function'][] = $set; + return true; + } + /** + * Add a protocol to a mirror's provides section + * @param string mirror name (server) + * @param string protocol type + * @param string protocol version + * @param string protocol name, if any + */ + function addMirrorFunction($mirror, $type, $version, $name = '') + { + if (!isset($this->_channelInfo['servers']['mirror'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, + array('mirror' => $mirror)); + return false; + } + + $setmirror = false; + if (isset($this->_channelInfo['servers']['mirror'][0])) { + foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { + if ($mirror == $mir['attribs']['host']) { + $setmirror = &$this->_channelInfo['servers']['mirror'][$i]; + break; + } + } + } else { + if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { + $setmirror = &$this->_channelInfo['servers']['mirror']; + } + } + + if (!$setmirror) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, + array('mirror' => $mirror)); + return false; + } + + $set = array('attribs' => array('version' => $version), '_content' => $name); + if (!isset($setmirror[$type]['function'])) { + $setmirror[$type]['function'] = $set; + $this->_isValid = false; + return true; + } elseif (!isset($setmirror[$type]['function'][0])) { + $setmirror[$type]['function'] = array($setmirror[$type]['function']); + } + + $setmirror[$type]['function'][] = $set; + $this->_isValid = false; + return true; + } + + /** + * @param string Resource Type this url links to + * @param string URL + * @param string|false mirror name, if this is not a primary server REST base URL + */ + function setBaseURL($resourceType, $url, $mirror = false) + { + if ($mirror) { + if (!isset($this->_channelInfo['servers']['mirror'])) { + $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, + array('mirror' => $mirror)); + return false; + } + + $setmirror = false; + if (isset($this->_channelInfo['servers']['mirror'][0])) { + foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { + if ($mirror == $mir['attribs']['host']) { + $setmirror = &$this->_channelInfo['servers']['mirror'][$i]; + break; + } + } + } else { + if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { + $setmirror = &$this->_channelInfo['servers']['mirror']; + } + } + } else { + $setmirror = &$this->_channelInfo['servers']['primary']; + } + + $set = array('attribs' => array('type' => $resourceType), '_content' => $url); + if (!isset($setmirror['rest'])) { + $setmirror['rest'] = array(); + } + + if (!isset($setmirror['rest']['baseurl'])) { + $setmirror['rest']['baseurl'] = $set; + $this->_isValid = false; + return true; + } elseif (!isset($setmirror['rest']['baseurl'][0])) { + $setmirror['rest']['baseurl'] = array($setmirror['rest']['baseurl']); + } + + foreach ($setmirror['rest']['baseurl'] as $i => $url) { + if ($url['attribs']['type'] == $resourceType) { + $this->_isValid = false; + $setmirror['rest']['baseurl'][$i] = $set; + return true; + } + } + + $setmirror['rest']['baseurl'][] = $set; + $this->_isValid = false; + return true; + } + + /** + * @param string mirror server + * @param int mirror http port + * @return boolean + */ + function addMirror($server, $port = null) + { + if ($this->_channelInfo['name'] == '__uri') { + return false; // the __uri channel cannot have mirrors by definition + } + + $set = array('attribs' => array('host' => $server)); + if (is_numeric($port)) { + $set['attribs']['port'] = $port; + } + + if (!isset($this->_channelInfo['servers']['mirror'])) { + $this->_channelInfo['servers']['mirror'] = $set; + return true; + } + + if (!isset($this->_channelInfo['servers']['mirror'][0])) { + $this->_channelInfo['servers']['mirror'] = + array($this->_channelInfo['servers']['mirror']); + } + + $this->_channelInfo['servers']['mirror'][] = $set; + return true; + } + + /** + * Retrieve the name of the validation package for this channel + * @return string|false + */ + function getValidationPackage() + { + if (!$this->_isValid && !$this->validate()) { + return false; + } + + if (!isset($this->_channelInfo['validatepackage'])) { + return array('attribs' => array('version' => 'default'), + '_content' => 'PEAR_Validate'); + } + + return $this->_channelInfo['validatepackage']; + } + + /** + * Retrieve the object that can be used for custom validation + * @param string|false the name of the package to validate. If the package is + * the channel validation package, PEAR_Validate is returned + * @return PEAR_Validate|false false is returned if the validation package + * cannot be located + */ + function &getValidationObject($package = false) + { + if (!class_exists('PEAR_Validate')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Validate.php'; + } + + if (!$this->_isValid) { + if (!$this->validate()) { + $a = false; + return $a; + } + } + + if (isset($this->_channelInfo['validatepackage'])) { + if ($package == $this->_channelInfo['validatepackage']) { + // channel validation packages are always validated by PEAR_Validate + $val = &new PEAR_Validate; + return $val; + } + + if (!class_exists(str_replace('.', '_', + $this->_channelInfo['validatepackage']['_content']))) { + if ($this->isIncludeable(str_replace('_', '/', + $this->_channelInfo['validatepackage']['_content']) . '.php')) { + include_once 'phar://install-pear-nozlib.phar/' . str_replace('_', '/', + $this->_channelInfo['validatepackage']['_content']) . '.php'; + $vclass = str_replace('.', '_', + $this->_channelInfo['validatepackage']['_content']); + $val = &new $vclass; + } else { + $a = false; + return $a; + } + } else { + $vclass = str_replace('.', '_', + $this->_channelInfo['validatepackage']['_content']); + $val = &new $vclass; + } + } else { + $val = &new PEAR_Validate; + } + + return $val; + } + + function isIncludeable($path) + { + $possibilities = explode(PATH_SEPARATOR, ini_get('include_path')); + foreach ($possibilities as $dir) { + if (file_exists($dir . DIRECTORY_SEPARATOR . $path) + && is_readable($dir . DIRECTORY_SEPARATOR . $path)) { + return true; + } + } + + return false; + } + + /** + * This function is used by the channel updater and retrieves a value set by + * the registry, or the current time if it has not been set + * @return string + */ + function lastModified() + { + if (isset($this->_channelInfo['_lastmodified'])) { + return $this->_channelInfo['_lastmodified']; + } + + return time(); + } +} + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Parser.php 276383 2009-02-24 23:39:37Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * base xml parser class + */ +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/XMLParser.php'; +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/ChannelFile.php'; +/** + * Parser for channel.xml + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_ChannelFile_Parser extends PEAR_XMLParser +{ + var $_config; + var $_logger; + var $_registry; + + function setConfig(&$c) + { + $this->_config = &$c; + $this->_registry = &$c->getRegistry(); + } + + function setLogger(&$l) + { + $this->_logger = &$l; + } + + function parse($data, $file) + { + if (PEAR::isError($err = parent::parse($data, $file))) { + return $err; + } + + $ret = new PEAR_ChannelFile; + $ret->setConfig($this->_config); + if (isset($this->_logger)) { + $ret->setLogger($this->_logger); + } + + $ret->fromArray($this->_unserializedData); + // make sure the filelist is in the easy to read format needed + $ret->flattenFilelist(); + $ret->setPackagefile($file, $archive); + return $ret; + } +} + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Command.php 286494 2009-07-29 06:57:11Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * Needed for error handling + */ +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR.php'; +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Frontend.php'; +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/XMLParser.php'; + +/** + * List of commands and what classes they are implemented in. + * @var array command => implementing class + */ +$GLOBALS['_PEAR_Command_commandlist'] = array(); + +/** + * List of commands and their descriptions + * @var array command => description + */ +$GLOBALS['_PEAR_Command_commanddesc'] = array(); + +/** + * List of shortcuts to common commands. + * @var array shortcut => command + */ +$GLOBALS['_PEAR_Command_shortcuts'] = array(); + +/** + * Array of command objects + * @var array class => object + */ +$GLOBALS['_PEAR_Command_objects'] = array(); + +/** + * PEAR command class, a simple factory class for administrative + * commands. + * + * How to implement command classes: + * + * - The class must be called PEAR_Command_Nnn, installed in the + * "PEAR/Common" subdir, with a method called getCommands() that + * returns an array of the commands implemented by the class (see + * PEAR/Command/Install.php for an example). + * + * - The class must implement a run() function that is called with three + * params: + * + * (string) command name + * (array) assoc array with options, freely defined by each + * command, for example: + * array('force' => true) + * (array) list of the other parameters + * + * The run() function returns a PEAR_CommandResponse object. Use + * these methods to get information: + * + * int getStatus() Returns PEAR_COMMAND_(SUCCESS|FAILURE|PARTIAL) + * *_PARTIAL means that you need to issue at least + * one more command to complete the operation + * (used for example for validation steps). + * + * string getMessage() Returns a message for the user. Remember, + * no HTML or other interface-specific markup. + * + * If something unexpected happens, run() returns a PEAR error. + * + * - DON'T OUTPUT ANYTHING! Return text for output instead. + * + * - DON'T USE HTML! The text you return will be used from both Gtk, + * web and command-line interfaces, so for now, keep everything to + * plain text. + * + * - DON'T USE EXIT OR DIE! Always use pear errors. From static + * classes do PEAR::raiseError(), from other classes do + * $this->raiseError(). + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Command +{ + // {{{ factory() + + /** + * Get the right object for executing a command. + * + * @param string $command The name of the command + * @param object $config Instance of PEAR_Config object + * + * @return object the command object or a PEAR error + * + * @access public + * @static + */ + function &factory($command, &$config) + { + if (empty($GLOBALS['_PEAR_Command_commandlist'])) { + PEAR_Command::registerCommands(); + } + if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) { + $command = $GLOBALS['_PEAR_Command_shortcuts'][$command]; + } + if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) { + $a = PEAR::raiseError("unknown command `$command'"); + return $a; + } + $class = $GLOBALS['_PEAR_Command_commandlist'][$command]; + if (!class_exists($class)) { + require_once $GLOBALS['_PEAR_Command_objects'][$class]; + } + if (!class_exists($class)) { + $a = PEAR::raiseError("unknown command `$command'"); + return $a; + } + $ui =& PEAR_Command::getFrontendObject(); + $obj = &new $class($ui, $config); + return $obj; + } + + // }}} + // {{{ & getObject() + function &getObject($command) + { + $class = $GLOBALS['_PEAR_Command_commandlist'][$command]; + if (!class_exists($class)) { + require_once $GLOBALS['_PEAR_Command_objects'][$class]; + } + if (!class_exists($class)) { + return PEAR::raiseError("unknown command `$command'"); + } + $ui =& PEAR_Command::getFrontendObject(); + $config = &PEAR_Config::singleton(); + $obj = &new $class($ui, $config); + return $obj; + } + + // }}} + // {{{ & getFrontendObject() + + /** + * Get instance of frontend object. + * + * @return object|PEAR_Error + * @static + */ + function &getFrontendObject() + { + $a = &PEAR_Frontend::singleton(); + return $a; + } + + // }}} + // {{{ & setFrontendClass() + + /** + * Load current frontend class. + * + * @param string $uiclass Name of class implementing the frontend + * + * @return object the frontend object, or a PEAR error + * @static + */ + function &setFrontendClass($uiclass) + { + $a = &PEAR_Frontend::setFrontendClass($uiclass); + return $a; + } + + // }}} + // {{{ setFrontendType() + + /** + * Set current frontend. + * + * @param string $uitype Name of the frontend type (for example "CLI") + * + * @return object the frontend object, or a PEAR error + * @static + */ + function setFrontendType($uitype) + { + $uiclass = 'PEAR_Frontend_' . $uitype; + return PEAR_Command::setFrontendClass($uiclass); + } + + // }}} + // {{{ registerCommands() + + /** + * Scan through the Command directory looking for classes + * and see what commands they implement. + * + * @param bool (optional) if FALSE (default), the new list of + * commands should replace the current one. If TRUE, + * new entries will be merged with old. + * + * @param string (optional) where (what directory) to look for + * classes, defaults to the Command subdirectory of + * the directory from where this file (__FILE__) is + * included. + * + * @return bool TRUE on success, a PEAR error on failure + * + * @access public + * @static + */ + function registerCommands($merge = false, $dir = null) + { + $parser = new PEAR_XMLParser; + if ($dir === null) { + $dir = dirname(__FILE__) . '/Command'; + } + if (!is_dir($dir)) { + return PEAR::raiseError("registerCommands: opendir($dir) '$dir' does not exist or is not a directory"); + } + $dp = @opendir($dir); + if (empty($dp)) { + return PEAR::raiseError("registerCommands: opendir($dir) failed"); + } + if (!$merge) { + $GLOBALS['_PEAR_Command_commandlist'] = array(); + } + + while ($file = readdir($dp)) { + if ($file{0} == '.' || substr($file, -4) != '.xml') { + continue; + } + + $f = substr($file, 0, -4); + $class = "PEAR_Command_" . $f; + // List of commands + if (empty($GLOBALS['_PEAR_Command_objects'][$class])) { + $GLOBALS['_PEAR_Command_objects'][$class] = "$dir/" . $f . '.php'; + } + + $parser->parse(file_get_contents("$dir/$file")); + $implements = $parser->getData(); + foreach ($implements as $command => $desc) { + if ($command == 'attribs') { + continue; + } + + if (isset($GLOBALS['_PEAR_Command_commandlist'][$command])) { + return PEAR::raiseError('Command "' . $command . '" already registered in ' . + 'class "' . $GLOBALS['_PEAR_Command_commandlist'][$command] . '"'); + } + + $GLOBALS['_PEAR_Command_commandlist'][$command] = $class; + $GLOBALS['_PEAR_Command_commanddesc'][$command] = $desc['summary']; + if (isset($desc['shortcut'])) { + $shortcut = $desc['shortcut']; + if (isset($GLOBALS['_PEAR_Command_shortcuts'][$shortcut])) { + return PEAR::raiseError('Command shortcut "' . $shortcut . '" already ' . + 'registered to command "' . $command . '" in class "' . + $GLOBALS['_PEAR_Command_commandlist'][$command] . '"'); + } + $GLOBALS['_PEAR_Command_shortcuts'][$shortcut] = $command; + } + + if (isset($desc['options']) && $desc['options']) { + foreach ($desc['options'] as $oname => $option) { + if (isset($option['shortopt']) && strlen($option['shortopt']) > 1) { + return PEAR::raiseError('Option "' . $oname . '" short option "' . + $option['shortopt'] . '" must be ' . + 'only 1 character in Command "' . $command . '" in class "' . + $class . '"'); + } + } + } + } + } + + ksort($GLOBALS['_PEAR_Command_shortcuts']); + ksort($GLOBALS['_PEAR_Command_commandlist']); + @closedir($dp); + return true; + } + + // }}} + // {{{ getCommands() + + /** + * Get the list of currently supported commands, and what + * classes implement them. + * + * @return array command => implementing class + * + * @access public + * @static + */ + function getCommands() + { + if (empty($GLOBALS['_PEAR_Command_commandlist'])) { + PEAR_Command::registerCommands(); + } + return $GLOBALS['_PEAR_Command_commandlist']; + } + + // }}} + // {{{ getShortcuts() + + /** + * Get the list of command shortcuts. + * + * @return array shortcut => command + * + * @access public + * @static + */ + function getShortcuts() + { + if (empty($GLOBALS['_PEAR_Command_shortcuts'])) { + PEAR_Command::registerCommands(); + } + return $GLOBALS['_PEAR_Command_shortcuts']; + } + + // }}} + // {{{ getGetoptArgs() + + /** + * Compiles arguments for getopt. + * + * @param string $command command to get optstring for + * @param string $short_args (reference) short getopt format + * @param array $long_args (reference) long getopt format + * + * @return void + * + * @access public + * @static + */ + function getGetoptArgs($command, &$short_args, &$long_args) + { + if (empty($GLOBALS['_PEAR_Command_commandlist'])) { + PEAR_Command::registerCommands(); + } + if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) { + $command = $GLOBALS['_PEAR_Command_shortcuts'][$command]; + } + if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) { + return null; + } + $obj = &PEAR_Command::getObject($command); + return $obj->getGetoptArgs($command, $short_args, $long_args); + } + + // }}} + // {{{ getDescription() + + /** + * Get description for a command. + * + * @param string $command Name of the command + * + * @return string command description + * + * @access public + * @static + */ + function getDescription($command) + { + if (!isset($GLOBALS['_PEAR_Command_commanddesc'][$command])) { + return null; + } + return $GLOBALS['_PEAR_Command_commanddesc'][$command]; + } + + // }}} + // {{{ getHelp() + + /** + * Get help for command. + * + * @param string $command Name of the command to return help for + * + * @access public + * @static + */ + function getHelp($command) + { + $cmds = PEAR_Command::getCommands(); + if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) { + $command = $GLOBALS['_PEAR_Command_shortcuts'][$command]; + } + if (isset($cmds[$command])) { + $obj = &PEAR_Command::getObject($command); + return $obj->getHelp($command); + } + return false; + } + // }}} +} + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Common.php 276383 2009-02-24 23:39:37Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * base class + */ +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR.php'; + +/** + * PEAR commands base class + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Command_Common extends PEAR +{ + /** + * PEAR_Config object used to pass user system and configuration + * on when executing commands + * + * @var PEAR_Config + */ + var $config; + /** + * @var PEAR_Registry + * @access protected + */ + var $_registry; + + /** + * User Interface object, for all interaction with the user. + * @var object + */ + var $ui; + + var $_deps_rel_trans = array( + 'lt' => '<', + 'le' => '<=', + 'eq' => '=', + 'ne' => '!=', + 'gt' => '>', + 'ge' => '>=', + 'has' => '==' + ); + + var $_deps_type_trans = array( + 'pkg' => 'package', + 'ext' => 'extension', + 'php' => 'PHP', + 'prog' => 'external program', + 'ldlib' => 'external library for linking', + 'rtlib' => 'external runtime library', + 'os' => 'operating system', + 'websrv' => 'web server', + 'sapi' => 'SAPI backend' + ); + + /** + * PEAR_Command_Common constructor. + * + * @access public + */ + function PEAR_Command_Common(&$ui, &$config) + { + parent::PEAR(); + $this->config = &$config; + $this->ui = &$ui; + } + + /** + * Return a list of all the commands defined by this class. + * @return array list of commands + * @access public + */ + function getCommands() + { + $ret = array(); + foreach (array_keys($this->commands) as $command) { + $ret[$command] = $this->commands[$command]['summary']; + } + + return $ret; + } + + /** + * Return a list of all the command shortcuts defined by this class. + * @return array shortcut => command + * @access public + */ + function getShortcuts() + { + $ret = array(); + foreach (array_keys($this->commands) as $command) { + if (isset($this->commands[$command]['shortcut'])) { + $ret[$this->commands[$command]['shortcut']] = $command; + } + } + + return $ret; + } + + function getOptions($command) + { + $shortcuts = $this->getShortcuts(); + if (isset($shortcuts[$command])) { + $command = $shortcuts[$command]; + } + + if (isset($this->commands[$command]) && + isset($this->commands[$command]['options'])) { + return $this->commands[$command]['options']; + } + + return null; + } + + function getGetoptArgs($command, &$short_args, &$long_args) + { + $short_args = ''; + $long_args = array(); + if (empty($this->commands[$command]) || empty($this->commands[$command]['options'])) { + return; + } + + reset($this->commands[$command]['options']); + while (list($option, $info) = each($this->commands[$command]['options'])) { + $larg = $sarg = ''; + if (isset($info['arg'])) { + if ($info['arg']{0} == '(') { + $larg = '=='; + $sarg = '::'; + $arg = substr($info['arg'], 1, -1); + } else { + $larg = '='; + $sarg = ':'; + $arg = $info['arg']; + } + } + + if (isset($info['shortopt'])) { + $short_args .= $info['shortopt'] . $sarg; + } + + $long_args[] = $option . $larg; + } + } + + /** + * Returns the help message for the given command + * + * @param string $command The command + * @return mixed A fail string if the command does not have help or + * a two elements array containing [0]=>help string, + * [1]=> help string for the accepted cmd args + */ + function getHelp($command) + { + $config = &PEAR_Config::singleton(); + if (!isset($this->commands[$command])) { + return "No such command \"$command\""; + } + + $help = null; + if (isset($this->commands[$command]['doc'])) { + $help = $this->commands[$command]['doc']; + } + + if (empty($help)) { + // XXX (cox) Fallback to summary if there is no doc (show both?) + if (!isset($this->commands[$command]['summary'])) { + return "No help for command \"$command\""; + } + $help = $this->commands[$command]['summary']; + } + + if (preg_match_all('/{config\s+([^\}]+)}/e', $help, $matches)) { + foreach($matches[0] as $k => $v) { + $help = preg_replace("/$v/", $config->get($matches[1][$k]), $help); + } + } + + return array($help, $this->getHelpArgs($command)); + } + + /** + * Returns the help for the accepted arguments of a command + * + * @param string $command + * @return string The help string + */ + function getHelpArgs($command) + { + if (isset($this->commands[$command]['options']) && + count($this->commands[$command]['options'])) + { + $help = "Options:\n"; + foreach ($this->commands[$command]['options'] as $k => $v) { + if (isset($v['arg'])) { + if ($v['arg'][0] == '(') { + $arg = substr($v['arg'], 1, -1); + $sapp = " [$arg]"; + $lapp = "[=$arg]"; + } else { + $sapp = " $v[arg]"; + $lapp = "=$v[arg]"; + } + } else { + $sapp = $lapp = ""; + } + + if (isset($v['shortopt'])) { + $s = $v['shortopt']; + $help .= " -$s$sapp, --$k$lapp\n"; + } else { + $help .= " --$k$lapp\n"; + } + + $p = " "; + $doc = rtrim(str_replace("\n", "\n$p", $v['doc'])); + $help .= " $doc\n"; + } + + return $help; + } + + return null; + } + + function run($command, $options, $params) + { + if (empty($this->commands[$command]['function'])) { + // look for shortcuts + foreach (array_keys($this->commands) as $cmd) { + if (isset($this->commands[$cmd]['shortcut']) && $this->commands[$cmd]['shortcut'] == $command) { + if (empty($this->commands[$cmd]['function'])) { + return $this->raiseError("unknown command `$command'"); + } else { + $func = $this->commands[$cmd]['function']; + } + $command = $cmd; + + //$command = $this->commands[$cmd]['function']; + break; + } + } + } else { + $func = $this->commands[$command]['function']; + } + + return $this->$func($command, $options, $params); + } +} + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Install.php 287477 2009-08-19 14:19:43Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * base class + */ +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Command/Common.php'; + +/** + * PEAR commands for installation or deinstallation/upgrading of + * packages. + * + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Command_Install extends PEAR_Command_Common +{ + // {{{ properties + + var $commands = array( + 'install' => array( + 'summary' => 'Install Package', + 'function' => 'doInstall', + 'shortcut' => 'i', + 'options' => array( + 'force' => array( + 'shortopt' => 'f', + 'doc' => 'will overwrite newer installed packages', + ), + 'loose' => array( + 'shortopt' => 'l', + 'doc' => 'do not check for recommended dependency version', + ), + 'nodeps' => array( + 'shortopt' => 'n', + 'doc' => 'ignore dependencies, install anyway', + ), + 'register-only' => array( + 'shortopt' => 'r', + 'doc' => 'do not install files, only register the package as installed', + ), + 'soft' => array( + 'shortopt' => 's', + 'doc' => 'soft install, fail silently, or upgrade if already installed', + ), + 'nobuild' => array( + 'shortopt' => 'B', + 'doc' => 'don\'t build C extensions', + ), + 'nocompress' => array( + 'shortopt' => 'Z', + 'doc' => 'request uncompressed files when downloading', + ), + 'installroot' => array( + 'shortopt' => 'R', + 'arg' => 'DIR', + 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM', + ), + 'packagingroot' => array( + 'shortopt' => 'P', + 'arg' => 'DIR', + 'doc' => 'root directory used when packaging files, like RPM packaging', + ), + 'ignore-errors' => array( + 'doc' => 'force install even if there were errors', + ), + 'alldeps' => array( + 'shortopt' => 'a', + 'doc' => 'install all required and optional dependencies', + ), + 'onlyreqdeps' => array( + 'shortopt' => 'o', + 'doc' => 'install all required dependencies', + ), + 'offline' => array( + 'shortopt' => 'O', + 'doc' => 'do not attempt to download any urls or contact channels', + ), + 'pretend' => array( + 'shortopt' => 'p', + 'doc' => 'Only list the packages that would be downloaded', + ), + ), + 'doc' => '[channel/] ... +Installs one or more PEAR packages. You can specify a package to +install in four ways: + +"Package-1.0.tgz" : installs from a local file + +"http://example.com/Package-1.0.tgz" : installs from +anywhere on the net. + +"package.xml" : installs the package described in +package.xml. Useful for testing, or for wrapping a PEAR package in +another package manager such as RPM. + +"Package[-version/state][.tar]" : queries your default channel\'s server +({config master_server}) and downloads the newest package with +the preferred quality/state ({config preferred_state}). + +To retrieve Package version 1.1, use "Package-1.1," to retrieve +Package state beta, use "Package-beta." To retrieve an uncompressed +file, append .tar (make sure there is no file by the same name first) + +To download a package from another channel, prefix with the channel name like +"channel/Package" + +More than one package may be specified at once. It is ok to mix these +four ways of specifying packages. +'), + 'upgrade' => array( + 'summary' => 'Upgrade Package', + 'function' => 'doInstall', + 'shortcut' => 'up', + 'options' => array( + 'channel' => array( + 'shortopt' => 'c', + 'doc' => 'upgrade packages from a specific channel', + 'arg' => 'CHAN', + ), + 'force' => array( + 'shortopt' => 'f', + 'doc' => 'overwrite newer installed packages', + ), + 'loose' => array( + 'shortopt' => 'l', + 'doc' => 'do not check for recommended dependency version', + ), + 'nodeps' => array( + 'shortopt' => 'n', + 'doc' => 'ignore dependencies, upgrade anyway', + ), + 'register-only' => array( + 'shortopt' => 'r', + 'doc' => 'do not install files, only register the package as upgraded', + ), + 'nobuild' => array( + 'shortopt' => 'B', + 'doc' => 'don\'t build C extensions', + ), + 'nocompress' => array( + 'shortopt' => 'Z', + 'doc' => 'request uncompressed files when downloading', + ), + 'installroot' => array( + 'shortopt' => 'R', + 'arg' => 'DIR', + 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)', + ), + 'ignore-errors' => array( + 'doc' => 'force install even if there were errors', + ), + 'alldeps' => array( + 'shortopt' => 'a', + 'doc' => 'install all required and optional dependencies', + ), + 'onlyreqdeps' => array( + 'shortopt' => 'o', + 'doc' => 'install all required dependencies', + ), + 'offline' => array( + 'shortopt' => 'O', + 'doc' => 'do not attempt to download any urls or contact channels', + ), + 'pretend' => array( + 'shortopt' => 'p', + 'doc' => 'Only list the packages that would be downloaded', + ), + ), + 'doc' => ' ... +Upgrades one or more PEAR packages. See documentation for the +"install" command for ways to specify a package. + +When upgrading, your package will be updated if the provided new +package has a higher version number (use the -f option if you need to +upgrade anyway). + +More than one package may be specified at once. +'), + 'upgrade-all' => array( + 'summary' => 'Upgrade All Packages [Deprecated in favor of calling upgrade with no parameters]', + 'function' => 'doUpgradeAll', + 'shortcut' => 'ua', + 'options' => array( + 'channel' => array( + 'shortopt' => 'c', + 'doc' => 'upgrade packages from a specific channel', + 'arg' => 'CHAN', + ), + 'nodeps' => array( + 'shortopt' => 'n', + 'doc' => 'ignore dependencies, upgrade anyway', + ), + 'register-only' => array( + 'shortopt' => 'r', + 'doc' => 'do not install files, only register the package as upgraded', + ), + 'nobuild' => array( + 'shortopt' => 'B', + 'doc' => 'don\'t build C extensions', + ), + 'nocompress' => array( + 'shortopt' => 'Z', + 'doc' => 'request uncompressed files when downloading', + ), + 'installroot' => array( + 'shortopt' => 'R', + 'arg' => 'DIR', + 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM', + ), + 'ignore-errors' => array( + 'doc' => 'force install even if there were errors', + ), + 'loose' => array( + 'doc' => 'do not check for recommended dependency version', + ), + ), + 'doc' => ' +WARNING: This function is deprecated in favor of using the upgrade command with no params + +Upgrades all packages that have a newer release available. Upgrades are +done only if there is a release available of the state specified in +"preferred_state" (currently {config preferred_state}), or a state considered +more stable. +'), + 'uninstall' => array( + 'summary' => 'Un-install Package', + 'function' => 'doUninstall', + 'shortcut' => 'un', + 'options' => array( + 'nodeps' => array( + 'shortopt' => 'n', + 'doc' => 'ignore dependencies, uninstall anyway', + ), + 'register-only' => array( + 'shortopt' => 'r', + 'doc' => 'do not remove files, only register the packages as not installed', + ), + 'installroot' => array( + 'shortopt' => 'R', + 'arg' => 'DIR', + 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)', + ), + 'ignore-errors' => array( + 'doc' => 'force install even if there were errors', + ), + 'offline' => array( + 'shortopt' => 'O', + 'doc' => 'do not attempt to uninstall remotely', + ), + ), + 'doc' => '[channel/] ... +Uninstalls one or more PEAR packages. More than one package may be +specified at once. Prefix with channel name to uninstall from a +channel not in your default channel ({config default_channel}) +'), + 'bundle' => array( + 'summary' => 'Unpacks a Pecl Package', + 'function' => 'doBundle', + 'shortcut' => 'bun', + 'options' => array( + 'destination' => array( + 'shortopt' => 'd', + 'arg' => 'DIR', + 'doc' => 'Optional destination directory for unpacking (defaults to current path or "ext" if exists)', + ), + 'force' => array( + 'shortopt' => 'f', + 'doc' => 'Force the unpacking even if there were errors in the package', + ), + ), + 'doc' => ' +Unpacks a Pecl Package into the selected location. It will download the +package if needed. +'), + 'run-scripts' => array( + 'summary' => 'Run Post-Install Scripts bundled with a package', + 'function' => 'doRunScripts', + 'shortcut' => 'rs', + 'options' => array( + ), + 'doc' => ' +Run post-installation scripts in package , if any exist. +'), + ); + + // }}} + // {{{ constructor + + /** + * PEAR_Command_Install constructor. + * + * @access public + */ + function PEAR_Command_Install(&$ui, &$config) + { + parent::PEAR_Command_Common($ui, $config); + } + + // }}} + + /** + * For unit testing purposes + */ + function &getDownloader(&$ui, $options, &$config) + { + if (!class_exists('PEAR_Downloader')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Downloader.php'; + } + $a = &new PEAR_Downloader($ui, $options, $config); + return $a; + } + + /** + * For unit testing purposes + */ + function &getInstaller(&$ui) + { + if (!class_exists('PEAR_Installer')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Installer.php'; + } + $a = &new PEAR_Installer($ui); + return $a; + } + + function enableExtension($binaries, $type) + { + if (!($phpini = $this->config->get('php_ini', null, 'pear.php.net'))) { + return PEAR::raiseError('configuration option "php_ini" is not set to php.ini location'); + } + $ini = $this->_parseIni($phpini); + if (PEAR::isError($ini)) { + return $ini; + } + $line = 0; + if ($type == 'extsrc' || $type == 'extbin') { + $search = 'extensions'; + $enable = 'extension'; + } else { + $search = 'zend_extensions'; + ob_start(); + phpinfo(INFO_GENERAL); + $info = ob_get_contents(); + ob_end_clean(); + $debug = function_exists('leak') ? '_debug' : ''; + $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : ''; + $enable = 'zend_extension' . $debug . $ts; + } + foreach ($ini[$search] as $line => $extension) { + if (in_array($extension, $binaries, true) || in_array( + $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) { + // already enabled - assume if one is, all are + return true; + } + } + if ($line) { + $newini = array_slice($ini['all'], 0, $line); + } else { + $newini = array(); + } + foreach ($binaries as $binary) { + if ($ini['extension_dir']) { + $binary = basename($binary); + } + $newini[] = $enable . '="' . $binary . '"' . (OS_UNIX ? "\n" : "\r\n"); + } + $newini = array_merge($newini, array_slice($ini['all'], $line)); + $fp = @fopen($phpini, 'wb'); + if (!$fp) { + return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing'); + } + foreach ($newini as $line) { + fwrite($fp, $line); + } + fclose($fp); + return true; + } + + function disableExtension($binaries, $type) + { + if (!($phpini = $this->config->get('php_ini', null, 'pear.php.net'))) { + return PEAR::raiseError('configuration option "php_ini" is not set to php.ini location'); + } + $ini = $this->_parseIni($phpini); + if (PEAR::isError($ini)) { + return $ini; + } + $line = 0; + if ($type == 'extsrc' || $type == 'extbin') { + $search = 'extensions'; + $enable = 'extension'; + } else { + $search = 'zend_extensions'; + ob_start(); + phpinfo(INFO_GENERAL); + $info = ob_get_contents(); + ob_end_clean(); + $debug = function_exists('leak') ? '_debug' : ''; + $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : ''; + $enable = 'zend_extension' . $debug . $ts; + } + $found = false; + foreach ($ini[$search] as $line => $extension) { + if (in_array($extension, $binaries, true) || in_array( + $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) { + $found = true; + break; + } + } + if (!$found) { + // not enabled + return true; + } + $fp = @fopen($phpini, 'wb'); + if (!$fp) { + return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing'); + } + if ($line) { + $newini = array_slice($ini['all'], 0, $line); + // delete the enable line + $newini = array_merge($newini, array_slice($ini['all'], $line + 1)); + } else { + $newini = array_slice($ini['all'], 1); + } + foreach ($newini as $line) { + fwrite($fp, $line); + } + fclose($fp); + return true; + } + + function _parseIni($filename) + { + if (!file_exists($filename)) { + return PEAR::raiseError('php.ini "' . $filename . '" does not exist'); + } + + if (filesize($filename) > 300000) { + return PEAR::raiseError('php.ini "' . $filename . '" is too large, aborting'); + } + + ob_start(); + phpinfo(INFO_GENERAL); + $info = ob_get_contents(); + ob_end_clean(); + $debug = function_exists('leak') ? '_debug' : ''; + $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : ''; + $zend_extension_line = 'zend_extension' . $debug . $ts; + $all = @file($filename); + if (!$all) { + return PEAR::raiseError('php.ini "' . $filename .'" could not be read'); + } + $zend_extensions = $extensions = array(); + // assume this is right, but pull from the php.ini if it is found + $extension_dir = ini_get('extension_dir'); + foreach ($all as $linenum => $line) { + $line = trim($line); + if (!$line) { + continue; + } + if ($line[0] == ';') { + continue; + } + if (strtolower(substr($line, 0, 13)) == 'extension_dir') { + $line = trim(substr($line, 13)); + if ($line[0] == '=') { + $x = trim(substr($line, 1)); + $x = explode(';', $x); + $extension_dir = str_replace('"', '', array_shift($x)); + continue; + } + } + if (strtolower(substr($line, 0, 9)) == 'extension') { + $line = trim(substr($line, 9)); + if ($line[0] == '=') { + $x = trim(substr($line, 1)); + $x = explode(';', $x); + $extensions[$linenum] = str_replace('"', '', array_shift($x)); + continue; + } + } + if (strtolower(substr($line, 0, strlen($zend_extension_line))) == + $zend_extension_line) { + $line = trim(substr($line, strlen($zend_extension_line))); + if ($line[0] == '=') { + $x = trim(substr($line, 1)); + $x = explode(';', $x); + $zend_extensions[$linenum] = str_replace('"', '', array_shift($x)); + continue; + } + } + } + return array( + 'extensions' => $extensions, + 'zend_extensions' => $zend_extensions, + 'extension_dir' => $extension_dir, + 'all' => $all, + ); + } + + // {{{ doInstall() + + function doInstall($command, $options, $params) + { + if (!class_exists('PEAR_PackageFile')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile.php'; + } + + if (isset($options['installroot']) && isset($options['packagingroot'])) { + return $this->raiseError('ERROR: cannot use both --installroot and --packagingroot'); + } + + $reg = &$this->config->getRegistry(); + $channel = isset($options['channel']) ? $options['channel'] : $this->config->get('default_channel'); + if (!$reg->channelExists($channel)) { + return $this->raiseError('Channel "' . $channel . '" does not exist'); + } + + if (empty($this->installer)) { + $this->installer = &$this->getInstaller($this->ui); + } + + if ($command == 'upgrade' || $command == 'upgrade-all') { + // If people run the upgrade command but pass nothing, emulate a upgrade-all + if ($command == 'upgrade' && empty($params)) { + return $this->doUpgradeAll($command, $options, $params); + } + $options['upgrade'] = true; + } else { + $packages = $params; + } + + $instreg = &$reg; // instreg used to check if package is installed + if (isset($options['packagingroot']) && !isset($options['upgrade'])) { + $packrootphp_dir = $this->installer->_prependPath( + $this->config->get('php_dir', null, 'pear.php.net'), + $options['packagingroot']); + $instreg = new PEAR_Registry($packrootphp_dir); // other instreg! + + if ($this->config->get('verbose') > 2) { + $this->ui->outputData('using package root: ' . $options['packagingroot']); + } + } + + $abstractpackages = $otherpackages = array(); + // parse params + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + + foreach ($params as $param) { + if (strpos($param, 'http://') === 0) { + $otherpackages[] = $param; + continue; + } + + if (strpos($param, 'channel://') === false && @file_exists($param)) { + if (isset($options['force'])) { + $otherpackages[] = $param; + continue; + } + + $pkg = new PEAR_PackageFile($this->config); + $pf = $pkg->fromAnyFile($param, PEAR_VALIDATE_DOWNLOADING); + if (PEAR::isError($pf)) { + $otherpackages[] = $param; + continue; + } + + $exists = $reg->packageExists($pf->getPackage(), $pf->getChannel()); + $pversion = $reg->packageInfo($pf->getPackage(), 'version', $pf->getChannel()); + $version_compare = version_compare($pf->getVersion(), $pversion, '<='); + if ($exists && $version_compare) { + if ($this->config->get('verbose')) { + $this->ui->outputData('Ignoring installed package ' . + $reg->parsedPackageNameToString( + array('package' => $pf->getPackage(), + 'channel' => $pf->getChannel()), true)); + } + continue; + } + $otherpackages[] = $param; + continue; + } + + $e = $reg->parsePackageName($param, $channel); + if (PEAR::isError($e)) { + $otherpackages[] = $param; + } else { + $abstractpackages[] = $e; + } + } + PEAR::staticPopErrorHandling(); + + // if there are any local package .tgz or remote static url, we can't + // filter. The filter only works for abstract packages + if (count($abstractpackages) && !isset($options['force'])) { + // when not being forced, only do necessary upgrades/installs + if (isset($options['upgrade'])) { + $abstractpackages = $this->_filterUptodatePackages($abstractpackages, $command); + } else { + $count = count($abstractpackages); + foreach ($abstractpackages as $i => $package) { + if (isset($package['group'])) { + // do not filter out install groups + continue; + } + + if ($instreg->packageExists($package['package'], $package['channel'])) { + if ($count > 1) { + if ($this->config->get('verbose')) { + $this->ui->outputData('Ignoring installed package ' . + $reg->parsedPackageNameToString($package, true)); + } + unset($abstractpackages[$i]); + } elseif ($count === 1) { + // Lets try to upgrade it since it's already installed + $options['upgrade'] = true; + } + } + } + } + $abstractpackages = + array_map(array($reg, 'parsedPackageNameToString'), $abstractpackages); + } elseif (count($abstractpackages)) { + $abstractpackages = + array_map(array($reg, 'parsedPackageNameToString'), $abstractpackages); + } + + $packages = array_merge($abstractpackages, $otherpackages); + if (!count($packages)) { + $c = ''; + if (isset($options['channel'])){ + $c .= ' in channel "' . $options['channel'] . '"'; + } + $this->ui->outputData('Nothing to ' . $command . $c); + return true; + } - Remove custom XML_Util class in favor of using upstream XML_Util package as dependency + $this->downloader = &$this->getDownloader($this->ui, $options, $this->config); + $errors = $downloaded = $binaries = array(); + $downloaded = &$this->downloader->download($packages); + if (PEAR::isError($downloaded)) { + return $this->raiseError($downloaded); + } -RC1 Release Notes: - * Fix Bug #14331: pear cvstag only works from inside the package directory [dufuz] - * Fix Bug #16045: E_Notice: Undefined index: channel in PEAR/DependencyDB.php [dufuz] + $errors = $this->downloader->getErrorMsgs(); + if (count($errors)) { + $err = array(); + $err['data'] = array(); + foreach ($errors as $error) { + if ($error !== null) { + $err['data'][] = array($error); + } + } - * Implemented Request #11230: better error message when mirror not in channel.xml file [dufuz] - * Implemented Request #13150: Add support for following HTTP 302 redirects [dufuz] + if (!empty($err['data'])) { + $err['headline'] = 'Install Errors'; + $this->ui->outputData($err); + } -Alpha1 Release Notes: - * Implement Request #10373: if pref_state=stable and installed package=beta, allow up to latest beta version [dufuz] - * Implement Request #10581: login / logout should map to channel-login / channel-logout [dufuz] - * Implement Request #10825: Only display the "invalid or missing package file"-error if it makes sense [dufuz] - * Implement Request #11170: script to generate Command/[command].xml [dufuz] - * Implement Request #11176: improve channel ... has updated its protocols message [dufuz] - * Implement Request #12706: pear list -a hard to read [dufuz] - * Implement Request #11353: upgrade-all and upgrade commands to upgrade within the same stability level [dufuz] - * Implement Request #13015: Add https discovery for channel.xml [dufuz / initial patch by Martin Roos] - * Implement Request #13927: install-pear.php should have option to set www_dir [timj] - * Implement Request #14324: Make the pear install command behave similar to apt-get [dufuz] - * Implement Request #14325: make pear upgrade with no params behave like pear upgrade-all [dufuz] - - upgrade-all can be considered deprecated in favor of calling upgrade with no parameters to replicate - better what other package managers are doing. upgrade-all will still work as intended. - * Implement Request #14504: add a channel parameter support to the upgrade function [dufuz] - - Options -c ezc and --channel=ezc got added to upgrade and upgrade-all to allow for - channel specific upgrades - * Implement Request #14556: install-pear-nozlib.phar should get download_dir config and other options [cweiske] - * Implement Request #15566: Add doc.php.net as a default channel [dufuz / saltybeagle] + if (!count($downloaded)) { + return $this->raiseError("$command failed"); + } + } - * Fix PHP Bug #43857: --program-suffix not always reflected everywhere [cellog] - * Fix PHP Bug #47323: strotime warnings in make install [dufuz] + $data = array( + 'headline' => 'Packages that would be Installed' + ); - * Fix Bug #13908: pear info command and maintainers inactive not mentioned [dufuz] - * Fix Bug #13926: install-pear.php does not set cfg_dir if -d option set with no -c option [timj] - * Fix Bug #13943: tests fail when php.exe path contains spaces [dufuz / jorrit] - * Fix Bug #13953: config-set/config-show with channel alias fail [cellog] - * Fix Bug #13958: When a phpt tests exit() or die() xdebug coverage is not generated, patch by izi (David Jean Louis) [izi / dufuz] - * Fix Bug #14041: Unpredictable unit test processing sequence [dufuz] - * Fix Bug #14140: Strict warning not suppressed in the shutdown function [dufuz] - * Fix Bug #14210: pear list -ia brings warnings [dufuz] - * Fix Bug #14274: PEAR packager mangles package.xml encoding, then complains about it [dufuz] - * Fix Bug #14287: cannot upgrade from stable to beta via -beta when config is set to stable [dufuz] - * Fix Bug #14300: Package files themselves can not be served over https [dufuz / initial patch by Martin Roos] - * Fix Bug #14437: openbasedir warning when loading config [dufuz] - * Fix Bug #14558: PackageFile.php creates tmp directory outside configured temp_dir [cweiske] - * Fix Bug #14947: downloadHttp() is missing Host part of the HTTP Request when using Proxy [ifeghali] - * Fix Bug #14977: PEAR/Frontend.php doesn't require_once PEAR.php [dufuz] - * Fix Bug #15750: Unreachable code in PEAR_Downloader [dufuz] - * Fix Bug #15979: Package files incorrectly removed when splitting a package into multiple pkgs [dufuz] - * Fix Bug #15914: pear upgrade installs different version if desired version not found [dufuz] + if (isset($options['pretend'])) { + foreach ($downloaded as $package) { + $data['data'][] = array($reg->parsedPackageNameToString($package->getParsedPackage())); + } + $this->ui->outputData($data, 'pretend'); + return true; + } - NOTE! - Functions that have been deprecated for 3+ years in PEAR_Common, please take a moment - to migrate over to one of the alternatives that have ben provided: - * PEAR_Common->downloadHttp (use PEAR_Downloader->downloadHttp instead) - * PEAR_Common->infoFromTgzFile (use PEAR_PackageFile->fromTgzFile instead) - * PEAR_Common->infoFromDescriptionFile (use PEAR_PackageFile->fromPackageFile instead) - * PEAR_Common->infoFromString (use PEAR_PackageFile->fromXmlstring instead) - * PEAR_Common->infoFromArray (use PEAR_PackageFile->fromAnyFile instead) - * PEAR_Common->xmlFromInfo (use a PEAR_PackageFile_v* object's generator instead) - * PEAR_Common->validatePackageInfo (use the validation of PEAR_PackageFile objects) - * PEAR_Common->analyzeSourceCode (use a PEAR_PackageFile_v* object instead) - * PEAR_Common->detectDependencies (use PEAR_Downloader_Package->detectDependencies instead) - * PEAR_Common->buildProvidesArray (use PEAR_PackageFile_v1->_buildProvidesArray or - PEAR_PackageFile_v2_Validator->_buildProvidesArray) + $this->installer->setOptions($options); + $this->installer->sortPackagesForInstall($downloaded); + if (PEAR::isError($err = $this->installer->setDownloadedPackages($downloaded))) { + $this->raiseError($err->getMessage()); + return true; + } - PHP 4.4 and 5.1.6 are now the minimum PHP requirements, for brave souls - pear upgrade -f PEAR will allow people with lower versions - to upgrade to this release but no guarantees will be made that it will work properly. + $binaries = $extrainfo = array(); + foreach ($downloaded as $param) { + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $info = $this->installer->install($param, $options); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($info)) { + $oldinfo = $info; + $pkg = &$param->getPackageFile(); + if ($info->getCode() != PEAR_INSTALLER_NOBINARY) { + if (!($info = $pkg->installBinary($this->installer))) { + $this->ui->outputData('ERROR: ' .$oldinfo->getMessage()); + continue; + } + + // we just installed a different package than requested, + // let's change the param and info so that the rest of this works + $param = $info[0]; + $info = $info[1]; + } + } + + if (!is_array($info)) { + return $this->raiseError("$command failed"); + } + + if ($param->getPackageType() == 'extsrc' || + $param->getPackageType() == 'extbin' || + $param->getPackageType() == 'zendextsrc' || + $param->getPackageType() == 'zendextbin') { + $pkg = &$param->getPackageFile(); + if ($instbin = $pkg->getInstalledBinary()) { + $instpkg = &$instreg->getPackage($instbin, $pkg->getChannel()); + } else { + $instpkg = &$instreg->getPackage($pkg->getPackage(), $pkg->getChannel()); + } + + foreach ($instpkg->getFilelist() as $name => $atts) { + $pinfo = pathinfo($atts['installed_as']); + if (!isset($pinfo['extension']) || + in_array($pinfo['extension'], array('c', 'h'))) { + continue; // make sure we don't match php_blah.h + } + + if ((strpos($pinfo['basename'], 'php_') === 0 && + $pinfo['extension'] == 'dll') || + // most unices + $pinfo['extension'] == 'so' || + // hp-ux + $pinfo['extension'] == 'sl') { + $binaries[] = array($atts['installed_as'], $pinfo); + break; + } + } + + if (count($binaries)) { + foreach ($binaries as $pinfo) { + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $ret = $this->enableExtension(array($pinfo[0]), $param->getPackageType()); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($ret)) { + $extrainfo[] = $ret->getMessage(); + if ($param->getPackageType() == 'extsrc' || + $param->getPackageType() == 'extbin') { + $exttype = 'extension'; + } else { + ob_start(); + phpinfo(INFO_GENERAL); + $info = ob_get_contents(); + ob_end_clean(); + $debug = function_exists('leak') ? '_debug' : ''; + $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : ''; + $exttype = 'zend_extension' . $debug . $ts; + } + $extrainfo[] = 'You should add "' . $exttype . '=' . + $pinfo[1]['basename'] . '" to php.ini'; + } else { + $extrainfo[] = 'Extension ' . $instpkg->getProvidesExtension() . + ' enabled in php.ini'; + } + } + } + } + + if ($this->config->get('verbose') > 0) { + $chan = $param->getChannel(); + $label = $reg->parsedPackageNameToString( + array( + 'channel' => $chan, + 'package' => $param->getPackage(), + 'version' => $param->getVersion(), + )); + $out = array('data' => "$command ok: $label"); + if (isset($info['release_warnings'])) { + $out['release_warnings'] = $info['release_warnings']; + } + $this->ui->outputData($out, $command); + + if (!isset($options['register-only']) && !isset($options['offline'])) { + if ($this->config->isDefinedLayer('ftp')) { + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $info = $this->installer->ftpInstall($param); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($info)) { + $this->ui->outputData($info->getMessage()); + $this->ui->outputData("remote install failed: $label"); + } else { + $this->ui->outputData("remote install ok: $label"); + } + } + } + } + + $deps = $param->getDeps(); + if ($deps) { + if (isset($deps['group'])) { + $groups = $deps['group']; + if (!isset($groups[0])) { + $groups = array($groups); + } + + foreach ($groups as $group) { + if ($group['attribs']['name'] == 'default') { + // default group is always installed, unless the user + // explicitly chooses to install another group + continue; + } + $extrainfo[] = $param->getPackage() . ': Optional feature ' . + $group['attribs']['name'] . ' available (' . + $group['attribs']['hint'] . ')'; + } + + $extrainfo[] = $param->getPackage() . + ': To install optional features use "pear install ' . + $reg->parsedPackageNameToString( + array('package' => $param->getPackage(), + 'channel' => $param->getChannel()), true) . + '#featurename"'; + } + } + + $pkg = &$instreg->getPackage($param->getPackage(), $param->getChannel()); + // $pkg may be NULL if install is a 'fake' install via --packagingroot + if (is_object($pkg)) { + $pkg->setConfig($this->config); + if ($list = $pkg->listPostinstallScripts()) { + $pn = $reg->parsedPackageNameToString(array('channel' => + $param->getChannel(), 'package' => $param->getPackage()), true); + $extrainfo[] = $pn . ' has post-install scripts:'; + foreach ($list as $file) { + $extrainfo[] = $file; + } + $extrainfo[] = $param->getPackage() . + ': Use "pear run-scripts ' . $pn . '" to finish setup.'; + $extrainfo[] = 'DO NOT RUN SCRIPTS FROM UNTRUSTED SOURCES'; + } + } + } + + if (count($extrainfo)) { + foreach ($extrainfo as $info) { + $this->ui->outputData($info); + } + } + + return true; + } + + // }}} + // {{{ doUpgradeAll() + + function doUpgradeAll($command, $options, $params) + { + $reg = &$this->config->getRegistry(); + $upgrade = array(); + + if (isset($options['channel'])) { + $channels = array($options['channel']); + } else { + $channels = $reg->listChannels(); + } + + foreach ($channels as $channel) { + if ($channel == '__uri') { + continue; + } + + // parse name with channel + foreach ($reg->listPackages($channel) as $name) { + $upgrade[] = $reg->parsedPackageNameToString(array( + 'channel' => $channel, + 'package' => $name + )); + } + } + + $err = $this->doInstall($command, $options, $upgrade); + if (PEAR::isError($err)) { + $this->ui->outputData($err->getMessage(), $command); + } + } + + // }}} + // {{{ doUninstall() + + function doUninstall($command, $options, $params) + { + if (count($params) < 1) { + return $this->raiseError("Please supply the package(s) you want to uninstall"); + } + + if (empty($this->installer)) { + $this->installer = &$this->getInstaller($this->ui); + } + + if (isset($options['remoteconfig'])) { + $e = $this->config->readFTPConfigFile($options['remoteconfig']); + if (!PEAR::isError($e)) { + $this->installer->setConfig($this->config); + } + } + + $reg = &$this->config->getRegistry(); + $newparams = array(); + $binaries = array(); + $badparams = array(); + foreach ($params as $pkg) { + $channel = $this->config->get('default_channel'); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $parsed = $reg->parsePackageName($pkg, $channel); + PEAR::staticPopErrorHandling(); + if (!$parsed || PEAR::isError($parsed)) { + $badparams[] = $pkg; + continue; + } + $package = $parsed['package']; + $channel = $parsed['channel']; + $info = &$reg->getPackage($package, $channel); + if ($info === null && + ($channel == 'pear.php.net' || $channel == 'pecl.php.net')) { + // make sure this isn't a package that has flipped from pear to pecl but + // used a package.xml 1.0 + $testc = ($channel == 'pear.php.net') ? 'pecl.php.net' : 'pear.php.net'; + $info = &$reg->getPackage($package, $testc); + if ($info !== null) { + $channel = $testc; + } + } + if ($info === null) { + $badparams[] = $pkg; + } else { + $newparams[] = &$info; + // check for binary packages (this is an alias for those packages if so) + if ($installedbinary = $info->getInstalledBinary()) { + $this->ui->log('adding binary package ' . + $reg->parsedPackageNameToString(array('channel' => $channel, + 'package' => $installedbinary), true)); + $newparams[] = &$reg->getPackage($installedbinary, $channel); + } + // add the contents of a dependency group to the list of installed packages + if (isset($parsed['group'])) { + $group = $info->getDependencyGroup($parsed['group']); + if ($group) { + $installed = $reg->getInstalledGroup($group); + if ($installed) { + foreach ($installed as $i => $p) { + $newparams[] = &$installed[$i]; + } + } + } + } + } + } + $err = $this->installer->sortPackagesForUninstall($newparams); + if (PEAR::isError($err)) { + $this->ui->outputData($err->getMessage(), $command); + return true; + } + $params = $newparams; + // twist this to use it to check on whether dependent packages are also being uninstalled + // for circular dependencies like subpackages + $this->installer->setUninstallPackages($newparams); + $params = array_merge($params, $badparams); + $binaries = array(); + foreach ($params as $pkg) { + $this->installer->pushErrorHandling(PEAR_ERROR_RETURN); + if ($err = $this->installer->uninstall($pkg, $options)) { + $this->installer->popErrorHandling(); + if (PEAR::isError($err)) { + $this->ui->outputData($err->getMessage(), $command); + continue; + } + if ($pkg->getPackageType() == 'extsrc' || + $pkg->getPackageType() == 'extbin' || + $pkg->getPackageType() == 'zendextsrc' || + $pkg->getPackageType() == 'zendextbin') { + if ($instbin = $pkg->getInstalledBinary()) { + continue; // this will be uninstalled later + } + + foreach ($pkg->getFilelist() as $name => $atts) { + $pinfo = pathinfo($atts['installed_as']); + if (!isset($pinfo['extension']) || + in_array($pinfo['extension'], array('c', 'h'))) { + continue; // make sure we don't match php_blah.h + } + if ((strpos($pinfo['basename'], 'php_') === 0 && + $pinfo['extension'] == 'dll') || + // most unices + $pinfo['extension'] == 'so' || + // hp-ux + $pinfo['extension'] == 'sl') { + $binaries[] = array($atts['installed_as'], $pinfo); + break; + } + } + if (count($binaries)) { + foreach ($binaries as $pinfo) { + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $ret = $this->disableExtension(array($pinfo[0]), $pkg->getPackageType()); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($ret)) { + $extrainfo[] = $ret->getMessage(); + if ($pkg->getPackageType() == 'extsrc' || + $pkg->getPackageType() == 'extbin') { + $exttype = 'extension'; + } else { + ob_start(); + phpinfo(INFO_GENERAL); + $info = ob_get_contents(); + ob_end_clean(); + $debug = function_exists('leak') ? '_debug' : ''; + $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : ''; + $exttype = 'zend_extension' . $debug . $ts; + } + $this->ui->outputData('Unable to remove "' . $exttype . '=' . + $pinfo[1]['basename'] . '" from php.ini', $command); + } else { + $this->ui->outputData('Extension ' . $pkg->getProvidesExtension() . + ' disabled in php.ini', $command); + } + } + } + } + $savepkg = $pkg; + if ($this->config->get('verbose') > 0) { + if (is_object($pkg)) { + $pkg = $reg->parsedPackageNameToString($pkg); + } + $this->ui->outputData("uninstall ok: $pkg", $command); + } + if (!isset($options['offline']) && is_object($savepkg) && + defined('PEAR_REMOTEINSTALL_OK')) { + if ($this->config->isDefinedLayer('ftp')) { + $this->installer->pushErrorHandling(PEAR_ERROR_RETURN); + $info = $this->installer->ftpUninstall($savepkg); + $this->installer->popErrorHandling(); + if (PEAR::isError($info)) { + $this->ui->outputData($info->getMessage()); + $this->ui->outputData("remote uninstall failed: $pkg"); + } else { + $this->ui->outputData("remote uninstall ok: $pkg"); + } + } + } + } else { + $this->installer->popErrorHandling(); + if (!is_object($pkg)) { + return $this->raiseError("uninstall failed: $pkg"); + } + $pkg = $reg->parsedPackageNameToString($pkg); + } + } + + return true; + } + + // }}} + + + // }}} + // {{{ doBundle() + /* + (cox) It just downloads and untars the package, does not do + any check that the PEAR_Installer::_installFile() does. + */ + + function doBundle($command, $options, $params) + { + $opts = array( + 'force' => true, + 'nodeps' => true, + 'soft' => true, + 'downloadonly' => true + ); + $downloader = &$this->getDownloader($this->ui, $opts, $this->config); + $reg = &$this->config->getRegistry(); + if (count($params) < 1) { + return $this->raiseError("Please supply the package you want to bundle"); + } + + if (isset($options['destination'])) { + if (!is_dir($options['destination'])) { + System::mkdir('-p ' . $options['destination']); + } + $dest = realpath($options['destination']); + } else { + $pwd = getcwd(); + $dir = $pwd . DIRECTORY_SEPARATOR . 'ext'; + $dest = is_dir($dir) ? $dir : $pwd; + } + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $err = $downloader->setDownloadDir($dest); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($err)) { + return PEAR::raiseError('download directory "' . $dest . + '" is not writeable.'); + } + $result = &$downloader->download(array($params[0])); + if (PEAR::isError($result)) { + return $result; + } + if (!isset($result[0])) { + return $this->raiseError('unable to unpack ' . $params[0]); + } + $pkgfile = &$result[0]->getPackageFile(); + $pkgname = $pkgfile->getName(); + $pkgversion = $pkgfile->getVersion(); - Support for XML RPC channels has been dropped - The only ones that used it - (pear.php.net and pecl.php.net) have used the REST interface for years now. - SOAP support also removed as it was only proof of concept. + // Unpacking ------------------------------------------------- + $dest .= DIRECTORY_SEPARATOR . $pkgname; + $orig = $pkgname . '-' . $pkgversion; - Move codebase from the PHP License to New BSD 2 clause license - - - - - - * @author Stig Bakken - * @author Tomas V.V.Cox - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: PEAR.php,v 1.111 2009/04/08 23:32:04 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ + $tar = &new Archive_Tar($pkgfile->getArchiveFile()); + if (!$tar->extractModify($dest, $orig)) { + return $this->raiseError('unable to unpack ' . $pkgfile->getArchiveFile()); + } + $this->ui->outputData("Package ready at '$dest'"); + // }}} + } -/**#@+ - * ERROR constants - */ -define('PEAR_ERROR_RETURN', 1); -define('PEAR_ERROR_PRINT', 2); -define('PEAR_ERROR_TRIGGER', 4); -define('PEAR_ERROR_DIE', 8); -define('PEAR_ERROR_CALLBACK', 16); -/** - * WARNING: obsolete - * @deprecated - */ -define('PEAR_ERROR_EXCEPTION', 32); -/**#@-*/ -define('PEAR_ZE2', (function_exists('version_compare') && - version_compare(zend_version(), "2-dev", "ge"))); + // }}} -if (substr(PHP_OS, 0, 3) == 'WIN') { - define('OS_WINDOWS', true); - define('OS_UNIX', false); - define('PEAR_OS', 'Windows'); -} else { - define('OS_WINDOWS', false); - define('OS_UNIX', true); - define('PEAR_OS', 'Unix'); // blatant assumption -} + function doRunScripts($command, $options, $params) + { + if (!isset($params[0])) { + return $this->raiseError('run-scripts expects 1 parameter: a package name'); + } -$GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_RETURN; -$GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE; -$GLOBALS['_PEAR_destructor_object_list'] = array(); -$GLOBALS['_PEAR_shutdown_funcs'] = array(); -$GLOBALS['_PEAR_error_handler_stack'] = array(); + $reg = &$this->config->getRegistry(); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel')); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($parsed)) { + return $this->raiseError($parsed); + } -@ini_set('track_errors', true); + $package = &$reg->getPackage($parsed['package'], $parsed['channel']); + if (!is_object($package)) { + return $this->raiseError('Could not retrieve package "' . $params[0] . '" from registry'); + } -/** - * Base class for other PEAR classes. Provides rudimentary - * emulation of destructors. - * - * If you want a destructor in your class, inherit PEAR and make a - * destructor method called _yourclassname (same name as the - * constructor, but with a "_" prefix). Also, in your constructor you - * have to call the PEAR constructor: $this->PEAR();. - * The destructor method will be called without parameters. Note that - * at in some SAPI implementations (such as Apache), any output during - * the request shutdown (in which destructors are called) seems to be - * discarded. If you need to get any debug information from your - * destructor, use error_log(), syslog() or something similar. - * - * IMPORTANT! To use the emulated destructors you need to create the - * objects by reference: $obj =& new PEAR_child; - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Tomas V.V. Cox - * @author Greg Beaver - * @copyright 1997-2006 The PHP Group - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @see PEAR_Error - * @since Class available since PHP 4.0.2 - * @link http://pear.php.net/manual/en/core.pear.php#core.pear.pear - */ -class PEAR -{ - // {{{ properties + $package->setConfig($this->config); + $package->runPostinstallScripts(); + $this->ui->outputData('Install scripts complete', $command); + return true; + } /** - * Whether to enable internal debug messages. + * Given a list of packages, filter out those ones that are already up to date * - * @var bool - * @access private + * @param $packages: packages, in parsed array format ! + * @return list of packages that can be upgraded */ - var $_debug = false; + function _filterUptodatePackages($packages, $command) + { + $reg = &$this->config->getRegistry(); + $latestReleases = array(); - /** - * Default error mode for this object. - * - * @var int - * @access private - */ - var $_default_error_mode = null; + $ret = array(); + foreach ($packages as $package) { + if (isset($package['group'])) { + $ret[] = $package; + continue; + } - /** - * Default error options used for this object when error mode - * is PEAR_ERROR_TRIGGER. - * - * @var int - * @access private - */ - var $_default_error_options = null; + $channel = $package['channel']; + $name = $package['package']; + if (!$reg->packageExists($name, $channel)) { + $ret[] = $package; + continue; + } - /** - * Default error handler (callback) for this object, if error mode is - * PEAR_ERROR_CALLBACK. - * - * @var string - * @access private - */ - var $_default_error_handler = ''; + if (!isset($latestReleases[$channel])) { + // fill in cache for this channel + $chan = &$reg->getChannel($channel); + if (PEAR::isError($chan)) { + return $this->raiseError($chan); + } - /** - * Which class to use for error objects. - * - * @var string - * @access private - */ - var $_error_class = 'PEAR_Error'; + $base2 = false; + $preferred_mirror = $this->config->get('preferred_mirror', null, $channel); + if ($chan->supportsREST($preferred_mirror) && + ( + //($base2 = $chan->getBaseURL('REST1.4', $preferred_mirror)) || + ($base = $chan->getBaseURL('REST1.0', $preferred_mirror)) + ) + ) { + $dorest = true; + } - /** - * An array of expected errors. - * - * @var array - * @access private - */ - var $_expected_errors = array(); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + if (!isset($package['state'])) { + $state = $this->config->get('preferred_state', null, $channel); + } else { + $state = $package['state']; + } - // }}} + if ($dorest) { + if ($base2) { + $rest = &$this->config->getREST('1.4', array()); + $base = $base2; + } else { + $rest = &$this->config->getREST('1.0', array()); + } - // {{{ constructor + $installed = array_flip($reg->listPackages($channel)); + $latest = $rest->listLatestUpgrades($base, $state, $installed, $channel, $reg); + } - /** - * Constructor. Registers this object in - * $_PEAR_destructor_object_list for destructor emulation if a - * destructor object exists. - * - * @param string $error_class (optional) which class to use for - * error objects, defaults to PEAR_Error. - * @access public - * @return void - */ - function PEAR($error_class = null) - { - $classname = strtolower(get_class($this)); - if ($this->_debug) { - print "PEAR constructor called, class=$classname\n"; - } - if ($error_class !== null) { - $this->_error_class = $error_class; - } - while ($classname && strcasecmp($classname, "pear")) { - $destructor = "_$classname"; - if (method_exists($this, $destructor)) { - global $_PEAR_destructor_object_list; - $_PEAR_destructor_object_list[] = &$this; - if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { - register_shutdown_function("_PEAR_call_destructors"); - $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; + PEAR::staticPopErrorHandling(); + if (PEAR::isError($latest)) { + $this->ui->outputData('Error getting channel info from ' . $channel . + ': ' . $latest->getMessage()); + continue; } - break; - } else { - $classname = get_parent_class($classname); + + $latestReleases[$channel] = array_change_key_case($latest); } - } - } - // }}} - // {{{ destructor + // check package for latest release + $name_lower = strtolower($name); + if (isset($latestReleases[$channel][$name_lower])) { + // if not set, up to date + $inst_version = $reg->packageInfo($name, 'version', $channel); + $channel_version = $latestReleases[$channel][$name_lower]['version']; + if (version_compare($channel_version, $inst_version, 'le')) { + // installed version is up-to-date + continue; + } - /** - * Destructor (the emulated type of...). Does nothing right now, - * but is included for forward compatibility, so subclass - * destructors should always call it. - * - * See the note in the class desciption about output from - * destructors. - * - * @access public - * @return void - */ - function _PEAR() { - if ($this->_debug) { - printf("PEAR destructor called, class=%s\n", strtolower(get_class($this))); + // maintain BC + if ($command == 'upgrade-all') { + $this->ui->outputData(array('data' => 'Will upgrade ' . + $reg->parsedPackageNameToString($package)), $command); + } + $ret[] = $package; + } } - } - // }}} - // {{{ getStaticProperty() + return $ret; + } +} + + Install Package + doInstall + i + + + f + will overwrite newer installed packages + + + l + do not check for recommended dependency version + + + n + ignore dependencies, install anyway + + + r + do not install files, only register the package as installed + + + s + soft install, fail silently, or upgrade if already installed + + + B + don't build C extensions + + + Z + request uncompressed files when downloading + + + R + root directory used when installing files (ala PHP's INSTALL_ROOT), use packagingroot for RPM + DIR + + + P + root directory used when packaging files, like RPM packaging + DIR + + + + force install even if there were errors + + + a + install all required and optional dependencies + + + o + install all required dependencies + + + O + do not attempt to download any urls or contact channels + + + p + Only list the packages that would be downloaded + + + [channel/]<package> ... +Installs one or more PEAR packages. You can specify a package to +install in four ways: - /** - * If you have a class that's mostly/entirely static, and you need static - * properties, you can use this method to simulate them. Eg. in your method(s) - * do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar'); - * You MUST use a reference, or they will not persist! - * - * @access public - * @param string $class The calling classname, to prevent clashes - * @param string $var The variable to retrieve. - * @return mixed A reference to the variable. If not set it will be - * auto initialised to NULL. - */ - function &getStaticProperty($class, $var) - { - static $properties; - if (!isset($properties[$class])) { - $properties[$class] = array(); - } +"Package-1.0.tgz" : installs from a local file - if (!array_key_exists($var, $properties[$class])) { - $properties[$class][$var] = null; - } +"http://example.com/Package-1.0.tgz" : installs from +anywhere on the net. - return $properties[$class][$var]; - } +"package.xml" : installs the package described in +package.xml. Useful for testing, or for wrapping a PEAR package in +another package manager such as RPM. - // }}} - // {{{ registerShutdownFunc() +"Package[-version/state][.tar]" : queries your default channel's server +({config master_server}) and downloads the newest package with +the preferred quality/state ({config preferred_state}). - /** - * Use this function to register a shutdown method for static - * classes. - * - * @access public - * @param mixed $func The function name (or array of class/method) to call - * @param mixed $args The arguments to pass to the function - * @return void - */ - function registerShutdownFunc($func, $args = array()) - { - // if we are called statically, there is a potential - // that no shutdown func is registered. Bug #6445 - if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { - register_shutdown_function("_PEAR_call_destructors"); - $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; - } - $GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args); - } +To retrieve Package version 1.1, use "Package-1.1," to retrieve +Package state beta, use "Package-beta." To retrieve an uncompressed +file, append .tar (make sure there is no file by the same name first) - // }}} - // {{{ isError() +To download a package from another channel, prefix with the channel name like +"channel/Package" - /** - * Tell whether a value is a PEAR error. - * - * @param mixed $data the value to test - * @param int $code if $data is an error object, return true - * only if $code is a string and - * $obj->getMessage() == $code or - * $code is an integer and $obj->getCode() == $code - * @access public - * @return bool true if parameter is an error - */ - function isError($data, $code = null) - { - if (!is_a($data, 'PEAR_Error')) { - return false; - } +More than one package may be specified at once. It is ok to mix these +four ways of specifying packages. + + + + Upgrade Package + doInstall + up + + + c + upgrade packages from a specific channel + CHAN + + + f + overwrite newer installed packages + + + l + do not check for recommended dependency version + + + n + ignore dependencies, upgrade anyway + + + r + do not install files, only register the package as upgraded + + + B + don't build C extensions + + + Z + request uncompressed files when downloading + + + R + root directory used when installing files (ala PHP's INSTALL_ROOT) + DIR + + + + force install even if there were errors + + + a + install all required and optional dependencies + + + o + install all required dependencies + + + O + do not attempt to download any urls or contact channels + + + p + Only list the packages that would be downloaded + + + <package> ... +Upgrades one or more PEAR packages. See documentation for the +"install" command for ways to specify a package. - if (is_null($code)) { - return true; - } elseif (is_string($code)) { - return $data->getMessage() == $code; - } +When upgrading, your package will be updated if the provided new +package has a higher version number (use the -f option if you need to +upgrade anyway). - return $data->getCode() == $code; - } +More than one package may be specified at once. + + + + Upgrade All Packages [Deprecated in favor of calling upgrade with no parameters] + doUpgradeAll + ua + + + c + upgrade packages from a specific channel + CHAN + + + n + ignore dependencies, upgrade anyway + + + r + do not install files, only register the package as upgraded + + + B + don't build C extensions + + + Z + request uncompressed files when downloading + + + R + root directory used when installing files (ala PHP's INSTALL_ROOT), use packagingroot for RPM + DIR + + + + force install even if there were errors + + + + do not check for recommended dependency version + + + +WARNING: This function is deprecated in favor of using the upgrade command with no params - // }}} - // {{{ setErrorHandling() +Upgrades all packages that have a newer release available. Upgrades are +done only if there is a release available of the state specified in +"preferred_state" (currently {config preferred_state}), or a state considered +more stable. + + + + Un-install Package + doUninstall + un + + + n + ignore dependencies, uninstall anyway + + + r + do not remove files, only register the packages as not installed + + + R + root directory used when installing files (ala PHP's INSTALL_ROOT) + DIR + + + + force install even if there were errors + + + O + do not attempt to uninstall remotely + + + [channel/]<package> ... +Uninstalls one or more PEAR packages. More than one package may be +specified at once. Prefix with channel name to uninstall from a +channel not in your default channel ({config default_channel}) + + + + Unpacks a Pecl Package + doBundle + bun + + + d + Optional destination directory for unpacking (defaults to current path or "ext" if exists) + DIR + + + f + Force the unpacking even if there were errors in the package + + + <package> +Unpacks a Pecl Package into the selected location. It will download the +package if needed. + + + + Run Post-Install Scripts bundled with a package + doRunScripts + rs + + <package> +Run post-installation scripts in package <package>, if any exist. + + + + * @author Tomas V. V. Cox + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Common.php 282969 2009-06-28 23:09:27Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1.0 + * @deprecated File deprecated since Release 1.4.0a1 + */ - /** - * Sets how errors generated by this object should be handled. - * Can be invoked both in objects and statically. If called - * statically, setErrorHandling sets the default behaviour for all - * PEAR objects. If called in an object, setErrorHandling sets - * the default behaviour for that object. - * - * @param int $mode - * One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, - * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, - * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION. - * - * @param mixed $options - * When $mode is PEAR_ERROR_TRIGGER, this is the error level (one - * of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). - * - * When $mode is PEAR_ERROR_CALLBACK, this parameter is expected - * to be the callback function or method. A callback - * function is a string with the name of the function, a - * callback method is an array of two elements: the element - * at index 0 is the object, and the element at index 1 is - * the name of the method to call in the object. - * - * When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is - * a printf format string used when printing the error - * message. - * - * @access public - * @return void - * @see PEAR_ERROR_RETURN - * @see PEAR_ERROR_PRINT - * @see PEAR_ERROR_TRIGGER - * @see PEAR_ERROR_DIE - * @see PEAR_ERROR_CALLBACK - * @see PEAR_ERROR_EXCEPTION - * - * @since PHP 4.0.5 - */ +/** + * Include error handling + */ +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR.php'; - function setErrorHandling($mode = null, $options = null) - { - if (isset($this) && is_a($this, 'PEAR')) { - $setmode = &$this->_default_error_mode; - $setoptions = &$this->_default_error_options; - } else { - $setmode = &$GLOBALS['_PEAR_default_error_mode']; - $setoptions = &$GLOBALS['_PEAR_default_error_options']; - } +/** + * PEAR_Common error when an invalid PHP file is passed to PEAR_Common::analyzeSourceCode() + */ +define('PEAR_COMMON_ERROR_INVALIDPHP', 1); +define('_PEAR_COMMON_PACKAGE_NAME_PREG', '[A-Za-z][a-zA-Z0-9_]+'); +define('PEAR_COMMON_PACKAGE_NAME_PREG', '/^' . _PEAR_COMMON_PACKAGE_NAME_PREG . '\\z/'); - switch ($mode) { - case PEAR_ERROR_EXCEPTION: - case PEAR_ERROR_RETURN: - case PEAR_ERROR_PRINT: - case PEAR_ERROR_TRIGGER: - case PEAR_ERROR_DIE: - case null: - $setmode = $mode; - $setoptions = $options; - break; +// this should allow: 1, 1.0, 1.0RC1, 1.0dev, 1.0dev123234234234, 1.0a1, 1.0b1, 1.0pl1 +define('_PEAR_COMMON_PACKAGE_VERSION_PREG', '\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?'); +define('PEAR_COMMON_PACKAGE_VERSION_PREG', '/^' . _PEAR_COMMON_PACKAGE_VERSION_PREG . '\\z/i'); - case PEAR_ERROR_CALLBACK: - $setmode = $mode; - // class/object method callback - if (is_callable($options)) { - $setoptions = $options; - } else { - trigger_error("invalid error callback", E_USER_WARNING); - } - break; +// XXX far from perfect :-) +define('_PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '(' . _PEAR_COMMON_PACKAGE_NAME_PREG . + ')(-([.0-9a-zA-Z]+))?'); +define('PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_PACKAGE_DOWNLOAD_PREG . + '\\z/'); - default: - trigger_error("invalid error mode", E_USER_WARNING); - break; - } - } +define('_PEAR_CHANNELS_NAME_PREG', '[A-Za-z][a-zA-Z0-9\.]+'); +define('PEAR_CHANNELS_NAME_PREG', '/^' . _PEAR_CHANNELS_NAME_PREG . '\\z/'); - // }}} - // {{{ expectError() +// this should allow any dns or IP address, plus a path - NO UNDERSCORES ALLOWED +define('_PEAR_CHANNELS_SERVER_PREG', '[a-zA-Z0-9\-]+(?:\.[a-zA-Z0-9\-]+)*(\/[a-zA-Z0-9\-]+)*'); +define('PEAR_CHANNELS_SERVER_PREG', '/^' . _PEAR_CHANNELS_SERVER_PREG . '\\z/i'); - /** - * This method is used to tell which errors you expect to get. - * Expected errors are always returned with error mode - * PEAR_ERROR_RETURN. Expected error codes are stored in a stack, - * and this method pushes a new element onto it. The list of - * expected errors are in effect until they are popped off the - * stack with the popExpect() method. - * - * Note that this method can not be called statically - * - * @param mixed $code a single error code or an array of error codes to expect - * - * @return int the new depth of the "expected errors" stack - * @access public - */ - function expectError($code = '*') - { - if (is_array($code)) { - array_push($this->_expected_errors, $code); - } else { - array_push($this->_expected_errors, array($code)); - } - return sizeof($this->_expected_errors); - } +define('_PEAR_CHANNELS_PACKAGE_PREG', '(' ._PEAR_CHANNELS_SERVER_PREG . ')\/(' + . _PEAR_COMMON_PACKAGE_NAME_PREG . ')'); +define('PEAR_CHANNELS_PACKAGE_PREG', '/^' . _PEAR_CHANNELS_PACKAGE_PREG . '\\z/i'); - // }}} - // {{{ popExpect() +define('_PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '(' . _PEAR_CHANNELS_NAME_PREG . ')::(' + . _PEAR_COMMON_PACKAGE_NAME_PREG . ')(-([.0-9a-zA-Z]+))?'); +define('PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_CHANNEL_DOWNLOAD_PREG . '\\z/'); - /** - * This method pops one element off the expected error codes - * stack. - * - * @return array the list of error codes that were popped - */ - function popExpect() - { - return array_pop($this->_expected_errors); - } +/** + * List of temporary files and directories registered by + * PEAR_Common::addTempFile(). + * @var array + */ +$GLOBALS['_PEAR_Common_tempfiles'] = array(); - // }}} - // {{{ _checkDelExpect() +/** + * Valid maintainer roles + * @var array + */ +$GLOBALS['_PEAR_Common_maintainer_roles'] = array('lead','developer','contributor','helper'); - /** - * This method checks unsets an error code if available - * - * @param mixed error code - * @return bool true if the error code was unset, false otherwise - * @access private - * @since PHP 4.3.0 - */ - function _checkDelExpect($error_code) - { - $deleted = false; +/** + * Valid release states + * @var array + */ +$GLOBALS['_PEAR_Common_release_states'] = array('alpha','beta','stable','snapshot','devel'); - foreach ($this->_expected_errors AS $key => $error_array) { - if (in_array($error_code, $error_array)) { - unset($this->_expected_errors[$key][array_search($error_code, $error_array)]); - $deleted = true; - } +/** + * Valid dependency types + * @var array + */ +$GLOBALS['_PEAR_Common_dependency_types'] = array('pkg','ext','php','prog','ldlib','rtlib','os','websrv','sapi'); - // clean up empty arrays - if (0 == count($this->_expected_errors[$key])) { - unset($this->_expected_errors[$key]); - } - } - return $deleted; - } +/** + * Valid dependency relations + * @var array + */ +$GLOBALS['_PEAR_Common_dependency_relations'] = array('has','eq','lt','le','gt','ge','not', 'ne'); - // }}} - // {{{ delExpect() +/** + * Valid file roles + * @var array + */ +$GLOBALS['_PEAR_Common_file_roles'] = array('php','ext','test','doc','data','src','script'); - /** - * This method deletes all occurences of the specified element from - * the expected error codes stack. - * - * @param mixed $error_code error code that should be deleted - * @return mixed list of error codes that were deleted or error - * @access public - * @since PHP 4.3.0 - */ - function delExpect($error_code) - { - $deleted = false; - if ((is_array($error_code) && (0 != count($error_code)))) { - // $error_code is a non-empty array here; - // we walk through it trying to unset all - // values - foreach($error_code as $key => $error) { - if ($this->_checkDelExpect($error)) { - $deleted = true; - } else { - $deleted = false; - } - } - return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME - } elseif (!empty($error_code)) { - // $error_code comes alone, trying to unset it - if ($this->_checkDelExpect($error_code)) { - return true; - } else { - return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME - } - } +/** + * Valid replacement types + * @var array + */ +$GLOBALS['_PEAR_Common_replacement_types'] = array('php-const', 'pear-config', 'package-info'); - // $error_code is empty - return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME - } +/** + * Valid "provide" types + * @var array + */ +$GLOBALS['_PEAR_Common_provide_types'] = array('ext', 'prog', 'class', 'function', 'feature', 'api'); - // }}} - // {{{ raiseError() +/** + * Valid "provide" types + * @var array + */ +$GLOBALS['_PEAR_Common_script_phases'] = array('pre-install', 'post-install', 'pre-uninstall', 'post-uninstall', 'pre-build', 'post-build', 'pre-configure', 'post-configure', 'pre-setup', 'post-setup'); +/** + * Class providing common functionality for PEAR administration classes. + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Tomas V. V. Cox + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + * @deprecated This class will disappear, and its components will be spread + * into smaller classes, like the AT&T breakup, as of Release 1.4.0a1 + */ +class PEAR_Common extends PEAR +{ /** - * This method is a wrapper that returns an instance of the - * configured error class with this object's default error - * handling applied. If the $mode and $options parameters are not - * specified, the object's defaults are used. - * - * @param mixed $message a text error message or a PEAR error object - * - * @param int $code a numeric error code (it is up to your class - * to define these if you want to use codes) - * - * @param int $mode One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, - * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, - * PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION. - * - * @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter - * specifies the PHP-internal error level (one of - * E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). - * If $mode is PEAR_ERROR_CALLBACK, this - * parameter specifies the callback function or - * method. In other error modes this parameter - * is ignored. - * - * @param string $userinfo If you need to pass along for example debug - * information, this parameter is meant for that. - * - * @param string $error_class The returned error object will be - * instantiated from this class, if specified. - * - * @param bool $skipmsg If true, raiseError will only pass error codes, - * the error message parameter will be dropped. - * - * @access public - * @return object a PEAR error object - * @see PEAR::setErrorHandling - * @since PHP 4.0.5 + * User Interface object (PEAR_Frontend_* class). If null, + * the log() method uses print. + * @var object */ - function &raiseError($message = null, - $code = null, - $mode = null, - $options = null, - $userinfo = null, - $error_class = null, - $skipmsg = false) - { - // The error is yet a PEAR error object - if (is_object($message)) { - $code = $message->getCode(); - $userinfo = $message->getUserInfo(); - $error_class = $message->getType(); - $message->error_message_prefix = ''; - $message = $message->getMessage(); - } + var $ui = null; - if (isset($this) && isset($this->_expected_errors) && sizeof($this->_expected_errors) > 0 && sizeof($exp = end($this->_expected_errors))) { - if ($exp[0] == "*" || - (is_int(reset($exp)) && in_array($code, $exp)) || - (is_string(reset($exp)) && in_array($message, $exp))) { - $mode = PEAR_ERROR_RETURN; - } - } + /** + * Configuration object (PEAR_Config). + * @var PEAR_Config + */ + var $config = null; - // No mode given, try global ones - if ($mode === null) { - // Class error handler - if (isset($this) && isset($this->_default_error_mode)) { - $mode = $this->_default_error_mode; - $options = $this->_default_error_options; - // Global error handler - } elseif (isset($GLOBALS['_PEAR_default_error_mode'])) { - $mode = $GLOBALS['_PEAR_default_error_mode']; - $options = $GLOBALS['_PEAR_default_error_options']; - } - } + /** stack of elements, gives some sort of XML context */ + var $element_stack = array(); - if ($error_class !== null) { - $ec = $error_class; - } elseif (isset($this) && isset($this->_error_class)) { - $ec = $this->_error_class; - } else { - $ec = 'PEAR_Error'; - } + /** name of currently parsed XML element */ + var $current_element; - if (intval(PHP_VERSION) < 5) { - // little non-eval hack to fix bug #12147 - include 'phar://install-pear-nozlib.phar/' . 'PEAR/FixPHP5PEARWarnings.php'; - return $a; - } + /** array of attributes of the currently parsed XML element */ + var $current_attributes = array(); - if ($skipmsg) { - $a = new $ec($code, $mode, $options, $userinfo); - } else { - $a = new $ec($message, $code, $mode, $options, $userinfo); - } + /** assoc with information about a package */ + var $pkginfo = array(); - return $a; - } + var $current_path = null; - // }}} - // {{{ throwError() + /** + * Flag variable used to mark a valid package file + * @var boolean + * @access private + */ + var $_validPackageFile; /** - * Simpler form of raiseError with fewer options. In most cases - * message, code and userinfo are enough. - * - * @param string $message + * PEAR_Common constructor * + * @access public */ - function &throwError($message = null, - $code = null, - $userinfo = null) - { - if (isset($this) && is_a($this, 'PEAR')) { - $a = &$this->raiseError($message, $code, null, null, $userinfo); - return $a; - } - - $a = &PEAR::raiseError($message, $code, null, null, $userinfo); - return $a; - } - - // }}} - function staticPushErrorHandling($mode, $options = null) + function PEAR_Common() { - $stack = &$GLOBALS['_PEAR_error_handler_stack']; - $def_mode = &$GLOBALS['_PEAR_default_error_mode']; - $def_options = &$GLOBALS['_PEAR_default_error_options']; - $stack[] = array($def_mode, $def_options); - switch ($mode) { - case PEAR_ERROR_EXCEPTION: - case PEAR_ERROR_RETURN: - case PEAR_ERROR_PRINT: - case PEAR_ERROR_TRIGGER: - case PEAR_ERROR_DIE: - case null: - $def_mode = $mode; - $def_options = $options; - break; - - case PEAR_ERROR_CALLBACK: - $def_mode = $mode; - // class/object method callback - if (is_callable($options)) { - $def_options = $options; - } else { - trigger_error("invalid error callback", E_USER_WARNING); - } - break; - - default: - trigger_error("invalid error mode", E_USER_WARNING); - break; - } - $stack[] = array($mode, $options); - return true; + parent::PEAR(); + $this->config = &PEAR_Config::singleton(); + $this->debug = $this->config->get('verbose'); } - function staticPopErrorHandling() + /** + * PEAR_Common destructor + * + * @access private + */ + function _PEAR_Common() { - $stack = &$GLOBALS['_PEAR_error_handler_stack']; - $setmode = &$GLOBALS['_PEAR_default_error_mode']; - $setoptions = &$GLOBALS['_PEAR_default_error_options']; - array_pop($stack); - list($mode, $options) = $stack[sizeof($stack) - 1]; - array_pop($stack); - switch ($mode) { - case PEAR_ERROR_EXCEPTION: - case PEAR_ERROR_RETURN: - case PEAR_ERROR_PRINT: - case PEAR_ERROR_TRIGGER: - case PEAR_ERROR_DIE: - case null: - $setmode = $mode; - $setoptions = $options; - break; - - case PEAR_ERROR_CALLBACK: - $setmode = $mode; - // class/object method callback - if (is_callable($options)) { - $setoptions = $options; - } else { - trigger_error("invalid error callback", E_USER_WARNING); + // doesn't work due to bug #14744 + //$tempfiles = $this->_tempfiles; + $tempfiles =& $GLOBALS['_PEAR_Common_tempfiles']; + while ($file = array_shift($tempfiles)) { + if (@is_dir($file)) { + if (!class_exists('System')) { + require_once 'phar://install-pear-nozlib.phar/' . 'System.php'; } - break; - default: - trigger_error("invalid error mode", E_USER_WARNING); - break; + System::rm(array('-rf', $file)); + } elseif (file_exists($file)) { + unlink($file); + } } - return true; } - // {{{ pushErrorHandling() - /** - * Push a new error handler on top of the error handler options stack. With this - * you can easily override the actual error handler for some code and restore - * it later with popErrorHandling. + * Register a temporary file or directory. When the destructor is + * executed, all registered temporary files and directories are + * removed. * - * @param mixed $mode (same as setErrorHandling) - * @param mixed $options (same as setErrorHandling) + * @param string $file name of file or directory * - * @return bool Always true + * @return void * - * @see PEAR::setErrorHandling + * @access public */ - function pushErrorHandling($mode, $options = null) + function addTempFile($file) { - $stack = &$GLOBALS['_PEAR_error_handler_stack']; - if (isset($this) && is_a($this, 'PEAR')) { - $def_mode = &$this->_default_error_mode; - $def_options = &$this->_default_error_options; - } else { - $def_mode = &$GLOBALS['_PEAR_default_error_mode']; - $def_options = &$GLOBALS['_PEAR_default_error_options']; - } - $stack[] = array($def_mode, $def_options); - - if (isset($this) && is_a($this, 'PEAR')) { - $this->setErrorHandling($mode, $options); - } else { - PEAR::setErrorHandling($mode, $options); + if (!class_exists('PEAR_Frontend')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Frontend.php'; } - $stack[] = array($mode, $options); - return true; + PEAR_Frontend::addTempFile($file); } - // }}} - // {{{ popErrorHandling() - /** - * Pop the last error handler used - * - * @return bool Always true - * - * @see PEAR::pushErrorHandling - */ - function popErrorHandling() + * Wrapper to System::mkDir(), creates a directory as well as + * any necessary parent directories. + * + * @param string $dir directory name + * + * @return bool TRUE on success, or a PEAR error + * + * @access public + */ + function mkDirHier($dir) { - $stack = &$GLOBALS['_PEAR_error_handler_stack']; - array_pop($stack); - list($mode, $options) = $stack[sizeof($stack) - 1]; - array_pop($stack); - if (isset($this) && is_a($this, 'PEAR')) { - $this->setErrorHandling($mode, $options); - } else { - PEAR::setErrorHandling($mode, $options); + // Only used in Installer - move it there ? + $this->log(2, "+ create dir $dir"); + if (!class_exists('System')) { + require_once 'phar://install-pear-nozlib.phar/' . 'System.php'; } - return true; + return System::mkDir(array('-p', $dir)); } - // }}} - // {{{ loadExtension() - /** - * OS independant PHP extension load. Remember to take care - * on the correct extension name for case sensitive OSes. - * - * @param string $ext The extension name - * @return bool Success or not on the dl() call - */ - function loadExtension($ext) + * Logging method. + * + * @param int $level log level (0 is quiet, higher is noisier) + * @param string $msg message to write to the log + * + * @return void + * + * @access public + * @static + */ + function log($level, $msg, $append_crlf = true) { - if (!extension_loaded($ext)) { - // if either returns true dl() will produce a FATAL error, stop that - if ((ini_get('enable_dl') != 1) || (ini_get('safe_mode') == 1)) { - return false; + if ($this->debug >= $level) { + if (!class_exists('PEAR_Frontend')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Frontend.php'; } - if (OS_WINDOWS) { - $suffix = '.dll'; - } elseif (PHP_OS == 'HP-UX') { - $suffix = '.sl'; - } elseif (PHP_OS == 'AIX') { - $suffix = '.a'; - } elseif (PHP_OS == 'OSX') { - $suffix = '.bundle'; + $ui = &PEAR_Frontend::singleton(); + if (is_a($ui, 'PEAR_Frontend')) { + $ui->log($msg, $append_crlf); } else { - $suffix = '.so'; + print "$msg\n"; } - - return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix); } - - return true; } - // }}} -} - -if (PEAR_ZE2) { /** - * This is only meant for PHP 5 to get rid of certain strict warning - * that doesn't get hidden since it's in the shutdown function + * Create and register a temporary directory. + * + * @param string $tmpdir (optional) Directory to use as tmpdir. + * Will use system defaults (for example + * /tmp or c:\windows\temp) if not specified + * + * @return string name of created directory + * + * @access public */ - class PEAR5 - { - /** - * If you have a class that's mostly/entirely static, and you need static - * properties, you can use this method to simulate them. Eg. in your method(s) - * do this: $myVar = &PEAR5::getStaticProperty('myclass', 'myVar'); - * You MUST use a reference, or they will not persist! - * - * @access public - * @param string $class The calling classname, to prevent clashes - * @param string $var The variable to retrieve. - * @return mixed A reference to the variable. If not set it will be - * auto initialised to NULL. - */ - static function &getStaticProperty($class, $var) - { - static $properties; - if (!isset($properties[$class])) { - $properties[$class] = array(); - } - - if (!array_key_exists($var, $properties[$class])) { - $properties[$class][$var] = null; - } - - return $properties[$class][$var]; - } - } -} - -// {{{ _PEAR_call_destructors() - -function _PEAR_call_destructors() -{ - global $_PEAR_destructor_object_list; - if (is_array($_PEAR_destructor_object_list) && - sizeof($_PEAR_destructor_object_list)) + function mkTempDir($tmpdir = '') { - reset($_PEAR_destructor_object_list); - if (PEAR_ZE2) { - $destructLifoExists = PEAR5::getStaticProperty('PEAR', 'destructlifo'); - } else { - $destructLifoExists = PEAR::getStaticProperty('PEAR', 'destructlifo'); - } - - if ($destructLifoExists) { - $_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list); + $topt = $tmpdir ? array('-t', $tmpdir) : array(); + $topt = array_merge($topt, array('-d', 'pear')); + if (!class_exists('System')) { + require_once 'phar://install-pear-nozlib.phar/' . 'System.php'; } - while (list($k, $objref) = each($_PEAR_destructor_object_list)) { - $classname = get_class($objref); - while ($classname) { - $destructor = "_$classname"; - if (method_exists($objref, $destructor)) { - $objref->$destructor(); - break; - } else { - $classname = get_parent_class($classname); - } - } + if (!$tmpdir = System::mktemp($topt)) { + return false; } - // Empty the object list to ensure that destructors are - // not called more than once. - $_PEAR_destructor_object_list = array(); - } - // Now call the shutdown functions - if (is_array($GLOBALS['_PEAR_shutdown_funcs']) AND !empty($GLOBALS['_PEAR_shutdown_funcs'])) { - foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) { - call_user_func_array($value[0], $value[1]); - } + $this->addTempFile($tmpdir); + return $tmpdir; } -} - -// }}} -/** - * Standard PEAR error class for PHP 4 - * - * This class is supserseded by {@link PEAR_Exception} in PHP 5 - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Tomas V.V. Cox - * @author Gregory Beaver - * @copyright 1997-2006 The PHP Group - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/manual/en/core.pear.pear-error.php - * @see PEAR::raiseError(), PEAR::throwError() - * @since Class available since PHP 4.0.2 - */ -class PEAR_Error -{ - // {{{ properties - - var $error_message_prefix = ''; - var $mode = PEAR_ERROR_RETURN; - var $level = E_USER_NOTICE; - var $code = -1; - var $message = ''; - var $userinfo = ''; - var $backtrace = null; - - // }}} - // {{{ constructor /** - * PEAR_Error constructor - * - * @param string $message message - * - * @param int $code (optional) error code - * - * @param int $mode (optional) error mode, one of: PEAR_ERROR_RETURN, - * PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER, - * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION - * - * @param mixed $options (optional) error level, _OR_ in the case of - * PEAR_ERROR_CALLBACK, the callback function or object/method - * tuple. - * - * @param string $userinfo (optional) additional user/debug info + * Set object that represents the frontend to be used. * + * @param object Reference of the frontend object + * @return void * @access public - * */ - function PEAR_Error($message = 'unknown error', $code = null, - $mode = null, $options = null, $userinfo = null) + function setFrontendObject(&$ui) { - if ($mode === null) { - $mode = PEAR_ERROR_RETURN; - } - $this->message = $message; - $this->code = $code; - $this->mode = $mode; - $this->userinfo = $userinfo; - - if (PEAR_ZE2) { - $skiptrace = PEAR5::getStaticProperty('PEAR_Error', 'skiptrace'); - } else { - $skiptrace = PEAR::getStaticProperty('PEAR_Error', 'skiptrace'); - } + $this->ui = &$ui; + } - if (!$skiptrace) { - $this->backtrace = debug_backtrace(); - if (isset($this->backtrace[0]) && isset($this->backtrace[0]['object'])) { - unset($this->backtrace[0]['object']); - } - } - if ($mode & PEAR_ERROR_CALLBACK) { - $this->level = E_USER_NOTICE; - $this->callback = $options; - } else { - if ($options === null) { - $options = E_USER_NOTICE; - } - $this->level = $options; - $this->callback = null; - } - if ($this->mode & PEAR_ERROR_PRINT) { - if (is_null($options) || is_int($options)) { - $format = "%s"; - } else { - $format = $options; - } - printf($format, $this->getMessage()); - } - if ($this->mode & PEAR_ERROR_TRIGGER) { - trigger_error($this->getMessage(), $this->level); - } - if ($this->mode & PEAR_ERROR_DIE) { - $msg = $this->getMessage(); - if (is_null($options) || is_int($options)) { - $format = "%s"; - if (substr($msg, -1) != "\n") { - $msg .= "\n"; - } - } else { - $format = $options; - } - die(sprintf($format, $msg)); - } - if ($this->mode & PEAR_ERROR_CALLBACK) { - if (is_callable($this->callback)) { - call_user_func($this->callback, $this); - } + /** + * Return an array containing all of the states that are more stable than + * or equal to the passed in state + * + * @param string Release state + * @param boolean Determines whether to include $state in the list + * @return false|array False if $state is not a valid release state + */ + function betterStates($state, $include = false) + { + static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable'); + $i = array_search($state, $states); + if ($i === false) { + return false; } - if ($this->mode & PEAR_ERROR_EXCEPTION) { - trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_Exception for exceptions", E_USER_WARNING); - eval('$e = new Exception($this->message, $this->code);throw($e);'); + if ($include) { + $i--; } + return array_slice($states, $i + 1); } - // }}} - // {{{ getMode() - /** - * Get the error mode from an error object. + * Get the valid roles for a PEAR package maintainer * - * @return int error mode - * @access public + * @return array + * @static */ - function getMode() { - return $this->mode; + function getUserRoles() + { + return $GLOBALS['_PEAR_Common_maintainer_roles']; } - // }}} - // {{{ getCallback() - /** - * Get the callback function/method from an error object. + * Get the valid package release states of packages * - * @return mixed callback function or object/method array - * @access public + * @return array + * @static */ - function getCallback() { - return $this->callback; + function getReleaseStates() + { + return $GLOBALS['_PEAR_Common_release_states']; } - // }}} - // {{{ getMessage() - - /** - * Get the error message from an error object. + * Get the implemented dependency types (php, ext, pkg etc.) * - * @return string full error message - * @access public + * @return array + * @static */ - function getMessage() + function getDependencyTypes() { - return ($this->error_message_prefix . $this->message); + return $GLOBALS['_PEAR_Common_dependency_types']; } - - // }}} - // {{{ getCode() + /** + * Get the implemented dependency relations (has, lt, ge etc.) + * + * @return array + * @static + */ + function getDependencyRelations() + { + return $GLOBALS['_PEAR_Common_dependency_relations']; + } /** - * Get error code from an error object + * Get the implemented file roles * - * @return int error code - * @access public + * @return array + * @static */ - function getCode() - { - return $this->code; - } + function getFileRoles() + { + return $GLOBALS['_PEAR_Common_file_roles']; + } - // }}} - // {{{ getType() + /** + * Get the implemented file replacement types in + * + * @return array + * @static + */ + function getReplacementTypes() + { + return $GLOBALS['_PEAR_Common_replacement_types']; + } /** - * Get the name of this error/exception. + * Get the implemented file replacement types in * - * @return string error/exception name (type) - * @access public + * @return array + * @static */ - function getType() + function getProvideTypes() { - return get_class($this); + return $GLOBALS['_PEAR_Common_provide_types']; } - // }}} - // {{{ getUserInfo() - /** - * Get additional user-supplied information. + * Get the implemented file replacement types in * - * @return string user-supplied information - * @access public + * @return array + * @static */ - function getUserInfo() + function getScriptPhases() { - return $this->userinfo; + return $GLOBALS['_PEAR_Common_script_phases']; } - // }}} - // {{{ getDebugInfo() - /** - * Get additional debug information supplied by the application. + * Test whether a string contains a valid package name. + * + * @param string $name the package name to test + * + * @return bool * - * @return string debug information * @access public */ - function getDebugInfo() + function validPackageName($name) { - return $this->getUserInfo(); + return (bool)preg_match(PEAR_COMMON_PACKAGE_NAME_PREG, $name); } - // }}} - // {{{ getBacktrace() - /** - * Get the call backtrace from where the error was generated. - * Supported with PHP 4.3.0 or newer. + * Test whether a string contains a valid package version. + * + * @param string $ver the package version to test + * + * @return bool * - * @param int $frame (optional) what frame to fetch - * @return array Backtrace, or NULL if not available. * @access public */ - function getBacktrace($frame = null) + function validPackageVersion($ver) { - if (defined('PEAR_IGNORE_BACKTRACE')) { - return null; - } - if ($frame === null) { - return $this->backtrace; - } - return $this->backtrace[$frame]; + return (bool)preg_match(PEAR_COMMON_PACKAGE_VERSION_PREG, $ver); } - // }}} - // {{{ addUserInfo() - - function addUserInfo($info) + /** + * @param string $path relative or absolute include path + * @return boolean + * @static + */ + function isIncludeable($path) { - if (empty($this->userinfo)) { - $this->userinfo = $info; - } else { - $this->userinfo .= " ** $info"; + if (file_exists($path) && is_readable($path)) { + return true; } - } - - // }}} - // {{{ toString() - function __toString() - { - return $this->getMessage(); - } - // }}} - // {{{ toString() - /** - * Make a string representation of this object. - * - * @return string a string with an object summary - * @access public - */ - function toString() { - $modes = array(); - $levels = array(E_USER_NOTICE => 'notice', - E_USER_WARNING => 'warning', - E_USER_ERROR => 'error'); - if ($this->mode & PEAR_ERROR_CALLBACK) { - if (is_array($this->callback)) { - $callback = (is_object($this->callback[0]) ? - strtolower(get_class($this->callback[0])) : - $this->callback[0]) . '::' . - $this->callback[1]; - } else { - $callback = $this->callback; + $ipath = explode(PATH_SEPARATOR, ini_get('include_path')); + foreach ($ipath as $include) { + $test = realpath($include . DIRECTORY_SEPARATOR . $path); + if (file_exists($test) && is_readable($test)) { + return true; } - return sprintf('[%s: message="%s" code=%d mode=callback '. - 'callback=%s prefix="%s" info="%s"]', - strtolower(get_class($this)), $this->message, $this->code, - $callback, $this->error_message_prefix, - $this->userinfo); - } - if ($this->mode & PEAR_ERROR_PRINT) { - $modes[] = 'print'; - } - if ($this->mode & PEAR_ERROR_TRIGGER) { - $modes[] = 'trigger'; } - if ($this->mode & PEAR_ERROR_DIE) { - $modes[] = 'die'; - } - if ($this->mode & PEAR_ERROR_RETURN) { - $modes[] = 'return'; - } - return sprintf('[%s: message="%s" code=%d mode=%s level=%s '. - 'prefix="%s" info="%s"]', - strtolower(get_class($this)), $this->message, $this->code, - implode("|", $modes), $levels[$this->level], - $this->error_message_prefix, - $this->userinfo); - } - - // }}} -} - -/* - * Local Variables: - * mode: php - * tab-width: 4 - * c-basic-offset: 4 - * End: - */ - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: ChannelFile.php,v 1.84 2009/03/09 01:03:51 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * Needed for error handling - */ -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/ErrorStack.php'; -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/XMLParser.php'; -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Common.php'; - -/** - * Error code if the channel.xml tag does not contain a valid version - */ -define('PEAR_CHANNELFILE_ERROR_NO_VERSION', 1); -/** - * Error code if the channel.xml tag version is not supported (version 1.0 is the only supported version, - * currently - */ -define('PEAR_CHANNELFILE_ERROR_INVALID_VERSION', 2); - -/** - * Error code if parsing is attempted with no xml extension - */ -define('PEAR_CHANNELFILE_ERROR_NO_XML_EXT', 3); - -/** - * Error code if creating the xml parser resource fails - */ -define('PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER', 4); - -/** - * Error code used for all sax xml parsing errors - */ -define('PEAR_CHANNELFILE_ERROR_PARSER_ERROR', 5); - -/**#@+ - * Validation errors - */ -/** - * Error code when channel name is missing - */ -define('PEAR_CHANNELFILE_ERROR_NO_NAME', 6); -/** - * Error code when channel name is invalid - */ -define('PEAR_CHANNELFILE_ERROR_INVALID_NAME', 7); -/** - * Error code when channel summary is missing - */ -define('PEAR_CHANNELFILE_ERROR_NO_SUMMARY', 8); -/** - * Error code when channel summary is multi-line - */ -define('PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY', 9); -/** - * Error code when channel server is missing for protocol - */ -define('PEAR_CHANNELFILE_ERROR_NO_HOST', 10); -/** - * Error code when channel server is invalid for protocol - */ -define('PEAR_CHANNELFILE_ERROR_INVALID_HOST', 11); -/** - * Error code when a mirror name is invalid - */ -define('PEAR_CHANNELFILE_ERROR_INVALID_MIRROR', 21); -/** - * Error code when a mirror type is invalid - */ -define('PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE', 22); -/** - * Error code when an attempt is made to generate xml, but the parsed content is invalid - */ -define('PEAR_CHANNELFILE_ERROR_INVALID', 23); -/** - * Error code when an empty package name validate regex is passed in - */ -define('PEAR_CHANNELFILE_ERROR_EMPTY_REGEX', 24); -/** - * Error code when a tag has no version - */ -define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION', 25); -/** - * Error code when a tag has no name - */ -define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME', 26); -/** - * Error code when a tag has no name - */ -define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME', 27); -/** - * Error code when a tag has no version attribute - */ -define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION', 28); -/** - * Error code when a mirror does not exist but is called for in one of the set* - * methods. - */ -define('PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND', 32); -/** - * Error code when a server port is not numeric - */ -define('PEAR_CHANNELFILE_ERROR_INVALID_PORT', 33); -/** - * Error code when contains no version attribute - */ -define('PEAR_CHANNELFILE_ERROR_NO_STATICVERSION', 34); -/** - * Error code when contains no type attribute in a protocol definition - */ -define('PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE', 35); -/** - * Error code when a mirror is defined and the channel.xml represents the __uri pseudo-channel - */ -define('PEAR_CHANNELFILE_URI_CANT_MIRROR', 36); -/** - * Error code when ssl attribute is present and is not "yes" - */ -define('PEAR_CHANNELFILE_ERROR_INVALID_SSL', 37); -/**#@-*/ - -/** - * Mirror types allowed. Currently only internet servers are recognized. - */ -$GLOBALS['_PEAR_CHANNELS_MIRROR_TYPES'] = array('server'); + return false; + } -/** - * The Channel handling class - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_ChannelFile -{ - /** - * @access private - * @var PEAR_ErrorStack - * @access private - */ - var $_stack; + function _postProcessChecks($pf) + { + if (!PEAR::isError($pf)) { + return $this->_postProcessValidPackagexml($pf); + } - /** - * Supported channel.xml versions, for parsing - * @var array - * @access private - */ - var $_supportedVersions = array('1.0'); + $errs = $pf->getUserinfo(); + if (is_array($errs)) { + foreach ($errs as $error) { + $e = $this->raiseError($error['message'], $error['code'], null, null, $error); + } + } - /** - * Parsed channel information - * @var array - * @access private - */ - var $_channelInfo; + return $pf; + } /** - * index into the subchannels array, used for parsing xml - * @var int - * @access private + * Returns information about a package file. Expects the name of + * a gzipped tar file as input. + * + * @param string $file name of .tgz file + * + * @return array array with package information + * + * @access public + * @deprecated use PEAR_PackageFile->fromTgzFile() instead + * */ - var $_subchannelIndex; + function infoFromTgzFile($file) + { + $packagefile = &new PEAR_PackageFile($this->config); + $pf = &$packagefile->fromTgzFile($file, PEAR_VALIDATE_NORMAL); + return $this->_postProcessChecks($pf); + } /** - * index into the mirrors array, used for parsing xml - * @var int - * @access private + * Returns information about a package file. Expects the name of + * a package xml file as input. + * + * @param string $descfile name of package xml file + * + * @return array array with package information + * + * @access public + * @deprecated use PEAR_PackageFile->fromPackageFile() instead + * */ - var $_mirrorIndex; + function infoFromDescriptionFile($descfile) + { + $packagefile = &new PEAR_PackageFile($this->config); + $pf = &$packagefile->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL); + return $this->_postProcessChecks($pf); + } /** - * Flag used to determine the validity of parsed content - * @var boolean - * @access private + * Returns information about a package file. Expects the contents + * of a package xml file as input. + * + * @param string $data contents of package.xml file + * + * @return array array with package information + * + * @access public + * @deprecated use PEAR_PackageFile->fromXmlstring() instead + * */ - var $_isValid = false; - - function PEAR_ChannelFile() + function infoFromString($data) { - $this->_stack = &new PEAR_ErrorStack('PEAR_ChannelFile'); - $this->_stack->setErrorMessageTemplate($this->_getErrorMessage()); - $this->_isValid = false; + $packagefile = &new PEAR_PackageFile($this->config); + $pf = &$packagefile->fromXmlString($data, PEAR_VALIDATE_NORMAL, false); + return $this->_postProcessChecks($pf); } /** + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 * @return array - * @access protected */ - function _getErrorMessage() + function _postProcessValidPackagexml(&$pf) { - return - array( - PEAR_CHANNELFILE_ERROR_INVALID_VERSION => - 'While parsing channel.xml, an invalid version number "%version% was passed in, expecting one of %versions%', - PEAR_CHANNELFILE_ERROR_NO_VERSION => - 'No version number found in tag', - PEAR_CHANNELFILE_ERROR_NO_XML_EXT => - '%error%', - PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER => - 'Unable to create XML parser', - PEAR_CHANNELFILE_ERROR_PARSER_ERROR => - '%error%', - PEAR_CHANNELFILE_ERROR_NO_NAME => - 'Missing channel name', - PEAR_CHANNELFILE_ERROR_INVALID_NAME => - 'Invalid channel %tag% "%name%"', - PEAR_CHANNELFILE_ERROR_NO_SUMMARY => - 'Missing channel summary', - PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY => - 'Channel summary should be on one line, but is multi-line', - PEAR_CHANNELFILE_ERROR_NO_HOST => - 'Missing channel server for %type% server', - PEAR_CHANNELFILE_ERROR_INVALID_HOST => - 'Server name "%server%" is invalid for %type% server', - PEAR_CHANNELFILE_ERROR_INVALID_MIRROR => - 'Invalid mirror name "%name%", mirror type %type%', - PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE => - 'Invalid mirror type "%type%"', - PEAR_CHANNELFILE_ERROR_INVALID => - 'Cannot generate xml, contents are invalid', - PEAR_CHANNELFILE_ERROR_EMPTY_REGEX => - 'packagenameregex cannot be empty', - PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION => - '%parent% %protocol% function has no version', - PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME => - '%parent% %protocol% function has no name', - PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE => - '%parent% rest baseurl has no type', - PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME => - 'Validation package has no name in tag', - PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION => - 'Validation package "%package%" has no version', - PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND => - 'Mirror "%mirror%" does not exist', - PEAR_CHANNELFILE_ERROR_INVALID_PORT => - 'Port "%port%" must be numeric', - PEAR_CHANNELFILE_ERROR_NO_STATICVERSION => - ' tag must contain version attribute', - PEAR_CHANNELFILE_URI_CANT_MIRROR => - 'The __uri pseudo-channel cannot have mirrors', - PEAR_CHANNELFILE_ERROR_INVALID_SSL => - '%server% has invalid ssl attribute "%ssl%" can only be yes or not present', - ); + if (!is_a($pf, 'PEAR_PackageFile_v2')) { + $this->pkginfo = $pf->toArray(); + return $this->pkginfo; + } + + // sort of make this into a package.xml 1.0-style array + // changelog is not converted to old format. + $arr = $pf->toArray(true); + $arr = array_merge($arr, $arr['old']); + unset($arr['old'], $arr['xsdversion'], $arr['contents'], $arr['compatible'], + $arr['channel'], $arr['uri'], $arr['dependencies'], $arr['phprelease'], + $arr['extsrcrelease'], $arr['zendextsrcrelease'], $arr['extbinrelease'], + $arr['zendextbinrelease'], $arr['bundle'], $arr['lead'], $arr['developer'], + $arr['helper'], $arr['contributor']); + $arr['filelist'] = $pf->getFilelist(); + $this->pkginfo = $arr; + return $arr; } /** - * @param string contents of package.xml file - * @return bool success of parsing + * Returns package information from different sources + * + * This method is able to extract information about a package + * from a .tgz archive or from a XML package definition file. + * + * @access public + * @param string Filename of the source ('package.xml', '.tgz') + * @return string + * @deprecated use PEAR_PackageFile->fromAnyFile() instead */ - function fromXmlString($data) + function infoFromAny($info) { - if (preg_match('/_supportedVersions)) { - $this->_stack->push(PEAR_CHANNELFILE_ERROR_INVALID_VERSION, 'error', - array('version' => $channelversion[1])); - return false; - } - $parser = new PEAR_XMLParser; - $result = $parser->parse($data); - if ($result !== true) { - if ($result->getCode() == 1) { - $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_XML_EXT, 'error', - array('error' => $result->getMessage())); - } else { - $this->_stack->push(PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER, 'error'); + if (is_string($info) && file_exists($info)) { + $packagefile = &new PEAR_PackageFile($this->config); + $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL); + if (PEAR::isError($pf)) { + $errs = $pf->getUserinfo(); + if (is_array($errs)) { + foreach ($errs as $error) { + $e = $this->raiseError($error['message'], $error['code'], null, null, $error); + } } - return false; + + return $pf; } - $this->_channelInfo = $parser->getData(); - return true; - } else { - $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_VERSION, 'error', array('xml' => $data)); - return false; + + return $this->_postProcessValidPackagexml($pf); } + + return $info; + } + + /** + * Return an XML document based on the package info (as returned + * by the PEAR_Common::infoFrom* methods). + * + * @param array $pkginfo package info + * + * @return string XML data + * + * @access public + * @deprecated use a PEAR_PackageFile_v* object's generator instead + */ + function xmlFromInfo($pkginfo) + { + $config = &PEAR_Config::singleton(); + $packagefile = &new PEAR_PackageFile($config); + $pf = &$packagefile->fromArray($pkginfo); + $gen = &$pf->getDefaultGenerator(); + return $gen->toXml(PEAR_VALIDATE_PACKAGING); } /** - * @return array + * Validate XML package definition file. + * + * @param string $info Filename of the package archive or of the + * package definition file + * @param array $errors Array that will contain the errors + * @param array $warnings Array that will contain the warnings + * @param string $dir_prefix (optional) directory where source files + * may be found, or empty if they are not available + * @access public + * @return boolean + * @deprecated use the validation of PEAR_PackageFile objects */ - function toArray() + function validatePackageInfo($info, &$errors, &$warnings, $dir_prefix = '') { - if (!$this->_isValid && !$this->validate()) { + $config = &PEAR_Config::singleton(); + $packagefile = &new PEAR_PackageFile($config); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + if (strpos($info, 'fromXmlString($info, PEAR_VALIDATE_NORMAL, ''); + } else { + $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL); + } + + PEAR::staticPopErrorHandling(); + if (PEAR::isError($pf)) { + $errs = $pf->getUserinfo(); + if (is_array($errs)) { + foreach ($errs as $error) { + if ($error['level'] == 'error') { + $errors[] = $error['message']; + } else { + $warnings[] = $error['message']; + } + } + } + return false; } - return $this->_channelInfo; + + return true; } /** - * @param array - * @static - * @return PEAR_ChannelFile|false false if invalid + * Build a "provides" array from data returned by + * analyzeSourceCode(). The format of the built array is like + * this: + * + * array( + * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'), + * ... + * ) + * + * + * @param array $srcinfo array with information about a source file + * as returned by the analyzeSourceCode() method. + * + * @return void + * + * @access public + * */ - function &fromArray($data, $compatibility = false, $stackClass = 'PEAR_ErrorStack') + function buildProvidesArray($srcinfo) { - $a = new PEAR_ChannelFile($compatibility, $stackClass); - $a->_fromArray($data); - if (!$a->validate()) { - $a = false; - return $a; + $file = basename($srcinfo['source_file']); + $pn = ''; + if (isset($this->_packageName)) { + $pn = $this->_packageName; } - return $a; - } - /** - * Unlike {@link fromArray()} this does not do any validation - * @param array - * @static - * @return PEAR_ChannelFile - */ - function &fromArrayWithErrors($data, $compatibility = false, - $stackClass = 'PEAR_ErrorStack') - { - $a = new PEAR_ChannelFile($compatibility, $stackClass); - $a->_fromArray($data); - return $a; + $pnl = strlen($pn); + foreach ($srcinfo['declared_classes'] as $class) { + $key = "class;$class"; + if (isset($this->pkginfo['provides'][$key])) { + continue; + } + + $this->pkginfo['provides'][$key] = + array('file'=> $file, 'type' => 'class', 'name' => $class); + if (isset($srcinfo['inheritance'][$class])) { + $this->pkginfo['provides'][$key]['extends'] = + $srcinfo['inheritance'][$class]; + } + } + + foreach ($srcinfo['declared_methods'] as $class => $methods) { + foreach ($methods as $method) { + $function = "$class::$method"; + $key = "function;$function"; + if ($method{0} == '_' || !strcasecmp($method, $class) || + isset($this->pkginfo['provides'][$key])) { + continue; + } + + $this->pkginfo['provides'][$key] = + array('file'=> $file, 'type' => 'function', 'name' => $function); + } + } + + foreach ($srcinfo['declared_functions'] as $function) { + $key = "function;$function"; + if ($function{0} == '_' || isset($this->pkginfo['provides'][$key])) { + continue; + } + + if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) { + $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\""; + } + + $this->pkginfo['provides'][$key] = + array('file'=> $file, 'type' => 'function', 'name' => $function); + } } /** - * @param array - * @access private + * Analyze the source code of the given PHP file + * + * @param string Filename of the PHP file + * @return mixed + * @access public */ - function _fromArray($data) + function analyzeSourceCode($file) { - $this->_channelInfo = $data; + if (!class_exists('PEAR_PackageFile_v2_Validator')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/v2/Validator.php'; + } + + $a = new PEAR_PackageFile_v2_Validator; + return $a->analyzeSourceCode($file); } - /** - * Wrapper to {@link PEAR_ErrorStack::getErrors()} - * @param boolean determines whether to purge the error stack after retrieving - * @return array - */ - function getErrors($purge = false) + function detectDependencies($any, $status_callback = null) { - return $this->_stack->getErrors($purge); + if (!function_exists("token_get_all")) { + return false; + } + + if (PEAR::isError($info = $this->infoFromAny($any))) { + return $this->raiseError($info); + } + + if (!is_array($info)) { + return false; + } + + $deps = array(); + $used_c = $decl_c = $decl_f = $decl_m = array(); + foreach ($info['filelist'] as $file => $fa) { + $tmp = $this->analyzeSourceCode($file); + $used_c = @array_merge($used_c, $tmp['used_classes']); + $decl_c = @array_merge($decl_c, $tmp['declared_classes']); + $decl_f = @array_merge($decl_f, $tmp['declared_functions']); + $decl_m = @array_merge($decl_m, $tmp['declared_methods']); + $inheri = @array_merge($inheri, $tmp['inheritance']); + } + + $used_c = array_unique($used_c); + $decl_c = array_unique($decl_c); + $undecl_c = array_diff($used_c, $decl_c); + + return array('used_classes' => $used_c, + 'declared_classes' => $decl_c, + 'declared_methods' => $decl_m, + 'declared_functions' => $decl_f, + 'undeclared_classes' => $undecl_c, + 'inheritance' => $inheri, + ); } /** - * Unindent given string (?) + * Download a file through HTTP. Considers suggested file name in + * Content-disposition: header and can run a callback function for + * different events. The callback will be called with two + * parameters: the callback type, and parameters. The implemented + * callback types are: * - * @param string $str The string that has to be unindented. - * @return string - * @access private + * 'setup' called at the very beginning, parameter is a UI object + * that should be used for all output + * 'message' the parameter is a string with an informational message + * 'saveas' may be used to save with a different file name, the + * parameter is the filename that is about to be used. + * If a 'saveas' callback returns a non-empty string, + * that file name will be used as the filename instead. + * Note that $save_dir will not be affected by this, only + * the basename of the file. + * 'start' download is starting, parameter is number of bytes + * that are expected, or -1 if unknown + * 'bytesread' parameter is the number of bytes read so far + * 'done' download is complete, parameter is the total number + * of bytes read + * 'connfailed' if the TCP connection fails, this callback is called + * with array(host,port,errno,errmsg) + * 'writefailed' if writing to disk fails, this callback is called + * with array(destfile,errmsg) + * + * If an HTTP proxy has been configured (http_proxy PEAR_Config + * setting), the proxy will be used. + * + * @param string $url the URL to download + * @param object $ui PEAR_Frontend_* instance + * @param object $config PEAR_Config instance + * @param string $save_dir (optional) directory to save file in + * @param mixed $callback (optional) function/method to call for status + * updates + * + * @return string Returns the full path of the downloaded file or a PEAR + * error on failure. If the error is caused by + * socket-related errors, the error object will + * have the fsockopen error code available through + * getCode(). + * + * @access public + * @deprecated in favor of PEAR_Downloader::downloadHttp() */ - function _unIndent($str) + function downloadHttp($url, &$ui, $save_dir = '.', $callback = null) { - // remove leading newlines - $str = preg_replace('/^[\r\n]+/', '', $str); - // find whitespace at the beginning of the first line - $indent_len = strspn($str, " \t"); - $indent = substr($str, 0, $indent_len); - $data = ''; - // remove the same amount of whitespace from following lines - foreach (explode("\n", $str) as $line) { - if (substr($line, 0, $indent_len) == $indent) { - $data .= substr($line, $indent_len) . "\n"; - } + if (!class_exists('PEAR_Downloader')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Downloader.php'; } - return $data; + return PEAR_Downloader::downloadHttp($url, $ui, $save_dir, $callback); + } +} + +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Config.php'; +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile.php'; + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Config.php 286480 2009-07-29 02:50:02Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 0.1 + */ + +/** + * Required for error handling + */ +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR.php'; +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Registry.php'; +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Installer/Role.php'; +require_once 'phar://install-pear-nozlib.phar/' . 'System.php'; + +/** + * Last created PEAR_Config instance. + * @var object + */ +$GLOBALS['_PEAR_Config_instance'] = null; +if (!defined('PEAR_INSTALL_DIR') || !PEAR_INSTALL_DIR) { + $PEAR_INSTALL_DIR = PHP_LIBDIR . DIRECTORY_SEPARATOR . 'pear'; +} else { + $PEAR_INSTALL_DIR = PEAR_INSTALL_DIR; +} + +// Below we define constants with default values for all configuration +// parameters except username/password. All of them can have their +// defaults set through environment variables. The reason we use the +// PHP_ prefix is for some security, PHP protects environment +// variables starting with PHP_*. + +// default channel and preferred mirror is based on whether we are invoked through +// the "pear" or the "pecl" command +if (!defined('PEAR_RUNTYPE')) { + define('PEAR_RUNTYPE', 'pear'); +} + +if (PEAR_RUNTYPE == 'pear') { + define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pear.php.net'); +} else { + define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pecl.php.net'); +} + +if (getenv('PHP_PEAR_SYSCONF_DIR')) { + define('PEAR_CONFIG_SYSCONFDIR', getenv('PHP_PEAR_SYSCONF_DIR')); +} elseif (getenv('SystemRoot')) { + define('PEAR_CONFIG_SYSCONFDIR', getenv('SystemRoot')); +} else { + define('PEAR_CONFIG_SYSCONFDIR', PHP_SYSCONFDIR); +} + +// Default for master_server +if (getenv('PHP_PEAR_MASTER_SERVER')) { + define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', getenv('PHP_PEAR_MASTER_SERVER')); +} else { + define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', 'pear.php.net'); +} + +// Default for http_proxy +if (getenv('PHP_PEAR_HTTP_PROXY')) { + define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('PHP_PEAR_HTTP_PROXY')); +} elseif (getenv('http_proxy')) { + define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('http_proxy')); +} else { + define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', ''); +} + +// Default for php_dir +if (getenv('PHP_PEAR_INSTALL_DIR')) { + define('PEAR_CONFIG_DEFAULT_PHP_DIR', getenv('PHP_PEAR_INSTALL_DIR')); +} else { + if (@file_exists($PEAR_INSTALL_DIR) && is_dir($PEAR_INSTALL_DIR)) { + define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR); + } else { + define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR); + } +} + +// Default for ext_dir +if (getenv('PHP_PEAR_EXTENSION_DIR')) { + define('PEAR_CONFIG_DEFAULT_EXT_DIR', getenv('PHP_PEAR_EXTENSION_DIR')); +} else { + if (ini_get('extension_dir')) { + define('PEAR_CONFIG_DEFAULT_EXT_DIR', ini_get('extension_dir')); + } elseif (defined('PEAR_EXTENSION_DIR') && + file_exists(PEAR_EXTENSION_DIR) && is_dir(PEAR_EXTENSION_DIR)) { + define('PEAR_CONFIG_DEFAULT_EXT_DIR', PEAR_EXTENSION_DIR); + } elseif (defined('PHP_EXTENSION_DIR')) { + define('PEAR_CONFIG_DEFAULT_EXT_DIR', PHP_EXTENSION_DIR); + } else { + define('PEAR_CONFIG_DEFAULT_EXT_DIR', '.'); } +} + +// Default for doc_dir +if (getenv('PHP_PEAR_DOC_DIR')) { + define('PEAR_CONFIG_DEFAULT_DOC_DIR', getenv('PHP_PEAR_DOC_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_DOC_DIR', + $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'docs'); +} + +// Default for bin_dir +if (getenv('PHP_PEAR_BIN_DIR')) { + define('PEAR_CONFIG_DEFAULT_BIN_DIR', getenv('PHP_PEAR_BIN_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_BIN_DIR', PHP_BINDIR); +} + +// Default for data_dir +if (getenv('PHP_PEAR_DATA_DIR')) { + define('PEAR_CONFIG_DEFAULT_DATA_DIR', getenv('PHP_PEAR_DATA_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_DATA_DIR', + $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'data'); +} + +// Default for cfg_dir +if (getenv('PHP_PEAR_CFG_DIR')) { + define('PEAR_CONFIG_DEFAULT_CFG_DIR', getenv('PHP_PEAR_CFG_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_CFG_DIR', + $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'cfg'); +} + +// Default for www_dir +if (getenv('PHP_PEAR_WWW_DIR')) { + define('PEAR_CONFIG_DEFAULT_WWW_DIR', getenv('PHP_PEAR_WWW_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_WWW_DIR', + $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'www'); +} + +// Default for test_dir +if (getenv('PHP_PEAR_TEST_DIR')) { + define('PEAR_CONFIG_DEFAULT_TEST_DIR', getenv('PHP_PEAR_TEST_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_TEST_DIR', + $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'tests'); +} + +// Default for temp_dir +if (getenv('PHP_PEAR_TEMP_DIR')) { + define('PEAR_CONFIG_DEFAULT_TEMP_DIR', getenv('PHP_PEAR_TEMP_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_TEMP_DIR', + System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' . + DIRECTORY_SEPARATOR . 'temp'); +} + +// Default for cache_dir +if (getenv('PHP_PEAR_CACHE_DIR')) { + define('PEAR_CONFIG_DEFAULT_CACHE_DIR', getenv('PHP_PEAR_CACHE_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_CACHE_DIR', + System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' . + DIRECTORY_SEPARATOR . 'cache'); +} + +// Default for download_dir +if (getenv('PHP_PEAR_DOWNLOAD_DIR')) { + define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR', getenv('PHP_PEAR_DOWNLOAD_DIR')); +} else { + define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR', + System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' . + DIRECTORY_SEPARATOR . 'download'); +} + +// Default for php_bin +if (getenv('PHP_PEAR_PHP_BIN')) { + define('PEAR_CONFIG_DEFAULT_PHP_BIN', getenv('PHP_PEAR_PHP_BIN')); +} else { + define('PEAR_CONFIG_DEFAULT_PHP_BIN', PEAR_CONFIG_DEFAULT_BIN_DIR. + DIRECTORY_SEPARATOR.'php'.(OS_WINDOWS ? '.exe' : '')); +} + +// Default for verbose +if (getenv('PHP_PEAR_VERBOSE')) { + define('PEAR_CONFIG_DEFAULT_VERBOSE', getenv('PHP_PEAR_VERBOSE')); +} else { + define('PEAR_CONFIG_DEFAULT_VERBOSE', 1); +} + +// Default for preferred_state +if (getenv('PHP_PEAR_PREFERRED_STATE')) { + define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', getenv('PHP_PEAR_PREFERRED_STATE')); +} else { + define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', 'stable'); +} + +// Default for umask +if (getenv('PHP_PEAR_UMASK')) { + define('PEAR_CONFIG_DEFAULT_UMASK', getenv('PHP_PEAR_UMASK')); +} else { + define('PEAR_CONFIG_DEFAULT_UMASK', decoct(umask())); +} + +// Default for cache_ttl +if (getenv('PHP_PEAR_CACHE_TTL')) { + define('PEAR_CONFIG_DEFAULT_CACHE_TTL', getenv('PHP_PEAR_CACHE_TTL')); +} else { + define('PEAR_CONFIG_DEFAULT_CACHE_TTL', 3600); +} + +// Default for sig_type +if (getenv('PHP_PEAR_SIG_TYPE')) { + define('PEAR_CONFIG_DEFAULT_SIG_TYPE', getenv('PHP_PEAR_SIG_TYPE')); +} else { + define('PEAR_CONFIG_DEFAULT_SIG_TYPE', 'gpg'); +} + +// Default for sig_bin +if (getenv('PHP_PEAR_SIG_BIN')) { + define('PEAR_CONFIG_DEFAULT_SIG_BIN', getenv('PHP_PEAR_SIG_BIN')); +} else { + define('PEAR_CONFIG_DEFAULT_SIG_BIN', + System::which( + 'gpg', OS_WINDOWS ? 'c:\gnupg\gpg.exe' : '/usr/local/bin/gpg')); +} + +// Default for sig_keydir +if (getenv('PHP_PEAR_SIG_KEYDIR')) { + define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR', getenv('PHP_PEAR_SIG_KEYDIR')); +} else { + define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR', + PEAR_CONFIG_SYSCONFDIR . DIRECTORY_SEPARATOR . 'pearkeys'); +} +/** + * This is a class for storing configuration data, keeping track of + * which are system-defined, user-defined or defaulted. + * @category pear + * @package PEAR + * @author Stig Bakken + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 0.1 + */ +class PEAR_Config extends PEAR +{ /** - * Parse a channel.xml file. Expects the name of - * a channel xml file as input. - * - * @param string $descfile name of channel xml file - * @return bool success of parsing + * Array of config files used. + * + * @var array layer => config file */ - function fromXmlFile($descfile) - { - if (!file_exists($descfile) || !is_file($descfile) || !is_readable($descfile) || - (!$fp = fopen($descfile, 'r'))) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR.php'; - return PEAR::raiseError("Unable to open $descfile"); - } + var $files = array( + 'system' => '', + 'user' => '', + ); - // read the whole thing so we only get one cdata callback - // for each block of cdata - fclose($fp); - $data = file_get_contents($descfile); - return $this->fromXmlString($data); - } + var $layers = array(); /** - * Parse channel information from different sources + * Configuration data, two-dimensional array where the first + * dimension is the config layer ('user', 'system' and 'default'), + * and the second dimension is keyname => value. * - * This method is able to extract information about a channel - * from an .xml file or a string + * The order in the first dimension is important! Earlier + * layers will shadow later ones when a config value is + * requested (if a 'user' value exists, it will be returned first, + * then 'system' and finally 'default'). * - * @access public - * @param string Filename of the source or the source itself - * @return bool + * @var array layer => array(keyname => value, ...) */ - function fromAny($info) - { - if (is_string($info) && file_exists($info) && strlen($info) < 255) { - $tmp = substr($info, -4); - if ($tmp == '.xml') { - $info = $this->fromXmlFile($info); - } else { - $fp = fopen($info, "r"); - $test = fread($fp, 5); - fclose($fp); - if ($test == "fromXmlFile($info); - } - } - if (PEAR::isError($info)) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR.php'; - return PEAR::raiseError($info); - } - } - if (is_string($info)) { - $info = $this->fromXmlString($info); - } - return $info; - } + var $configuration = array( + 'user' => array(), + 'system' => array(), + 'default' => array(), + ); /** - * Return an XML document based on previous parsing and modifications - * - * @return string XML data + * Configuration values that can be set for a channel * - * @access public + * All other configuration values can only have a global value + * @var array + * @access private */ - function toXml() - { - if (!$this->_isValid && !$this->validate()) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID); - return false; - } - if (!isset($this->_channelInfo['attribs']['version'])) { - $this->_channelInfo['attribs']['version'] = '1.0'; - } - $channelInfo = $this->_channelInfo; - $ret = "\n"; - $ret .= " - $channelInfo[name] - " . htmlspecialchars($channelInfo['summary'])." -"; - if (isset($channelInfo['suggestedalias'])) { - $ret .= ' ' . $channelInfo['suggestedalias'] . "\n"; - } - if (isset($channelInfo['validatepackage'])) { - $ret .= ' ' . - htmlspecialchars($channelInfo['validatepackage']['_content']) . - "\n"; - } - $ret .= " \n"; - $ret .= ' _makeRestXml($channelInfo['servers']['primary']['rest'], ' '); - } - $ret .= " \n"; - if (isset($channelInfo['servers']['mirror'])) { - $ret .= $this->_makeMirrorsXml($channelInfo); - } - $ret .= " \n"; - $ret .= ""; - return str_replace("\r", "\n", str_replace("\r\n", "\n", $ret)); - } + var $_channelConfigInfo = array( + 'php_dir', 'ext_dir', 'doc_dir', 'bin_dir', 'data_dir', 'cfg_dir', + 'test_dir', 'www_dir', 'php_bin', 'php_prefix', 'php_suffix', 'username', + 'password', 'verbose', 'preferred_state', 'umask', 'preferred_mirror', 'php_ini' + ); /** - * Generate the tag + * Channels that can be accessed + * @see setChannels() + * @var array * @access private */ - function _makeRestXml($info, $indent) - { - $ret = $indent . "\n"; - if (!isset($info['baseurl'][0])) { - $info['baseurl'] = array($info['baseurl']); - } - foreach ($info['baseurl'] as $url) { - $ret .= "$indent \n"; - } - $ret .= $indent . "\n"; - return $ret; - } + var $_channels = array('pear.php.net', 'pecl.php.net', '__uri'); /** - * Generate the tag + * This variable is used to control the directory values returned + * @see setInstallRoot(); + * @var string|false * @access private */ - function _makeMirrorsXml($channelInfo) - { - $ret = ""; - if (!isset($channelInfo['servers']['mirror'][0])) { - $channelInfo['servers']['mirror'] = array($channelInfo['servers']['mirror']); - } - foreach ($channelInfo['servers']['mirror'] as $mirror) { - $ret .= ' _makeRestXml($mirror['rest'], ' '); - } - $ret .= " \n"; - } else { - $ret .= "/>\n"; - } - } - return $ret; - } + var $_installRoot = false; /** - * Generate the tag + * If requested, this will always refer to the registry + * contained in php_dir + * @var PEAR_Registry + */ + var $_registry = array(); + + /** + * @var array * @access private */ - function _makeFunctionsXml($functions, $indent, $rest = false) - { - $ret = ''; - if (!isset($functions[0])) { - $functions = array($functions); - } - foreach ($functions as $function) { - $ret .= "$indent\n"; - } - return $ret; - } + var $_regInitialized = array(); /** - * Validation error. Also marks the object contents as invalid - * @param error code - * @param array error information + * @var bool * @access private */ - function _validateError($code, $params = array()) - { - $this->_stack->push($code, 'error', $params); - $this->_isValid = false; - } + var $_noRegistry = false; /** - * Validation warning. Does not mark the object contents invalid. - * @param error code - * @param array error information + * amount of errors found while parsing config + * @var integer * @access private */ - function _validateWarning($code, $params = array()) - { - $this->_stack->push($code, 'warning', $params); - } + var $_errorsFound = 0; + var $_lastError = null; /** - * Validate parsed file. + * Information about the configuration data. Stores the type, + * default value and a documentation string for each configuration + * value. * - * @access public - * @return boolean + * @var array layer => array(infotype => value, ...) */ - function validate() - { - $this->_isValid = true; - $info = $this->_channelInfo; - if (empty($info['name'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_NAME); - } elseif (!$this->validChannelServer($info['name'])) { - if ($info['name'] != '__uri') { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, array('tag' => 'name', - 'name' => $info['name'])); - } - } - if (empty($info['summary'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY); - } elseif (strpos(trim($info['summary']), "\n") !== false) { - $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY, - array('summary' => $info['summary'])); - } - if (isset($info['suggestedalias'])) { - if (!$this->validChannelServer($info['suggestedalias'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, - array('tag' => 'suggestedalias', 'name' =>$info['suggestedalias'])); - } - } - if (isset($info['localalias'])) { - if (!$this->validChannelServer($info['localalias'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, - array('tag' => 'localalias', 'name' =>$info['localalias'])); - } - } - if (isset($info['validatepackage'])) { - if (!isset($info['validatepackage']['_content'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME); - } - if (!isset($info['validatepackage']['attribs']['version'])) { - $content = isset($info['validatepackage']['_content']) ? - $info['validatepackage']['_content'] : - null; - $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION, - array('package' => $content)); - } - } - - if (isset($info['servers']['primary']['attribs'], $info['servers']['primary']['attribs']['port']) && - !is_numeric($info['servers']['primary']['attribs']['port'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_PORT, - array('port' => $info['servers']['primary']['attribs']['port'])); - } - - if (isset($info['servers']['primary']['attribs'], $info['servers']['primary']['attribs']['ssl']) && - $info['servers']['primary']['attribs']['ssl'] != 'yes') { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL, - array('ssl' => $info['servers']['primary']['attribs']['ssl'], - 'server' => $info['name'])); - } - - if (isset($info['servers']['primary']['rest']) && - isset($info['servers']['primary']['rest']['baseurl'])) { - $this->_validateFunctions('rest', $info['servers']['primary']['rest']['baseurl']); - } - if (isset($info['servers']['mirror'])) { - if ($this->_channelInfo['name'] == '__uri') { - $this->_validateError(PEAR_CHANNELFILE_URI_CANT_MIRROR); - } - if (!isset($info['servers']['mirror'][0])) { - $info['servers']['mirror'] = array($info['servers']['mirror']); - } - foreach ($info['servers']['mirror'] as $mirror) { - if (!isset($mirror['attribs']['host'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_HOST, - array('type' => 'mirror')); - } elseif (!$this->validChannelServer($mirror['attribs']['host'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_HOST, - array('server' => $mirror['attribs']['host'], 'type' => 'mirror')); - } - if (isset($mirror['attribs']['ssl']) && $mirror['attribs']['ssl'] != 'yes') { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL, - array('ssl' => $info['ssl'], 'server' => $mirror['attribs']['host'])); - } - if (isset($mirror['rest'])) { - $this->_validateFunctions('rest', $mirror['rest']['baseurl'], - $mirror['attribs']['host']); - } - } - } - return $this->_isValid; - } + var $configuration_info = array( + // Channels/Internet Access + 'default_channel' => array( + 'type' => 'string', + 'default' => PEAR_CONFIG_DEFAULT_CHANNEL, + 'doc' => 'the default channel to use for all non explicit commands', + 'prompt' => 'Default Channel', + 'group' => 'Internet Access', + ), + 'preferred_mirror' => array( + 'type' => 'string', + 'default' => PEAR_CONFIG_DEFAULT_CHANNEL, + 'doc' => 'the default server or mirror to use for channel actions', + 'prompt' => 'Default Channel Mirror', + 'group' => 'Internet Access', + ), + 'remote_config' => array( + 'type' => 'password', + 'default' => '', + 'doc' => 'ftp url of remote configuration file to use for synchronized install', + 'prompt' => 'Remote Configuration File', + 'group' => 'Internet Access', + ), + 'auto_discover' => array( + 'type' => 'integer', + 'default' => 0, + 'doc' => 'whether to automatically discover new channels', + 'prompt' => 'Auto-discover new Channels', + 'group' => 'Internet Access', + ), + // Internet Access + 'master_server' => array( + 'type' => 'string', + 'default' => 'pear.php.net', + 'doc' => 'name of the main PEAR server [NOT USED IN THIS VERSION]', + 'prompt' => 'PEAR server [DEPRECATED]', + 'group' => 'Internet Access', + ), + 'http_proxy' => array( + 'type' => 'string', + 'default' => PEAR_CONFIG_DEFAULT_HTTP_PROXY, + 'doc' => 'HTTP proxy (host:port) to use when downloading packages', + 'prompt' => 'HTTP Proxy Server Address', + 'group' => 'Internet Access', + ), + // File Locations + 'php_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_PHP_DIR, + 'doc' => 'directory where .php files are installed', + 'prompt' => 'PEAR directory', + 'group' => 'File Locations', + ), + 'ext_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_EXT_DIR, + 'doc' => 'directory where loadable extensions are installed', + 'prompt' => 'PHP extension directory', + 'group' => 'File Locations', + ), + 'doc_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_DOC_DIR, + 'doc' => 'directory where documentation is installed', + 'prompt' => 'PEAR documentation directory', + 'group' => 'File Locations', + ), + 'bin_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_BIN_DIR, + 'doc' => 'directory where executables are installed', + 'prompt' => 'PEAR executables directory', + 'group' => 'File Locations', + ), + 'data_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_DATA_DIR, + 'doc' => 'directory where data files are installed', + 'prompt' => 'PEAR data directory', + 'group' => 'File Locations (Advanced)', + ), + 'cfg_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_CFG_DIR, + 'doc' => 'directory where modifiable configuration files are installed', + 'prompt' => 'PEAR configuration file directory', + 'group' => 'File Locations (Advanced)', + ), + 'www_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_WWW_DIR, + 'doc' => 'directory where www frontend files (html/js) are installed', + 'prompt' => 'PEAR www files directory', + 'group' => 'File Locations (Advanced)', + ), + 'test_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_TEST_DIR, + 'doc' => 'directory where regression tests are installed', + 'prompt' => 'PEAR test directory', + 'group' => 'File Locations (Advanced)', + ), + 'cache_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_CACHE_DIR, + 'doc' => 'directory which is used for web service cache', + 'prompt' => 'PEAR Installer cache directory', + 'group' => 'File Locations (Advanced)', + ), + 'temp_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_TEMP_DIR, + 'doc' => 'directory which is used for all temp files', + 'prompt' => 'PEAR Installer temp directory', + 'group' => 'File Locations (Advanced)', + ), + 'download_dir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR, + 'doc' => 'directory which is used for all downloaded files', + 'prompt' => 'PEAR Installer download directory', + 'group' => 'File Locations (Advanced)', + ), + 'php_bin' => array( + 'type' => 'file', + 'default' => PEAR_CONFIG_DEFAULT_PHP_BIN, + 'doc' => 'PHP CLI/CGI binary for executing scripts', + 'prompt' => 'PHP CLI/CGI binary', + 'group' => 'File Locations (Advanced)', + ), + 'php_prefix' => array( + 'type' => 'string', + 'default' => '', + 'doc' => '--program-prefix for php_bin\'s ./configure, used for pecl installs', + 'prompt' => '--program-prefix passed to PHP\'s ./configure', + 'group' => 'File Locations (Advanced)', + ), + 'php_suffix' => array( + 'type' => 'string', + 'default' => '', + 'doc' => '--program-suffix for php_bin\'s ./configure, used for pecl installs', + 'prompt' => '--program-suffix passed to PHP\'s ./configure', + 'group' => 'File Locations (Advanced)', + ), + 'php_ini' => array( + 'type' => 'file', + 'default' => '', + 'doc' => 'location of php.ini in which to enable PECL extensions on install', + 'prompt' => 'php.ini location', + 'group' => 'File Locations (Advanced)', + ), + // Maintainers + 'username' => array( + 'type' => 'string', + 'default' => '', + 'doc' => '(maintainers) your PEAR account name', + 'prompt' => 'PEAR username (for maintainers)', + 'group' => 'Maintainers', + ), + 'password' => array( + 'type' => 'password', + 'default' => '', + 'doc' => '(maintainers) your PEAR account password', + 'prompt' => 'PEAR password (for maintainers)', + 'group' => 'Maintainers', + ), + // Advanced + 'verbose' => array( + 'type' => 'integer', + 'default' => PEAR_CONFIG_DEFAULT_VERBOSE, + 'doc' => 'verbosity level +0: really quiet +1: somewhat quiet +2: verbose +3: debug', + 'prompt' => 'Debug Log Level', + 'group' => 'Advanced', + ), + 'preferred_state' => array( + 'type' => 'set', + 'default' => PEAR_CONFIG_DEFAULT_PREFERRED_STATE, + 'doc' => 'the installer will prefer releases with this state when installing packages without a version or state specified', + 'valid_set' => array( + 'stable', 'beta', 'alpha', 'devel', 'snapshot'), + 'prompt' => 'Preferred Package State', + 'group' => 'Advanced', + ), + 'umask' => array( + 'type' => 'mask', + 'default' => PEAR_CONFIG_DEFAULT_UMASK, + 'doc' => 'umask used when creating files (Unix-like systems only)', + 'prompt' => 'Unix file mask', + 'group' => 'Advanced', + ), + 'cache_ttl' => array( + 'type' => 'integer', + 'default' => PEAR_CONFIG_DEFAULT_CACHE_TTL, + 'doc' => 'amount of secs where the local cache is used and not updated', + 'prompt' => 'Cache TimeToLive', + 'group' => 'Advanced', + ), + 'sig_type' => array( + 'type' => 'set', + 'default' => PEAR_CONFIG_DEFAULT_SIG_TYPE, + 'doc' => 'which package signature mechanism to use', + 'valid_set' => array('gpg'), + 'prompt' => 'Package Signature Type', + 'group' => 'Maintainers', + ), + 'sig_bin' => array( + 'type' => 'string', + 'default' => PEAR_CONFIG_DEFAULT_SIG_BIN, + 'doc' => 'which package signature mechanism to use', + 'prompt' => 'Signature Handling Program', + 'group' => 'Maintainers', + ), + 'sig_keyid' => array( + 'type' => 'string', + 'default' => '', + 'doc' => 'which key to use for signing with', + 'prompt' => 'Signature Key Id', + 'group' => 'Maintainers', + ), + 'sig_keydir' => array( + 'type' => 'directory', + 'default' => PEAR_CONFIG_DEFAULT_SIG_KEYDIR, + 'doc' => 'directory where signature keys are located', + 'prompt' => 'Signature Key Directory', + 'group' => 'Maintainers', + ), + // __channels is reserved - used for channel-specific configuration + ); /** - * @param string rest - protocol name this function applies to - * @param array the functions - * @param string the name of the parent element (mirror name, for instance) + * Constructor. + * + * @param string file to read user-defined options from + * @param string file to read system-wide defaults from + * @param bool determines whether a registry object "follows" + * the value of php_dir (is automatically created + * and moved when php_dir is changed) + * @param bool if true, fails if configuration files cannot be loaded + * + * @access public + * + * @see PEAR_Config::singleton */ - function _validateFunctions($protocol, $functions, $parent = '') + function PEAR_Config($user_file = '', $system_file = '', $ftp_file = false, + $strict = true) { - if (!isset($functions[0])) { - $functions = array($functions); - } - foreach ($functions as $function) { - if (!isset($function['_content']) || empty($function['_content'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME, - array('parent' => $parent, 'protocol' => $protocol)); - } - if ($protocol == 'rest') { - if (!isset($function['attribs']['type']) || - empty($function['attribs']['type'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_BASEURLTYPE, - array('parent' => $parent, 'protocol' => $protocol)); - } + $this->PEAR(); + PEAR_Installer_Role::initializeConfig($this); + $sl = DIRECTORY_SEPARATOR; + if (empty($user_file)) { + if (OS_WINDOWS) { + $user_file = PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini'; } else { - if (!isset($function['attribs']['version']) || - empty($function['attribs']['version'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION, - array('parent' => $parent, 'protocol' => $protocol)); - } + $user_file = getenv('HOME') . $sl . '.pearrc'; } } - } - - /** - * Test whether a string contains a valid channel server. - * @param string $ver the package version to test - * @return bool - */ - function validChannelServer($server) - { - if ($server == '__uri') { - return true; - } - return (bool) preg_match(PEAR_CHANNELS_SERVER_PREG, $server); - } - /** - * @return string|false - */ - function getName() - { - if (isset($this->_channelInfo['name'])) { - return $this->_channelInfo['name']; + if (empty($system_file)) { + $system_file = PEAR_CONFIG_SYSCONFDIR . $sl; + if (OS_WINDOWS) { + $system_file .= 'pearsys.ini'; + } else { + $system_file .= 'pear.conf'; + } } - return false; - } - - /** - * @return string|false - */ - function getServer() - { - if (isset($this->_channelInfo['name'])) { - return $this->_channelInfo['name']; + $this->layers = array_keys($this->configuration); + $this->files['user'] = $user_file; + $this->files['system'] = $system_file; + if ($user_file && file_exists($user_file)) { + $this->pushErrorHandling(PEAR_ERROR_RETURN); + $this->readConfigFile($user_file, 'user', $strict); + $this->popErrorHandling(); + if ($this->_errorsFound > 0) { + return; + } } - return false; - } - - /** - * @return int|80 port number to connect to - */ - function getPort($mirror = false) - { - if ($mirror) { - if ($mir = $this->getMirror($mirror)) { - if (isset($mir['attribs']['port'])) { - return $mir['attribs']['port']; - } - - if ($this->getSSL($mirror)) { - return 443; - } - - return 80; + if ($system_file && @file_exists($system_file)) { + $this->mergeConfigFile($system_file, false, 'system', $strict); + if ($this->_errorsFound > 0) { + return; } - return false; - } - - if (isset($this->_channelInfo['servers']['primary']['attribs']['port'])) { - return $this->_channelInfo['servers']['primary']['attribs']['port']; } - if ($this->getSSL()) { - return 443; + if (!$ftp_file) { + $ftp_file = $this->get('remote_config'); } - return 80; - } - - /** - * @return bool Determines whether secure sockets layer (SSL) is used to connect to this channel - */ - function getSSL($mirror = false) - { - if ($mirror) { - if ($mir = $this->getMirror($mirror)) { - if (isset($mir['attribs']['ssl'])) { - return true; - } - - return false; - } - - return false; + if ($ftp_file && defined('PEAR_REMOTEINSTALL_OK')) { + $this->readFTPConfigFile($ftp_file); } - if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) { - return true; + foreach ($this->configuration_info as $key => $info) { + $this->configuration['default'][$key] = $info['default']; } - return false; + $this->_registry['default'] = &new PEAR_Registry($this->configuration['default']['php_dir']); + $this->_registry['default']->setConfig($this, false); + $this->_regInitialized['default'] = false; + //$GLOBALS['_PEAR_Config_instance'] = &$this; } /** - * @return string|false + * Return the default locations of user and system configuration files + * @static */ - function getSummary() + function getDefaultConfigFiles() { - if (isset($this->_channelInfo['summary'])) { - return $this->_channelInfo['summary']; + $sl = DIRECTORY_SEPARATOR; + if (OS_WINDOWS) { + return array( + 'user' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini', + 'system' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pearsys.ini' + ); } - return false; + return array( + 'user' => getenv('HOME') . $sl . '.pearrc', + 'system' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.conf' + ); } /** - * @param string protocol type - * @param string Mirror name - * @return array|false + * Static singleton method. If you want to keep only one instance + * of this class in use, this method will give you a reference to + * the last created PEAR_Config object if one exists, or create a + * new object. + * + * @param string (optional) file to read user-defined options from + * @param string (optional) file to read system-wide defaults from + * + * @return object an existing or new PEAR_Config instance + * + * @access public + * + * @see PEAR_Config::PEAR_Config */ - function getFunctions($protocol, $mirror = false) + function &singleton($user_file = '', $system_file = '', $strict = true) { - if ($this->getName() == '__uri') { - return false; - } - - $function = $protocol == 'rest' ? 'baseurl' : 'function'; - if ($mirror) { - if ($mir = $this->getMirror($mirror)) { - if (isset($mir[$protocol][$function])) { - return $mir[$protocol][$function]; - } - } - - return false; + if (is_object($GLOBALS['_PEAR_Config_instance'])) { + return $GLOBALS['_PEAR_Config_instance']; } - if (isset($this->_channelInfo['servers']['primary'][$protocol][$function])) { - return $this->_channelInfo['servers']['primary'][$protocol][$function]; + $t_conf = &new PEAR_Config($user_file, $system_file, false, $strict); + if ($t_conf->_errorsFound > 0) { + return $t_conf->lastError; } - return false; + $GLOBALS['_PEAR_Config_instance'] = &$t_conf; + return $GLOBALS['_PEAR_Config_instance']; } /** - * @param string Protocol type - * @param string Function name (null to return the - * first protocol of the type requested) - * @param string Mirror name, if any - * @return array - */ - function getFunction($type, $name = null, $mirror = false) - { - $protocols = $this->getFunctions($type, $mirror); - if (!$protocols) { - return false; - } - - foreach ($protocols as $protocol) { - if ($name === null) { - return $protocol; - } - - if ($protocol['_content'] != $name) { - continue; - } - - return $protocol; - } - - return false; - } - - /** - * @param string protocol type - * @param string protocol name - * @param string version - * @param string mirror name - * @return boolean + * Determine whether any configuration files have been detected, and whether a + * registry object can be retrieved from this configuration. + * @return bool + * @since PEAR 1.4.0a1 */ - function supports($type, $name = null, $mirror = false, $version = '1.0') + function validConfiguration() { - $protocols = $this->getFunctions($type, $mirror); - if (!$protocols) { - return false; - } - - foreach ($protocols as $protocol) { - if ($protocol['attribs']['version'] != $version) { - continue; - } - - if ($name === null) { - return true; - } - - if ($protocol['_content'] != $name) { - continue; - } - + if ($this->isDefinedLayer('user') || $this->isDefinedLayer('system')) { return true; } @@ -56300,21072 +61419,18594 @@ } /** - * Determines whether a channel supports Representational State Transfer (REST) protocols - * for retrieving channel information - * @param string - * @return bool + * Reads configuration data from a file. All existing values in + * the config layer are discarded and replaced with data from the + * file. + * @param string file to read from, if NULL or not specified, the + * last-used file for the same layer (second param) is used + * @param string config layer to insert data into ('user' or 'system') + * @return bool TRUE on success or a PEAR error on failure */ - function supportsREST($mirror = false) + function readConfigFile($file = null, $layer = 'user', $strict = true) { - if ($mirror == $this->_channelInfo['name']) { - $mirror = false; - } - - if ($mirror) { - if ($mir = $this->getMirror($mirror)) { - return isset($mir['rest']); - } - - return false; + if (empty($this->files[$layer])) { + return $this->raiseError("unknown config layer `$layer'"); } - return isset($this->_channelInfo['servers']['primary']['rest']); - } - - /** - * Get the URL to access a base resource. - * - * Hyperlinks in the returned xml will be used to retrieve the proper information - * needed. This allows extreme extensibility and flexibility in implementation - * @param string Resource Type to retrieve - */ - function getBaseURL($resourceType, $mirror = false) - { - if ($mirror == $this->_channelInfo['name']) { - $mirror = false; + if ($file === null) { + $file = $this->files[$layer]; } - if ($mirror) { - $mir = $this->getMirror($mirror); - if (!$mir) { - return false; + $data = $this->_readConfigDataFrom($file); + if (PEAR::isError($data)) { + if (!$strict) { + return true; } - $rest = $mir['rest']; - } else { - $rest = $this->_channelInfo['servers']['primary']['rest']; - } + $this->_errorsFound++; + $this->lastError = $data; - if (!isset($rest['baseurl'][0])) { - $rest['baseurl'] = array($rest['baseurl']); + return $data; } - foreach ($rest['baseurl'] as $baseurl) { - if (strtolower($baseurl['attribs']['type']) == strtolower($resourceType)) { - return $baseurl['_content']; - } + $this->files[$layer] = $file; + $this->_decodeInput($data); + $this->configuration[$layer] = $data; + $this->_setupChannels(); + if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) { + $this->_registry[$layer] = &new PEAR_Registry($phpdir); + $this->_registry[$layer]->setConfig($this, false); + $this->_regInitialized[$layer] = false; + } else { + unset($this->_registry[$layer]); } - - return false; - } - - /** - * Since REST does not implement RPC, provide this as a logical wrapper around - * resetFunctions for REST - * @param string|false mirror name, if any - */ - function resetREST($mirror = false) - { - return $this->resetFunctions('rest', $mirror); + return true; } /** - * Empty all protocol definitions - * @param string protocol type - * @param string|false mirror name, if any + * @param string url to the remote config file, like ftp://www.example.com/pear/config.ini + * @return true|PEAR_Error */ - function resetFunctions($type, $mirror = false) + function readFTPConfigFile($path) { - if ($mirror) { - if (isset($this->_channelInfo['servers']['mirror'])) { - $mirrors = $this->_channelInfo['servers']['mirror']; - if (!isset($mirrors[0])) { - $mirrors = array($mirrors); + do { // poor man's try + if (!class_exists('PEAR_FTP')) { + if (!class_exists('PEAR_Common')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Common.php'; } - - foreach ($mirrors as $i => $mir) { - if ($mir['attribs']['host'] == $mirror) { - if (isset($this->_channelInfo['servers']['mirror'][$i][$type])) { - unset($this->_channelInfo['servers']['mirror'][$i][$type]); - } - - return true; - } + if (PEAR_Common::isIncludeable('PEAR/FTP.php')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/FTP.php'; } - - return false; } - return false; - } - - if (isset($this->_channelInfo['servers']['primary'][$type])) { - unset($this->_channelInfo['servers']['primary'][$type]); - } - - return true; - } - - /** - * Set a channel's protocols to the protocols supported by pearweb - */ - function setDefaultPEARProtocols($version = '1.0', $mirror = false) - { - switch ($version) { - case '1.0' : - $this->resetREST($mirror); - return true; - break; - default : - return false; - break; - } - } - - /** - * @return array - */ - function getMirrors() - { - if (isset($this->_channelInfo['servers']['mirror'])) { - $mirrors = $this->_channelInfo['servers']['mirror']; - if (!isset($mirrors[0])) { - $mirrors = array($mirrors); + if (!class_exists('PEAR_FTP')) { + return PEAR::raiseError('PEAR_RemoteInstaller must be installed to use remote config'); } - return $mirrors; - } - - return array(); - } - - /** - * Get the unserialized XML representing a mirror - * @return array|false - */ - function getMirror($server) - { - foreach ($this->getMirrors() as $mirror) { - if ($mirror['attribs']['host'] == $server) { - return $mirror; + $this->_ftp = &new PEAR_FTP; + $this->_ftp->pushErrorHandling(PEAR_ERROR_RETURN); + $e = $this->_ftp->init($path); + if (PEAR::isError($e)) { + $this->_ftp->popErrorHandling(); + return $e; } - } - - return false; - } - /** - * @param string - * @return string|false - * @error PEAR_CHANNELFILE_ERROR_NO_NAME - * @error PEAR_CHANNELFILE_ERROR_INVALID_NAME - */ - function setName($name) - { - return $this->setServer($name); - } + $tmp = System::mktemp('-d'); + PEAR_Common::addTempFile($tmp); + $e = $this->_ftp->get(basename($path), $tmp . DIRECTORY_SEPARATOR . + 'pear.ini', false, FTP_BINARY); + if (PEAR::isError($e)) { + $this->_ftp->popErrorHandling(); + return $e; + } - /** - * Set the socket number (port) that is used to connect to this channel - * @param integer - * @param string|false name of the mirror server, or false for the primary - */ - function setPort($port, $mirror = false) - { - if ($mirror) { - if (!isset($this->_channelInfo['servers']['mirror'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, - array('mirror' => $mirror)); - return false; + PEAR_Common::addTempFile($tmp . DIRECTORY_SEPARATOR . 'pear.ini'); + $this->_ftp->disconnect(); + $this->_ftp->popErrorHandling(); + $this->files['ftp'] = $tmp . DIRECTORY_SEPARATOR . 'pear.ini'; + $e = $this->readConfigFile(null, 'ftp'); + if (PEAR::isError($e)) { + return $e; } - if (isset($this->_channelInfo['servers']['mirror'][0])) { - foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { - if ($mirror == $mir['attribs']['host']) { - $this->_channelInfo['servers']['mirror'][$i]['attribs']['port'] = $port; - return true; + $fail = array(); + foreach ($this->configuration_info as $key => $val) { + if (in_array($this->getGroup($key), + array('File Locations', 'File Locations (Advanced)')) && + $this->getType($key) == 'directory') { + // any directory configs must be set for this to work + if (!isset($this->configuration['ftp'][$key])) { + $fail[] = $key; } } + } - return false; - } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { - $this->_channelInfo['servers']['mirror']['attribs']['port'] = $port; - $this->_isValid = false; + if (!count($fail)) { return true; } - } - $this->_channelInfo['servers']['primary']['attribs']['port'] = $port; - $this->_isValid = false; - return true; + $fail = '"' . implode('", "', $fail) . '"'; + unset($this->files['ftp']); + unset($this->configuration['ftp']); + return PEAR::raiseError('ERROR: Ftp configuration file must set all ' . + 'directory configuration variables. These variables were not set: ' . + $fail); + } while (false); // poor man's catch + unset($this->files['ftp']); + return PEAR::raiseError('no remote host specified'); } /** - * Set the socket number (port) that is used to connect to this channel - * @param bool Determines whether to turn on SSL support or turn it off - * @param string|false name of the mirror server, or false for the primary + * Reads the existing configurations and creates the _channels array from it */ - function setSSL($ssl = true, $mirror = false) + function _setupChannels() { - if ($mirror) { - if (!isset($this->_channelInfo['servers']['mirror'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, - array('mirror' => $mirror)); - return false; - } - - if (isset($this->_channelInfo['servers']['mirror'][0])) { - foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { - if ($mirror == $mir['attribs']['host']) { - if (!$ssl) { - if (isset($this->_channelInfo['servers']['mirror'][$i] - ['attribs']['ssl'])) { - unset($this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl']); - } - } else { - $this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl'] = 'yes'; - } - - return true; - } - } - - return false; - } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { - if (!$ssl) { - if (isset($this->_channelInfo['servers']['mirror']['attribs']['ssl'])) { - unset($this->_channelInfo['servers']['mirror']['attribs']['ssl']); - } - } else { - $this->_channelInfo['servers']['mirror']['attribs']['ssl'] = 'yes'; + $set = array_flip(array_values($this->_channels)); + foreach ($this->configuration as $layer => $data) { + $i = 1000; + if (isset($data['__channels']) && is_array($data['__channels'])) { + foreach ($data['__channels'] as $channel => $info) { + $set[$channel] = $i++; } - - $this->_isValid = false; - return true; } } + $this->_channels = array_values(array_flip($set)); + $this->setChannels($this->_channels); + } - if ($ssl) { - $this->_channelInfo['servers']['primary']['attribs']['ssl'] = 'yes'; - } else { - if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) { - unset($this->_channelInfo['servers']['primary']['attribs']['ssl']); + function deleteChannel($channel) + { + $ch = strtolower($channel); + foreach ($this->configuration as $layer => $data) { + if (isset($data['__channels']) && isset($data['__channels'][$ch])) { + unset($this->configuration[$layer]['__channels'][$ch]); } } - $this->_isValid = false; - return true; + $this->_channels = array_flip($this->_channels); + unset($this->_channels[$ch]); + $this->_channels = array_flip($this->_channels); } /** - * @param string - * @return string|false - * @error PEAR_CHANNELFILE_ERROR_NO_SERVER - * @error PEAR_CHANNELFILE_ERROR_INVALID_SERVER + * Merges data into a config layer from a file. Does the same + * thing as readConfigFile, except it does not replace all + * existing values in the config layer. + * @param string file to read from + * @param bool whether to overwrite existing data (default TRUE) + * @param string config layer to insert data into ('user' or 'system') + * @param string if true, errors are returned if file opening fails + * @return bool TRUE on success or a PEAR error on failure */ - function setServer($server, $mirror = false) + function mergeConfigFile($file, $override = true, $layer = 'user', $strict = true) { - if (empty($server)) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SERVER); - return false; - } elseif (!$this->validChannelServer($server)) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, - array('tag' => 'name', 'name' => $server)); - return false; + if (empty($this->files[$layer])) { + return $this->raiseError("unknown config layer `$layer'"); } - if ($mirror) { - $found = false; - foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { - if ($mirror == $mir['attribs']['host']) { - $found = true; - break; - } - } + if ($file === null) { + $file = $this->files[$layer]; + } - if (!$found) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, - array('mirror' => $mirror)); - return false; + $data = $this->_readConfigDataFrom($file); + if (PEAR::isError($data)) { + if (!$strict) { + return true; } - $this->_channelInfo['mirror'][$i]['attribs']['host'] = $server; - return true; + $this->_errorsFound++; + $this->lastError = $data; + + return $data; } - $this->_channelInfo['name'] = $server; + $this->_decodeInput($data); + if ($override) { + $this->configuration[$layer] = + PEAR_Config::arrayMergeRecursive($this->configuration[$layer], $data); + } else { + $this->configuration[$layer] = + PEAR_Config::arrayMergeRecursive($data, $this->configuration[$layer]); + } + + $this->_setupChannels(); + if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) { + $this->_registry[$layer] = &new PEAR_Registry($phpdir); + $this->_registry[$layer]->setConfig($this, false); + $this->_regInitialized[$layer] = false; + } else { + unset($this->_registry[$layer]); + } return true; } /** - * @param string - * @return boolean success - * @error PEAR_CHANNELFILE_ERROR_NO_SUMMARY - * @warning PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY + * @param array + * @param array + * @return array + * @static */ - function setSummary($summary) + function arrayMergeRecursive($arr2, $arr1) { - if (empty($summary)) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY); - return false; - } elseif (strpos(trim($summary), "\n") !== false) { - $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY, - array('summary' => $summary)); + $ret = array(); + foreach ($arr2 as $key => $data) { + if (!isset($arr1[$key])) { + $ret[$key] = $data; + unset($arr1[$key]); + continue; + } + if (is_array($data)) { + if (!is_array($arr1[$key])) { + $ret[$key] = $arr1[$key]; + unset($arr1[$key]); + continue; + } + $ret[$key] = PEAR_Config::arrayMergeRecursive($arr1[$key], $arr2[$key]); + unset($arr1[$key]); + } } - $this->_channelInfo['summary'] = $summary; - return true; + return array_merge($ret, $arr1); } /** - * @param string - * @param boolean determines whether the alias is in channel.xml or local - * @return boolean success + * Writes data into a config layer from a file. + * + * @param string|null file to read from, or null for default + * @param string config layer to insert data into ('user' or + * 'system') + * @param string|null data to write to config file or null for internal data [DEPRECATED] + * @return bool TRUE on success or a PEAR error on failure */ - function setAlias($alias, $local = false) + function writeConfigFile($file = null, $layer = 'user', $data = null) { - if (!$this->validChannelServer($alias)) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, - array('tag' => 'suggestedalias', 'name' => $alias)); - return false; + $this->_lazyChannelSetup($layer); + if ($layer == 'both' || $layer == 'all') { + foreach ($this->files as $type => $file) { + $err = $this->writeConfigFile($file, $type, $data); + if (PEAR::isError($err)) { + return $err; + } + } + return true; } - if ($local) { - $this->_channelInfo['localalias'] = $alias; - } else { - $this->_channelInfo['suggestedalias'] = $alias; + if (empty($this->files[$layer])) { + return $this->raiseError("unknown config file type `$layer'"); + } + + if ($file === null) { + $file = $this->files[$layer]; + } + + $data = ($data === null) ? $this->configuration[$layer] : $data; + $this->_encodeOutput($data); + $opt = array('-p', dirname($file)); + if (!@System::mkDir($opt)) { + return $this->raiseError("could not create directory: " . dirname($file)); + } + + if (file_exists($file) && is_file($file) && !is_writeable($file)) { + return $this->raiseError("no write access to $file!"); + } + + $fp = @fopen($file, "w"); + if (!$fp) { + return $this->raiseError("PEAR_Config::writeConfigFile fopen('$file','w') failed ($php_errormsg)"); } + $contents = "#PEAR_Config 0.9\n" . serialize($data); + if (!@fwrite($fp, $contents)) { + return $this->raiseError("PEAR_Config::writeConfigFile: fwrite failed ($php_errormsg)"); + } return true; } /** - * @return string + * Reads configuration data from a file and returns the parsed data + * in an array. + * + * @param string file to read from + * @return array configuration data or a PEAR error on failure + * @access private */ - function getAlias() + function _readConfigDataFrom($file) { - if (isset($this->_channelInfo['localalias'])) { - return $this->_channelInfo['localalias']; + $fp = false; + if (file_exists($file)) { + $fp = @fopen($file, "r"); } - if (isset($this->_channelInfo['suggestedalias'])) { - return $this->_channelInfo['suggestedalias']; + + if (!$fp) { + return $this->raiseError("PEAR_Config::readConfigFile fopen('$file','r') failed"); } - if (isset($this->_channelInfo['name'])) { - return $this->_channelInfo['name']; + + $size = filesize($file); + $rt = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + fclose($fp); + $contents = file_get_contents($file); + if (empty($contents)) { + return $this->raiseError('Configuration file "' . $file . '" is empty'); } - return ''; + + set_magic_quotes_runtime($rt); + + $version = false; + if (preg_match('/^#PEAR_Config\s+(\S+)\s+/si', $contents, $matches)) { + $version = $matches[1]; + $contents = substr($contents, strlen($matches[0])); + } else { + // Museum config file + if (substr($contents,0,2) == 'a:') { + $version = '0.1'; + } + } + + if ($version && version_compare("$version", '1', '<')) { + // no '@', it is possible that unserialize + // raises a notice but it seems to block IO to + // STDOUT if a '@' is used and a notice is raise + $data = unserialize($contents); + + if (!is_array($data) && !$data) { + if ($contents == serialize(false)) { + $data = array(); + } else { + $err = $this->raiseError("PEAR_Config: bad data in $file"); + return $err; + } + } + if (!is_array($data)) { + if (strlen(trim($contents)) > 0) { + $error = "PEAR_Config: bad data in $file"; + $err = $this->raiseError($error); + return $err; + } + + $data = array(); + } + // add parsing of newer formats here... + } else { + $err = $this->raiseError("$file: unknown version `$version'"); + return $err; + } + + return $data; } /** - * Set the package validation object if it differs from PEAR's default - * The class must be includeable via changing _ in the classname to path separator, - * but no checking of this is made. - * @param string|false pass in false to reset to the default packagename regex - * @return boolean success - */ - function setValidationPackage($validateclass, $version) + * Gets the file used for storing the config for a layer + * + * @param string $layer 'user' or 'system' + */ + function getConfFile($layer) { - if (empty($validateclass)) { - unset($this->_channelInfo['validatepackage']); - } - $this->_channelInfo['validatepackage'] = array('_content' => $validateclass); - $this->_channelInfo['validatepackage']['attribs'] = array('version' => $version); + return $this->files[$layer]; } /** - * Add a protocol to the provides section - * @param string protocol type - * @param string protocol version - * @param string protocol name, if any - * @param string mirror name, if this is a mirror's protocol - * @return bool + * @param string Configuration class name, used for detecting duplicate calls + * @param array information on a role as parsed from its xml file + * @return true|PEAR_Error + * @access private */ - function addFunction($type, $version, $name = '', $mirror = false) + function _addConfigVars($class, $vars) { - if ($mirror) { - return $this->addMirrorFunction($mirror, $type, $version, $name); + static $called = array(); + if (isset($called[$class])) { + return; } - $set = array('attribs' => array('version' => $version), '_content' => $name); - if (!isset($this->_channelInfo['servers']['primary'][$type]['function'])) { - if (!isset($this->_channelInfo['servers'])) { - $this->_channelInfo['servers'] = array('primary' => - array($type => array())); - } elseif (!isset($this->_channelInfo['servers']['primary'])) { - $this->_channelInfo['servers']['primary'] = array($type => array()); + $called[$class] = 1; + if (count($vars) > 3) { + return $this->raiseError('Roles can only define 3 new config variables or less'); + } + + foreach ($vars as $name => $var) { + if (!is_array($var)) { + return $this->raiseError('Configuration information must be an array'); } - $this->_channelInfo['servers']['primary'][$type]['function'] = $set; - $this->_isValid = false; - return true; - } elseif (!isset($this->_channelInfo['servers']['primary'][$type]['function'][0])) { - $this->_channelInfo['servers']['primary'][$type]['function'] = array( - $this->_channelInfo['servers']['primary'][$type]['function']); + if (!isset($var['type'])) { + return $this->raiseError('Configuration information must contain a type'); + } elseif (!in_array($var['type'], + array('string', 'mask', 'password', 'directory', 'file', 'set'))) { + return $this->raiseError( + 'Configuration type must be one of directory, file, string, ' . + 'mask, set, or password'); + } + if (!isset($var['default'])) { + return $this->raiseError( + 'Configuration information must contain a default value ("default" index)'); + } + + if (is_array($var['default'])) { + $real_default = ''; + foreach ($var['default'] as $config_var => $val) { + if (strpos($config_var, 'text') === 0) { + $real_default .= $val; + } elseif (strpos($config_var, 'constant') === 0) { + if (!defined($val)) { + return $this->raiseError( + 'Unknown constant "' . $val . '" requested in ' . + 'default value for configuration variable "' . + $name . '"'); + } + + $real_default .= constant($val); + } elseif (isset($this->configuration_info[$config_var])) { + $real_default .= + $this->configuration_info[$config_var]['default']; + } else { + return $this->raiseError( + 'Unknown request for "' . $config_var . '" value in ' . + 'default value for configuration variable "' . + $name . '"'); + } + } + $var['default'] = $real_default; + } + + if ($var['type'] == 'integer') { + $var['default'] = (integer) $var['default']; + } + + if (!isset($var['doc'])) { + return $this->raiseError( + 'Configuration information must contain a summary ("doc" index)'); + } + + if (!isset($var['prompt'])) { + return $this->raiseError( + 'Configuration information must contain a simple prompt ("prompt" index)'); + } + + if (!isset($var['group'])) { + return $this->raiseError( + 'Configuration information must contain a simple group ("group" index)'); + } + + if (isset($this->configuration_info[$name])) { + return $this->raiseError('Configuration variable "' . $name . + '" already exists'); + } + + $this->configuration_info[$name] = $var; + // fix bug #7351: setting custom config variable in a channel fails + $this->_channelConfigInfo[] = $name; } - $this->_channelInfo['servers']['primary'][$type]['function'][] = $set; return true; } + /** - * Add a protocol to a mirror's provides section - * @param string mirror name (server) - * @param string protocol type - * @param string protocol version - * @param string protocol name, if any + * Encodes/scrambles configuration data before writing to files. + * Currently, 'password' values will be base64-encoded as to avoid + * that people spot cleartext passwords by accident. + * + * @param array (reference) array to encode values in + * @return bool TRUE on success + * @access private */ - function addMirrorFunction($mirror, $type, $version, $name = '') + function _encodeOutput(&$data) { - if (!isset($this->_channelInfo['servers']['mirror'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, - array('mirror' => $mirror)); - return false; - } - - $setmirror = false; - if (isset($this->_channelInfo['servers']['mirror'][0])) { - foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { - if ($mirror == $mir['attribs']['host']) { - $setmirror = &$this->_channelInfo['servers']['mirror'][$i]; - break; + foreach ($data as $key => $value) { + if ($key == '__channels') { + foreach ($data['__channels'] as $channel => $blah) { + $this->_encodeOutput($data['__channels'][$channel]); } } - } else { - if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { - $setmirror = &$this->_channelInfo['servers']['mirror']; - } - } - if (!$setmirror) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, - array('mirror' => $mirror)); - return false; - } + if (!isset($this->configuration_info[$key])) { + continue; + } - $set = array('attribs' => array('version' => $version), '_content' => $name); - if (!isset($setmirror[$type]['function'])) { - $setmirror[$type]['function'] = $set; - $this->_isValid = false; - return true; - } elseif (!isset($setmirror[$type]['function'][0])) { - $setmirror[$type]['function'] = array($setmirror[$type]['function']); + $type = $this->configuration_info[$key]['type']; + switch ($type) { + // we base64-encode passwords so they are at least + // not shown in plain by accident + case 'password': { + $data[$key] = base64_encode($data[$key]); + break; + } + case 'mask': { + $data[$key] = octdec($data[$key]); + break; + } + } } - $setmirror[$type]['function'][] = $set; - $this->_isValid = false; return true; } /** - * @param string Resource Type this url links to - * @param string URL - * @param string|false mirror name, if this is not a primary server REST base URL + * Decodes/unscrambles configuration data after reading from files. + * + * @param array (reference) array to encode values in + * @return bool TRUE on success + * @access private + * + * @see PEAR_Config::_encodeOutput */ - function setBaseURL($resourceType, $url, $mirror = false) + function _decodeInput(&$data) { - if ($mirror) { - if (!isset($this->_channelInfo['servers']['mirror'])) { - $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND, - array('mirror' => $mirror)); - return false; - } + if (!is_array($data)) { + return true; + } - $setmirror = false; - if (isset($this->_channelInfo['servers']['mirror'][0])) { - foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) { - if ($mirror == $mir['attribs']['host']) { - $setmirror = &$this->_channelInfo['servers']['mirror'][$i]; - break; - } - } - } else { - if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) { - $setmirror = &$this->_channelInfo['servers']['mirror']; + foreach ($data as $key => $value) { + if ($key == '__channels') { + foreach ($data['__channels'] as $channel => $blah) { + $this->_decodeInput($data['__channels'][$channel]); } } - } else { - $setmirror = &$this->_channelInfo['servers']['primary']; - } - - $set = array('attribs' => array('type' => $resourceType), '_content' => $url); - if (!isset($setmirror['rest'])) { - $setmirror['rest'] = array(); - } - if (!isset($setmirror['rest']['baseurl'])) { - $setmirror['rest']['baseurl'] = $set; - $this->_isValid = false; - return true; - } elseif (!isset($setmirror['rest']['baseurl'][0])) { - $setmirror['rest']['baseurl'] = array($setmirror['rest']['baseurl']); - } + if (!isset($this->configuration_info[$key])) { + continue; + } - foreach ($setmirror['rest']['baseurl'] as $i => $url) { - if ($url['attribs']['type'] == $resourceType) { - $this->_isValid = false; - $setmirror['rest']['baseurl'][$i] = $set; - return true; + $type = $this->configuration_info[$key]['type']; + switch ($type) { + case 'password': { + $data[$key] = base64_decode($data[$key]); + break; + } + case 'mask': { + $data[$key] = decoct($data[$key]); + break; + } } } - $setmirror['rest']['baseurl'][] = $set; - $this->_isValid = false; return true; } /** - * @param string mirror server - * @param int mirror http port - * @return boolean + * Retrieve the default channel. + * + * On startup, channels are not initialized, so if the default channel is not + * pear.php.net, then initialize the config. + * @param string registry layer + * @return string|false */ - function addMirror($server, $port = null) + function getDefaultChannel($layer = null) { - if ($this->_channelInfo['name'] == '__uri') { - return false; // the __uri channel cannot have mirrors by definition + $ret = false; + if ($layer === null) { + foreach ($this->layers as $layer) { + if (isset($this->configuration[$layer]['default_channel'])) { + $ret = $this->configuration[$layer]['default_channel']; + break; + } + } + } elseif (isset($this->configuration[$layer]['default_channel'])) { + $ret = $this->configuration[$layer]['default_channel']; } - $set = array('attribs' => array('host' => $server)); - if (is_numeric($port)) { - $set['attribs']['port'] = $port; + if ($ret == 'pear.php.net' && defined('PEAR_RUNTYPE') && PEAR_RUNTYPE == 'pecl') { + $ret = 'pecl.php.net'; } - if (!isset($this->_channelInfo['servers']['mirror'])) { - $this->_channelInfo['servers']['mirror'] = $set; - return true; - } + if ($ret) { + if ($ret != 'pear.php.net') { + $this->_lazyChannelSetup(); + } - if (!isset($this->_channelInfo['servers']['mirror'][0])) { - $this->_channelInfo['servers']['mirror'] = - array($this->_channelInfo['servers']['mirror']); + return $ret; } - $this->_channelInfo['servers']['mirror'][] = $set; - return true; + return PEAR_CONFIG_DEFAULT_CHANNEL; } /** - * Retrieve the name of the validation package for this channel - * @return string|false + * Returns a configuration value, prioritizing layers as per the + * layers property. + * + * @param string config key + * @return mixed the config value, or NULL if not found + * @access public */ - function getValidationPackage() + function get($key, $layer = null, $channel = false) { - if (!$this->_isValid && !$this->validate()) { - return false; + if (!isset($this->configuration_info[$key])) { + return null; } - if (!isset($this->_channelInfo['validatepackage'])) { - return array('attribs' => array('version' => 'default'), - '_content' => 'PEAR_Validate'); + if ($key == '__channels') { + return null; } - return $this->_channelInfo['validatepackage']; - } + if ($key == 'default_channel') { + return $this->getDefaultChannel($layer); + } - /** - * Retrieve the object that can be used for custom validation - * @param string|false the name of the package to validate. If the package is - * the channel validation package, PEAR_Validate is returned - * @return PEAR_Validate|false false is returned if the validation package - * cannot be located - */ - function &getValidationObject($package = false) - { - if (!class_exists('PEAR_Validate')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Validate.php'; + if (!$channel) { + $channel = $this->getDefaultChannel(); + } elseif ($channel != 'pear.php.net') { + $this->_lazyChannelSetup(); } + $channel = strtolower($channel); - if (!$this->_isValid) { - if (!$this->validate()) { - $a = false; - return $a; + $test = (in_array($key, $this->_channelConfigInfo)) ? + $this->_getChannelValue($key, $layer, $channel) : + null; + if ($test !== null) { + if ($this->_installRoot) { + if (in_array($this->getGroup($key), + array('File Locations', 'File Locations (Advanced)')) && + $this->getType($key) == 'directory') { + return $this->_prependPath($test, $this->_installRoot); + } } + return $test; } - if (isset($this->_channelInfo['validatepackage'])) { - if ($package == $this->_channelInfo['validatepackage']) { - // channel validation packages are always validated by PEAR_Validate - $val = &new PEAR_Validate; - return $val; - } + if ($layer === null) { + foreach ($this->layers as $layer) { + if (isset($this->configuration[$layer][$key])) { + $test = $this->configuration[$layer][$key]; + if ($this->_installRoot) { + if (in_array($this->getGroup($key), + array('File Locations', 'File Locations (Advanced)')) && + $this->getType($key) == 'directory') { + return $this->_prependPath($test, $this->_installRoot); + } + } - if (!class_exists(str_replace('.', '_', - $this->_channelInfo['validatepackage']['_content']))) { - if ($this->isIncludeable(str_replace('_', '/', - $this->_channelInfo['validatepackage']['_content']) . '.php')) { - include_once 'phar://install-pear-nozlib.phar/' . str_replace('_', '/', - $this->_channelInfo['validatepackage']['_content']) . '.php'; - $vclass = str_replace('.', '_', - $this->_channelInfo['validatepackage']['_content']); - $val = &new $vclass; - } else { - $a = false; - return $a; + if ($key == 'preferred_mirror') { + $reg = &$this->getRegistry(); + if (is_object($reg)) { + $chan = &$reg->getChannel($channel); + if (PEAR::isError($chan)) { + return $channel; + } + + if (!$chan->getMirror($test) && $chan->getName() != $test) { + return $channel; // mirror does not exist + } + } + } + return $test; + } + } + } elseif (isset($this->configuration[$layer][$key])) { + $test = $this->configuration[$layer][$key]; + if ($this->_installRoot) { + if (in_array($this->getGroup($key), + array('File Locations', 'File Locations (Advanced)')) && + $this->getType($key) == 'directory') { + return $this->_prependPath($test, $this->_installRoot); } - } else { - $vclass = str_replace('.', '_', - $this->_channelInfo['validatepackage']['_content']); - $val = &new $vclass; } - } else { - $val = &new PEAR_Validate; - } - return $val; - } + if ($key == 'preferred_mirror') { + $reg = &$this->getRegistry(); + if (is_object($reg)) { + $chan = &$reg->getChannel($channel); + if (PEAR::isError($chan)) { + return $channel; + } - function isIncludeable($path) - { - $possibilities = explode(PATH_SEPARATOR, ini_get('include_path')); - foreach ($possibilities as $dir) { - if (file_exists($dir . DIRECTORY_SEPARATOR . $path) - && is_readable($dir . DIRECTORY_SEPARATOR . $path)) { - return true; + if (!$chan->getMirror($test) && $chan->getName() != $test) { + return $channel; // mirror does not exist + } + } } + + return $test; } - return false; + return null; } /** - * This function is used by the channel updater and retrieves a value set by - * the registry, or the current time if it has not been set - * @return string + * Returns a channel-specific configuration value, prioritizing layers as per the + * layers property. + * + * @param string config key + * @return mixed the config value, or NULL if not found + * @access private */ - function lastModified() + function _getChannelValue($key, $layer, $channel) { - if (isset($this->_channelInfo['_lastmodified'])) { - return $this->_channelInfo['_lastmodified']; + if ($key == '__channels' || $channel == 'pear.php.net') { + return null; } - return time(); - } -} - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Parser.php,v 1.7 2009/02/24 23:39:07 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * base xml parser class - */ -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/XMLParser.php'; -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/ChannelFile.php'; -/** - * Parser for channel.xml - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_ChannelFile_Parser extends PEAR_XMLParser -{ - var $_config; - var $_logger; - var $_registry; - - function setConfig(&$c) - { - $this->_config = &$c; - $this->_registry = &$c->getRegistry(); - } - - function setLogger(&$l) - { - $this->_logger = &$l; - } - - function parse($data, $file) - { - if (PEAR::isError($err = parent::parse($data, $file))) { - return $err; + $ret = null; + if ($layer === null) { + foreach ($this->layers as $ilayer) { + if (isset($this->configuration[$ilayer]['__channels'][$channel][$key])) { + $ret = $this->configuration[$ilayer]['__channels'][$channel][$key]; + break; + } + } + } elseif (isset($this->configuration[$layer]['__channels'][$channel][$key])) { + $ret = $this->configuration[$layer]['__channels'][$channel][$key]; } - $ret = new PEAR_ChannelFile; - $ret->setConfig($this->_config); - if (isset($this->_logger)) { - $ret->setLogger($this->_logger); + if ($key != 'preferred_mirror') { + return $ret; } - $ret->fromArray($this->_unserializedData); - // make sure the filelist is in the easy to read format needed - $ret->flattenFilelist(); - $ret->setPackagefile($file, $archive); - return $ret; - } -} - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Command.php,v 1.41 2009/02/24 23:38:22 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/** - * Needed for error handling - */ -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR.php'; -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Frontend.php'; -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/XMLParser.php'; -/** - * List of commands and what classes they are implemented in. - * @var array command => implementing class - */ -$GLOBALS['_PEAR_Command_commandlist'] = array(); + if ($ret !== null) { + $reg = &$this->getRegistry($layer); + if (is_object($reg)) { + $chan = &$reg->getChannel($channel); + if (PEAR::isError($chan)) { + return $channel; + } -/** - * List of commands and their descriptions - * @var array command => description - */ -$GLOBALS['_PEAR_Command_commanddesc'] = array(); + if (!$chan->getMirror($ret) && $chan->getName() != $ret) { + return $channel; // mirror does not exist + } + } -/** - * List of shortcuts to common commands. - * @var array shortcut => command - */ -$GLOBALS['_PEAR_Command_shortcuts'] = array(); + return $ret; + } -/** - * Array of command objects - * @var array class => object - */ -$GLOBALS['_PEAR_Command_objects'] = array(); + if ($channel != $this->getDefaultChannel($layer)) { + return $channel; // we must use the channel name as the preferred mirror + // if the user has not chosen an alternate + } -/** - * PEAR command class, a simple factory class for administrative - * commands. - * - * How to implement command classes: - * - * - The class must be called PEAR_Command_Nnn, installed in the - * "PEAR/Common" subdir, with a method called getCommands() that - * returns an array of the commands implemented by the class (see - * PEAR/Command/Install.php for an example). - * - * - The class must implement a run() function that is called with three - * params: - * - * (string) command name - * (array) assoc array with options, freely defined by each - * command, for example: - * array('force' => true) - * (array) list of the other parameters - * - * The run() function returns a PEAR_CommandResponse object. Use - * these methods to get information: - * - * int getStatus() Returns PEAR_COMMAND_(SUCCESS|FAILURE|PARTIAL) - * *_PARTIAL means that you need to issue at least - * one more command to complete the operation - * (used for example for validation steps). - * - * string getMessage() Returns a message for the user. Remember, - * no HTML or other interface-specific markup. - * - * If something unexpected happens, run() returns a PEAR error. - * - * - DON'T OUTPUT ANYTHING! Return text for output instead. - * - * - DON'T USE HTML! The text you return will be used from both Gtk, - * web and command-line interfaces, so for now, keep everything to - * plain text. - * - * - DON'T USE EXIT OR DIE! Always use pear errors. From static - * classes do PEAR::raiseError(), from other classes do - * $this->raiseError(). - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 - */ -class PEAR_Command -{ - // {{{ factory() + return $this->getDefaultChannel($layer); + } /** - * Get the right object for executing a command. - * - * @param string $command The name of the command - * @param object $config Instance of PEAR_Config object - * - * @return object the command object or a PEAR error + * Set a config value in a specific layer (defaults to 'user'). + * Enforces the types defined in the configuration_info array. An + * integer config variable will be cast to int, and a set config + * variable will be validated against its legal values. * - * @access public - * @static + * @param string config key + * @param string config value + * @param string (optional) config layer + * @param string channel to set this value for, or null for global value + * @return bool TRUE on success, FALSE on failure */ - function &factory($command, &$config) + function set($key, $value, $layer = 'user', $channel = false) { - if (empty($GLOBALS['_PEAR_Command_commandlist'])) { - PEAR_Command::registerCommands(); + if ($key == '__channels') { + return false; } - if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) { - $command = $GLOBALS['_PEAR_Command_shortcuts'][$command]; + + if (!isset($this->configuration[$layer])) { + return false; } - if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) { - $a = PEAR::raiseError("unknown command `$command'"); - return $a; + + if ($key == 'default_channel') { + // can only set this value globally + $channel = 'pear.php.net'; + if ($value != 'pear.php.net') { + $this->_lazyChannelSetup($layer); + } + } + + if ($key == 'preferred_mirror') { + if ($channel == '__uri') { + return false; // can't set the __uri pseudo-channel's mirror + } + + $reg = &$this->getRegistry($layer); + if (is_object($reg)) { + $chan = &$reg->getChannel($channel ? $channel : 'pear.php.net'); + if (PEAR::isError($chan)) { + return false; + } + + if (!$chan->getMirror($value) && $chan->getName() != $value) { + return false; // mirror does not exist + } + } } - $class = $GLOBALS['_PEAR_Command_commandlist'][$command]; - if (!class_exists($class)) { - require_once $GLOBALS['_PEAR_Command_objects'][$class]; + + if (!isset($this->configuration_info[$key])) { + return false; } - if (!class_exists($class)) { - $a = PEAR::raiseError("unknown command `$command'"); - return $a; + + extract($this->configuration_info[$key]); + switch ($type) { + case 'integer': + $value = (int)$value; + break; + case 'set': { + // If a valid_set is specified, require the value to + // be in the set. If there is no valid_set, accept + // any value. + if ($valid_set) { + reset($valid_set); + if ((key($valid_set) === 0 && !in_array($value, $valid_set)) || + (key($valid_set) !== 0 && empty($valid_set[$value]))) + { + return false; + } + } + break; + } } - $ui =& PEAR_Command::getFrontendObject(); - $obj = &new $class($ui, $config); - return $obj; - } - // }}} - // {{{ & getObject() - function &getObject($command) - { - $class = $GLOBALS['_PEAR_Command_commandlist'][$command]; - if (!class_exists($class)) { - require_once $GLOBALS['_PEAR_Command_objects'][$class]; + if (!$channel) { + $channel = $this->get('default_channel', null, 'pear.php.net'); } - if (!class_exists($class)) { - return PEAR::raiseError("unknown command `$command'"); + + if (!in_array($channel, $this->_channels)) { + $this->_lazyChannelSetup($layer); + $reg = &$this->getRegistry($layer); + if ($reg) { + $channel = $reg->channelName($channel); + } + + if (!in_array($channel, $this->_channels)) { + return false; + } } - $ui =& PEAR_Command::getFrontendObject(); - $config = &PEAR_Config::singleton(); - $obj = &new $class($ui, $config); - return $obj; - } - // }}} - // {{{ & getFrontendObject() + if ($channel != 'pear.php.net') { + if (in_array($key, $this->_channelConfigInfo)) { + $this->configuration[$layer]['__channels'][$channel][$key] = $value; + return true; + } - /** - * Get instance of frontend object. - * - * @return object|PEAR_Error - * @static - */ - function &getFrontendObject() - { - $a = &PEAR_Frontend::singleton(); - return $a; - } + return false; + } - // }}} - // {{{ & setFrontendClass() + if ($key == 'default_channel') { + if (!isset($reg)) { + $reg = &$this->getRegistry($layer); + if (!$reg) { + $reg = &$this->getRegistry(); + } + } - /** - * Load current frontend class. - * - * @param string $uiclass Name of class implementing the frontend - * - * @return object the frontend object, or a PEAR error - * @static - */ - function &setFrontendClass($uiclass) - { - $a = &PEAR_Frontend::setFrontendClass($uiclass); - return $a; - } + if ($reg) { + $value = $reg->channelName($value); + } - // }}} - // {{{ setFrontendType() + if (!$value) { + return false; + } + } - /** - * Set current frontend. - * - * @param string $uitype Name of the frontend type (for example "CLI") - * - * @return object the frontend object, or a PEAR error - * @static - */ - function setFrontendType($uitype) - { - $uiclass = 'PEAR_Frontend_' . $uitype; - return PEAR_Command::setFrontendClass($uiclass); - } + $this->configuration[$layer][$key] = $value; + if ($key == 'php_dir' && !$this->_noRegistry) { + if (!isset($this->_registry[$layer]) || + $value != $this->_registry[$layer]->install_dir) { + $this->_registry[$layer] = &new PEAR_Registry($value); + $this->_regInitialized[$layer] = false; + $this->_registry[$layer]->setConfig($this, false); + } + } - // }}} - // {{{ registerCommands() + return true; + } - /** - * Scan through the Command directory looking for classes - * and see what commands they implement. - * - * @param bool (optional) if FALSE (default), the new list of - * commands should replace the current one. If TRUE, - * new entries will be merged with old. - * - * @param string (optional) where (what directory) to look for - * classes, defaults to the Command subdirectory of - * the directory from where this file (__FILE__) is - * included. - * - * @return bool TRUE on success, a PEAR error on failure - * - * @access public - * @static - */ - function registerCommands($merge = false, $dir = null) + function _lazyChannelSetup($uselayer = false) { - $parser = new PEAR_XMLParser; - if ($dir === null) { - $dir = dirname(__FILE__) . '/Command'; - } - if (!is_dir($dir)) { - return PEAR::raiseError("registerCommands: opendir($dir) '$dir' does not exist or is not a directory"); - } - $dp = @opendir($dir); - if (empty($dp)) { - return PEAR::raiseError("registerCommands: opendir($dir) failed"); - } - if (!$merge) { - $GLOBALS['_PEAR_Command_commandlist'] = array(); + if ($this->_noRegistry) { + return; } - while ($entry = readdir($dp)) { - if ($entry{0} == '.' || substr($entry, -4) != '.xml') { + + $merge = false; + foreach ($this->_registry as $layer => $p) { + if ($uselayer && $uselayer != $layer) { continue; } - $class = "PEAR_Command_".substr($entry, 0, -4); - $file = "$dir/$entry"; - $parser->parse(file_get_contents($file)); - $implements = $parser->getData(); - // List of commands - if (empty($GLOBALS['_PEAR_Command_objects'][$class])) { - $GLOBALS['_PEAR_Command_objects'][$class] = "$dir/" . substr($entry, 0, -4) . - '.php'; - } - foreach ($implements as $command => $desc) { - if ($command == 'attribs') { + + if (!$this->_regInitialized[$layer]) { + if ($layer == 'default' && isset($this->_registry['user']) || + isset($this->_registry['system'])) { + // only use the default registry if there are no alternatives continue; } - if (isset($GLOBALS['_PEAR_Command_commandlist'][$command])) { - return PEAR::raiseError('Command "' . $command . '" already registered in ' . - 'class "' . $GLOBALS['_PEAR_Command_commandlist'][$command] . '"'); - } - $GLOBALS['_PEAR_Command_commandlist'][$command] = $class; - $GLOBALS['_PEAR_Command_commanddesc'][$command] = $desc['summary']; - if (isset($desc['shortcut'])) { - $shortcut = $desc['shortcut']; - if (isset($GLOBALS['_PEAR_Command_shortcuts'][$shortcut])) { - return PEAR::raiseError('Command shortcut "' . $shortcut . '" already ' . - 'registered to command "' . $command . '" in class "' . - $GLOBALS['_PEAR_Command_commandlist'][$command] . '"'); - } - $GLOBALS['_PEAR_Command_shortcuts'][$shortcut] = $command; - } - if (isset($desc['options']) && $desc['options']) { - foreach ($desc['options'] as $oname => $option) { - if (isset($option['shortopt']) && strlen($option['shortopt']) > 1) { - return PEAR::raiseError('Option "' . $oname . '" short option "' . - $option['shortopt'] . '" must be ' . - 'only 1 character in Command "' . $command . '" in class "' . - $class . '"'); - } + + if (!is_object($this->_registry[$layer])) { + if ($phpdir = $this->get('php_dir', $layer, 'pear.php.net')) { + $this->_registry[$layer] = &new PEAR_Registry($phpdir); + $this->_registry[$layer]->setConfig($this, false); + $this->_regInitialized[$layer] = false; + } else { + unset($this->_registry[$layer]); + return; } } + + $this->setChannels($this->_registry[$layer]->listChannels(), $merge); + $this->_regInitialized[$layer] = true; + $merge = true; } } - ksort($GLOBALS['_PEAR_Command_shortcuts']); - ksort($GLOBALS['_PEAR_Command_commandlist']); - @closedir($dp); - return true; } - // }}} - // {{{ getCommands() - /** - * Get the list of currently supported commands, and what - * classes implement them. - * - * @return array command => implementing class + * Set the list of channels. * - * @access public - * @static + * This should be set via a call to {@link PEAR_Registry::listChannels()} + * @param array + * @param bool + * @return bool success of operation */ - function getCommands() + function setChannels($channels, $merge = false) { - if (empty($GLOBALS['_PEAR_Command_commandlist'])) { - PEAR_Command::registerCommands(); + if (!is_array($channels)) { + return false; } - return $GLOBALS['_PEAR_Command_commandlist']; - } - // }}} - // {{{ getShortcuts() + if ($merge) { + $this->_channels = array_merge($this->_channels, $channels); + } else { + $this->_channels = $channels; + } - /** - * Get the list of command shortcuts. - * - * @return array shortcut => command - * - * @access public - * @static - */ - function getShortcuts() - { - if (empty($GLOBALS['_PEAR_Command_shortcuts'])) { - PEAR_Command::registerCommands(); + foreach ($channels as $channel) { + $channel = strtolower($channel); + if ($channel == 'pear.php.net') { + continue; + } + + foreach ($this->layers as $layer) { + if (!isset($this->configuration[$layer]['__channels'])) { + $this->configuration[$layer]['__channels'] = array(); + } + if (!isset($this->configuration[$layer]['__channels'][$channel]) + || !is_array($this->configuration[$layer]['__channels'][$channel])) { + $this->configuration[$layer]['__channels'][$channel] = array(); + } + } } - return $GLOBALS['_PEAR_Command_shortcuts']; - } - // }}} - // {{{ getGetoptArgs() + return true; + } /** - * Compiles arguments for getopt. + * Get the type of a config value. * - * @param string $command command to get optstring for - * @param string $short_args (reference) short getopt format - * @param array $long_args (reference) long getopt format + * @param string config key * - * @return void + * @return string type, one of "string", "integer", "file", + * "directory", "set" or "password". * * @access public - * @static + * */ - function getGetoptArgs($command, &$short_args, &$long_args) + function getType($key) { - if (empty($GLOBALS['_PEAR_Command_commandlist'])) { - PEAR_Command::registerCommands(); - } - if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) { - $command = $GLOBALS['_PEAR_Command_shortcuts'][$command]; - } - if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) { - return null; + if (isset($this->configuration_info[$key])) { + return $this->configuration_info[$key]['type']; } - $obj = &PEAR_Command::getObject($command); - return $obj->getGetoptArgs($command, $short_args, $long_args); + return false; } - // }}} - // {{{ getDescription() - /** - * Get description for a command. - * - * @param string $command Name of the command + * Get the documentation for a config value. * - * @return string command description + * @param string config key + * @return string documentation string * * @access public - * @static + * */ - function getDescription($command) + function getDocs($key) { - if (!isset($GLOBALS['_PEAR_Command_commanddesc'][$command])) { - return null; + if (isset($this->configuration_info[$key])) { + return $this->configuration_info[$key]['doc']; } - return $GLOBALS['_PEAR_Command_commanddesc'][$command]; - } - // }}} - // {{{ getHelp() + return false; + } /** - * Get help for command. + * Get the short documentation for a config value. * - * @param string $command Name of the command to return help for + * @param string config key + * @return string short documentation string * * @access public - * @static + * */ - function getHelp($command) + function getPrompt($key) { - $cmds = PEAR_Command::getCommands(); - if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) { - $command = $GLOBALS['_PEAR_Command_shortcuts'][$command]; - } - if (isset($cmds[$command])) { - $obj = &PEAR_Command::getObject($command); - return $obj->getHelp($command); + if (isset($this->configuration_info[$key])) { + return $this->configuration_info[$key]['prompt']; } + return false; } - // }}} -} - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Common.php,v 1.39 2009/02/24 23:39:29 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/** - * base class - */ -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR.php'; -/** - * PEAR commands base class - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 - */ -class PEAR_Command_Common extends PEAR -{ /** - * PEAR_Config object used to pass user system and configuration - * on when executing commands + * Get the parameter group for a config key. * - * @var PEAR_Config - */ - var $config; - /** - * @var PEAR_Registry - * @access protected - */ - var $_registry; - - /** - * User Interface object, for all interaction with the user. - * @var object - */ - var $ui; - - var $_deps_rel_trans = array( - 'lt' => '<', - 'le' => '<=', - 'eq' => '=', - 'ne' => '!=', - 'gt' => '>', - 'ge' => '>=', - 'has' => '==' - ); - - var $_deps_type_trans = array( - 'pkg' => 'package', - 'ext' => 'extension', - 'php' => 'PHP', - 'prog' => 'external program', - 'ldlib' => 'external library for linking', - 'rtlib' => 'external runtime library', - 'os' => 'operating system', - 'websrv' => 'web server', - 'sapi' => 'SAPI backend' - ); - - /** - * PEAR_Command_Common constructor. + * @param string config key + * @return string parameter group * * @access public + * */ - function PEAR_Command_Common(&$ui, &$config) + function getGroup($key) { - parent::PEAR(); - $this->config = &$config; - $this->ui = &$ui; + if (isset($this->configuration_info[$key])) { + return $this->configuration_info[$key]['group']; + } + + return false; } /** - * Return a list of all the commands defined by this class. - * @return array list of commands + * Get the list of parameter groups. + * + * @return array list of parameter groups + * * @access public + * */ - function getCommands() + function getGroups() { - $ret = array(); - foreach (array_keys($this->commands) as $command) { - $ret[$command] = $this->commands[$command]['summary']; + $tmp = array(); + foreach ($this->configuration_info as $key => $info) { + $tmp[$info['group']] = 1; } - return $ret; + return array_keys($tmp); } /** - * Return a list of all the command shortcuts defined by this class. - * @return array shortcut => command + * Get the list of the parameters in a group. + * + * @param string $group parameter group + * @return array list of parameters in $group + * * @access public + * */ - function getShortcuts() + function getGroupKeys($group) { - $ret = array(); - foreach (array_keys($this->commands) as $command) { - if (isset($this->commands[$command]['shortcut'])) { - $ret[$this->commands[$command]['shortcut']] = $command; + $keys = array(); + foreach ($this->configuration_info as $key => $info) { + if ($info['group'] == $group) { + $keys[] = $key; } } - return $ret; + return $keys; } - function getOptions($command) - { - $shortcuts = $this->getShortcuts(); - if (isset($shortcuts[$command])) { - $command = $shortcuts[$command]; - } + /** + * Get the list of allowed set values for a config value. Returns + * NULL for config values that are not sets. + * + * @param string config key + * @return array enumerated array of set values, or NULL if the + * config key is unknown or not a set + * + * @access public + * + */ + function getSetValues($key) + { + if (isset($this->configuration_info[$key]) && + isset($this->configuration_info[$key]['type']) && + $this->configuration_info[$key]['type'] == 'set') + { + $valid_set = $this->configuration_info[$key]['valid_set']; + reset($valid_set); + if (key($valid_set) === 0) { + return $valid_set; + } - if (isset($this->commands[$command]) && - isset($this->commands[$command]['options'])) { - return $this->commands[$command]['options']; + return array_keys($valid_set); } return null; } - function getGetoptArgs($command, &$short_args, &$long_args) + /** + * Get all the current config keys. + * + * @return array simple array of config keys + * + * @access public + */ + function getKeys() { - $short_args = ''; - $long_args = array(); - if (empty($this->commands[$command]) || empty($this->commands[$command]['options'])) { - return; - } - - reset($this->commands[$command]['options']); - while (list($option, $info) = each($this->commands[$command]['options'])) { - $larg = $sarg = ''; - if (isset($info['arg'])) { - if ($info['arg']{0} == '(') { - $larg = '=='; - $sarg = '::'; - $arg = substr($info['arg'], 1, -1); - } else { - $larg = '='; - $sarg = ':'; - $arg = $info['arg']; + $keys = array(); + foreach ($this->layers as $layer) { + $test = $this->configuration[$layer]; + if (isset($test['__channels'])) { + foreach ($test['__channels'] as $channel => $configs) { + $keys = array_merge($keys, $configs); } } - if (isset($info['shortopt'])) { - $short_args .= $info['shortopt'] . $sarg; - } + unset($test['__channels']); + $keys = array_merge($keys, $test); - $long_args[] = $option . $larg; } + return array_keys($keys); } /** - * Returns the help message for the given command - * - * @param string $command The command - * @return mixed A fail string if the command does not have help or - * a two elements array containing [0]=>help string, - * [1]=> help string for the accepted cmd args - */ - function getHelp($command) + * Remove the a config key from a specific config layer. + * + * @param string config key + * @param string (optional) config layer + * @param string (optional) channel (defaults to default channel) + * @return bool TRUE on success, FALSE on failure + * + * @access public + */ + function remove($key, $layer = 'user', $channel = null) { - $config = &PEAR_Config::singleton(); - if (!isset($this->commands[$command])) { - return "No such command \"$command\""; - } - - $help = null; - if (isset($this->commands[$command]['doc'])) { - $help = $this->commands[$command]['doc']; + if ($channel === null) { + $channel = $this->getDefaultChannel(); } - if (empty($help)) { - // XXX (cox) Fallback to summary if there is no doc (show both?) - if (!isset($this->commands[$command]['summary'])) { - return "No help for command \"$command\""; + if ($channel !== 'pear.php.net') { + if (isset($this->configuration[$layer]['__channels'][$channel][$key])) { + unset($this->configuration[$layer]['__channels'][$channel][$key]); + return true; } - $help = $this->commands[$command]['summary']; } - if (preg_match_all('/{config\s+([^\}]+)}/e', $help, $matches)) { - foreach($matches[0] as $k => $v) { - $help = preg_replace("/$v/", $config->get($matches[1][$k]), $help); - } + if (isset($this->configuration[$layer][$key])) { + unset($this->configuration[$layer][$key]); + return true; } - return array($help, $this->getHelpArgs($command)); + return false; } /** - * Returns the help for the accepted arguments of a command + * Temporarily remove an entire config layer. USE WITH CARE! * - * @param string $command - * @return string The help string + * @param string config key + * @param string (optional) config layer + * @return bool TRUE on success, FALSE on failure + * + * @access public */ - function getHelpArgs($command) + function removeLayer($layer) { - if (isset($this->commands[$command]['options']) && - count($this->commands[$command]['options'])) - { - $help = "Options:\n"; - foreach ($this->commands[$command]['options'] as $k => $v) { - if (isset($v['arg'])) { - if ($v['arg'][0] == '(') { - $arg = substr($v['arg'], 1, -1); - $sapp = " [$arg]"; - $lapp = "[=$arg]"; - } else { - $sapp = " $v[arg]"; - $lapp = "=$v[arg]"; - } - } else { - $sapp = $lapp = ""; - } - - if (isset($v['shortopt'])) { - $s = $v['shortopt']; - $help .= " -$s$sapp, --$k$lapp\n"; - } else { - $help .= " --$k$lapp\n"; - } - - $p = " "; - $doc = rtrim(str_replace("\n", "\n$p", $v['doc'])); - $help .= " $doc\n"; - } - - return $help; + if (isset($this->configuration[$layer])) { + $this->configuration[$layer] = array(); + return true; } - return null; + return false; } - function run($command, $options, $params) + /** + * Stores configuration data in a layer. + * + * @param string config layer to store + * @return bool TRUE on success, or PEAR error on failure + * + * @access public + */ + function store($layer = 'user', $data = null) { - if (empty($this->commands[$command]['function'])) { - // look for shortcuts - foreach (array_keys($this->commands) as $cmd) { - if (isset($this->commands[$cmd]['shortcut']) && $this->commands[$cmd]['shortcut'] == $command) { - if (empty($this->commands[$cmd]['function'])) { - return $this->raiseError("unknown command `$command'"); - } else { - $func = $this->commands[$cmd]['function']; + return $this->writeConfigFile(null, $layer, $data); + } + + /** + * Tells what config layer that gets to define a key. + * + * @param string config key + * @param boolean return the defining channel + * + * @return string|array the config layer, or an empty string if not found. + * + * if $returnchannel, the return is an array array('layer' => layername, + * 'channel' => channelname), or an empty string if not found + * + * @access public + */ + function definedBy($key, $returnchannel = false) + { + foreach ($this->layers as $layer) { + $channel = $this->getDefaultChannel(); + if ($channel !== 'pear.php.net') { + if (isset($this->configuration[$layer]['__channels'][$channel][$key])) { + if ($returnchannel) { + return array('layer' => $layer, 'channel' => $channel); } - $command = $cmd; + return $layer; + } + } - //$command = $this->commands[$cmd]['function']; - break; + if (isset($this->configuration[$layer][$key])) { + if ($returnchannel) { + return array('layer' => $layer, 'channel' => 'pear.php.net'); } + return $layer; } - } else { - $func = $this->commands[$command]['function']; } - return $this->$func($command, $options, $params); + return ''; } -} - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Install.php,v 1.153 2009/03/08 04:01:11 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/** - * base class - */ -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Command/Common.php'; - -/** - * PEAR commands for installation or deinstallation/upgrading of - * packages. - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 - */ -class PEAR_Command_Install extends PEAR_Command_Common -{ - // {{{ properties - - var $commands = array( - 'install' => array( - 'summary' => 'Install Package', - 'function' => 'doInstall', - 'shortcut' => 'i', - 'options' => array( - 'force' => array( - 'shortopt' => 'f', - 'doc' => 'will overwrite newer installed packages', - ), - 'loose' => array( - 'shortopt' => 'l', - 'doc' => 'do not check for recommended dependency version', - ), - 'nodeps' => array( - 'shortopt' => 'n', - 'doc' => 'ignore dependencies, install anyway', - ), - 'register-only' => array( - 'shortopt' => 'r', - 'doc' => 'do not install files, only register the package as installed', - ), - 'soft' => array( - 'shortopt' => 's', - 'doc' => 'soft install, fail silently, or upgrade if already installed', - ), - 'nobuild' => array( - 'shortopt' => 'B', - 'doc' => 'don\'t build C extensions', - ), - 'nocompress' => array( - 'shortopt' => 'Z', - 'doc' => 'request uncompressed files when downloading', - ), - 'installroot' => array( - 'shortopt' => 'R', - 'arg' => 'DIR', - 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM', - ), - 'packagingroot' => array( - 'shortopt' => 'P', - 'arg' => 'DIR', - 'doc' => 'root directory used when packaging files, like RPM packaging', - ), - 'ignore-errors' => array( - 'doc' => 'force install even if there were errors', - ), - 'alldeps' => array( - 'shortopt' => 'a', - 'doc' => 'install all required and optional dependencies', - ), - 'onlyreqdeps' => array( - 'shortopt' => 'o', - 'doc' => 'install all required dependencies', - ), - 'offline' => array( - 'shortopt' => 'O', - 'doc' => 'do not attempt to download any urls or contact channels', - ), - 'pretend' => array( - 'shortopt' => 'p', - 'doc' => 'Only list the packages that would be downloaded', - ), - ), - 'doc' => '[channel/] ... -Installs one or more PEAR packages. You can specify a package to -install in four ways: - -"Package-1.0.tgz" : installs from a local file - -"http://example.com/Package-1.0.tgz" : installs from -anywhere on the net. - -"package.xml" : installs the package described in -package.xml. Useful for testing, or for wrapping a PEAR package in -another package manager such as RPM. - -"Package[-version/state][.tar]" : queries your default channel\'s server -({config master_server}) and downloads the newest package with -the preferred quality/state ({config preferred_state}). - -To retrieve Package version 1.1, use "Package-1.1," to retrieve -Package state beta, use "Package-beta." To retrieve an uncompressed -file, append .tar (make sure there is no file by the same name first) - -To download a package from another channel, prefix with the channel name like -"channel/Package" - -More than one package may be specified at once. It is ok to mix these -four ways of specifying packages. -'), - 'upgrade' => array( - 'summary' => 'Upgrade Package', - 'function' => 'doInstall', - 'shortcut' => 'up', - 'options' => array( - 'channel' => array( - 'shortopt' => 'c', - 'doc' => 'upgrade packages from a specific channel', - 'arg' => 'CHAN', - ), - 'force' => array( - 'shortopt' => 'f', - 'doc' => 'overwrite newer installed packages', - ), - 'loose' => array( - 'shortopt' => 'l', - 'doc' => 'do not check for recommended dependency version', - ), - 'nodeps' => array( - 'shortopt' => 'n', - 'doc' => 'ignore dependencies, upgrade anyway', - ), - 'register-only' => array( - 'shortopt' => 'r', - 'doc' => 'do not install files, only register the package as upgraded', - ), - 'nobuild' => array( - 'shortopt' => 'B', - 'doc' => 'don\'t build C extensions', - ), - 'nocompress' => array( - 'shortopt' => 'Z', - 'doc' => 'request uncompressed files when downloading', - ), - 'installroot' => array( - 'shortopt' => 'R', - 'arg' => 'DIR', - 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)', - ), - 'ignore-errors' => array( - 'doc' => 'force install even if there were errors', - ), - 'alldeps' => array( - 'shortopt' => 'a', - 'doc' => 'install all required and optional dependencies', - ), - 'onlyreqdeps' => array( - 'shortopt' => 'o', - 'doc' => 'install all required dependencies', - ), - 'offline' => array( - 'shortopt' => 'O', - 'doc' => 'do not attempt to download any urls or contact channels', - ), - 'pretend' => array( - 'shortopt' => 'p', - 'doc' => 'Only list the packages that would be downloaded', - ), - ), - 'doc' => ' ... -Upgrades one or more PEAR packages. See documentation for the -"install" command for ways to specify a package. - -When upgrading, your package will be updated if the provided new -package has a higher version number (use the -f option if you need to -upgrade anyway). - -More than one package may be specified at once. -'), - 'upgrade-all' => array( - 'summary' => 'Upgrade All Packages [Deprecated in favor of calling upgrade with no parameters]', - 'function' => 'doUpgradeAll', - 'shortcut' => 'ua', - 'options' => array( - 'channel' => array( - 'shortopt' => 'c', - 'doc' => 'upgrade packages from a specific channel', - 'arg' => 'CHAN', - ), - 'nodeps' => array( - 'shortopt' => 'n', - 'doc' => 'ignore dependencies, upgrade anyway', - ), - 'register-only' => array( - 'shortopt' => 'r', - 'doc' => 'do not install files, only register the package as upgraded', - ), - 'nobuild' => array( - 'shortopt' => 'B', - 'doc' => 'don\'t build C extensions', - ), - 'nocompress' => array( - 'shortopt' => 'Z', - 'doc' => 'request uncompressed files when downloading', - ), - 'installroot' => array( - 'shortopt' => 'R', - 'arg' => 'DIR', - 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM', - ), - 'ignore-errors' => array( - 'doc' => 'force install even if there were errors', - ), - 'loose' => array( - 'doc' => 'do not check for recommended dependency version', - ), - ), - 'doc' => ' -WARNING: This function is deprecated in favor of using the upgrade command with no params -Upgrades all packages that have a newer release available. Upgrades are -done only if there is a release available of the state specified in -"preferred_state" (currently {config preferred_state}), or a state considered -more stable. -'), - 'uninstall' => array( - 'summary' => 'Un-install Package', - 'function' => 'doUninstall', - 'shortcut' => 'un', - 'options' => array( - 'nodeps' => array( - 'shortopt' => 'n', - 'doc' => 'ignore dependencies, uninstall anyway', - ), - 'register-only' => array( - 'shortopt' => 'r', - 'doc' => 'do not remove files, only register the packages as not installed', - ), - 'installroot' => array( - 'shortopt' => 'R', - 'arg' => 'DIR', - 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)', - ), - 'ignore-errors' => array( - 'doc' => 'force install even if there were errors', - ), - 'offline' => array( - 'shortopt' => 'O', - 'doc' => 'do not attempt to uninstall remotely', - ), - ), - 'doc' => '[channel/] ... -Uninstalls one or more PEAR packages. More than one package may be -specified at once. Prefix with channel name to uninstall from a -channel not in your default channel ({config default_channel}) -'), - 'bundle' => array( - 'summary' => 'Unpacks a Pecl Package', - 'function' => 'doBundle', - 'shortcut' => 'bun', - 'options' => array( - 'destination' => array( - 'shortopt' => 'd', - 'arg' => 'DIR', - 'doc' => 'Optional destination directory for unpacking (defaults to current path or "ext" if exists)', - ), - 'force' => array( - 'shortopt' => 'f', - 'doc' => 'Force the unpacking even if there were errors in the package', - ), - ), - 'doc' => ' -Unpacks a Pecl Package into the selected location. It will download the -package if needed. -'), - 'run-scripts' => array( - 'summary' => 'Run Post-Install Scripts bundled with a package', - 'function' => 'doRunScripts', - 'shortcut' => 'rs', - 'options' => array( - ), - 'doc' => ' -Run post-installation scripts in package , if any exist. -'), - ); + /** + * Tells whether a given key exists as a config value. + * + * @param string config key + * @return bool whether exists in this object + * + * @access public + */ + function isDefined($key) + { + foreach ($this->layers as $layer) { + if (isset($this->configuration[$layer][$key])) { + return true; + } + } - // }}} - // {{{ constructor + return false; + } /** - * PEAR_Command_Install constructor. + * Tells whether a given config layer exists. + * + * @param string config layer + * @return bool whether exists in this object * * @access public */ - function PEAR_Command_Install(&$ui, &$config) + function isDefinedLayer($layer) { - parent::PEAR_Command_Common($ui, $config); + return isset($this->configuration[$layer]); } - // }}} + /** + * Returns the layers defined (except the 'default' one) + * + * @return array of the defined layers + */ + function getLayers() + { + $cf = $this->configuration; + unset($cf['default']); + return array_keys($cf); + } + + function apiVersion() + { + return '1.1'; + } /** - * For unit testing purposes + * @return PEAR_Registry */ - function &getDownloader(&$ui, $options, &$config) + function &getRegistry($use = null) { - if (!class_exists('PEAR_Downloader')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Downloader.php'; + $layer = $use === null ? 'user' : $use; + if (isset($this->_registry[$layer])) { + return $this->_registry[$layer]; + } elseif ($use === null && isset($this->_registry['system'])) { + return $this->_registry['system']; + } elseif ($use === null && isset($this->_registry['default'])) { + return $this->_registry['default']; + } elseif ($use) { + $a = false; + return $a; } - $a = &new PEAR_Downloader($ui, $options, $config); - return $a; + + // only go here if null was passed in + echo "CRITICAL ERROR: Registry could not be initialized from any value"; + exit(1); } /** - * For unit testing purposes + * This is to allow customization like the use of installroot + * @param PEAR_Registry + * @return bool */ - function &getInstaller(&$ui) + function setRegistry(&$reg, $layer = 'user') { - if (!class_exists('PEAR_Installer')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Installer.php'; + if ($this->_noRegistry) { + return false; } - $a = &new PEAR_Installer($ui); - return $a; + + if (!in_array($layer, array('user', 'system'))) { + return false; + } + + $this->_registry[$layer] = &$reg; + if (is_object($reg)) { + $this->_registry[$layer]->setConfig($this, false); + } + + return true; } - function enableExtension($binaries, $type) + function noRegistry() { - if (!($phpini = $this->config->get('php_ini', null, 'pear.php.net'))) { - return PEAR::raiseError('configuration option "php_ini" is not set to php.ini location'); - } - $ini = $this->_parseIni($phpini); - if (PEAR::isError($ini)) { - return $ini; + $this->_noRegistry = true; + } + + /** + * @return PEAR_REST + */ + function &getREST($version, $options = array()) + { + $version = str_replace('.', '', $version); + if (!class_exists($class = 'PEAR_REST_' . $version)) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/REST/' . $version . '.php'; } - $line = 0; - if ($type == 'extsrc' || $type == 'extbin') { - $search = 'extensions'; - $enable = 'extension'; - } else { - $search = 'zend_extensions'; - ob_start(); - phpinfo(INFO_GENERAL); - $info = ob_get_contents(); - ob_end_clean(); - $debug = function_exists('leak') ? '_debug' : ''; - $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : ''; - $enable = 'zend_extension' . $debug . $ts; + + $remote = &new $class($this, $options); + return $remote; + } + + /** + * The ftp server is set in {@link readFTPConfigFile()}. It exists only if a + * remote configuration file has been specified + * @return PEAR_FTP|false + */ + function &getFTP() + { + if (isset($this->_ftp)) { + return $this->_ftp; } - foreach ($ini[$search] as $line => $extension) { - if (in_array($extension, $binaries, true) || in_array( - $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) { - // already enabled - assume if one is, all are - return true; + + $a = false; + return $a; + } + + function _prependPath($path, $prepend) + { + if (strlen($prepend) > 0) { + if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) { + if (preg_match('/^[a-z]:/i', $prepend)) { + $prepend = substr($prepend, 2); + } elseif ($prepend{0} != '\\') { + $prepend = "\\$prepend"; + } + $path = substr($path, 0, 2) . $prepend . substr($path, 2); + } else { + $path = $prepend . $path; } } - if ($line) { - $newini = array_slice($ini['all'], 0, $line); - } else { - $newini = array(); + return $path; + } + + /** + * @param string|false installation directory to prepend to all _dir variables, or false to + * disable + */ + function setInstallRoot($root) + { + if (substr($root, -1) == DIRECTORY_SEPARATOR) { + $root = substr($root, 0, -1); } - foreach ($binaries as $binary) { - if ($ini['extension_dir']) { - $binary = basename($binary); + $old = $this->_installRoot; + $this->_installRoot = $root; + if (($old != $root) && !$this->_noRegistry) { + foreach (array_keys($this->_registry) as $layer) { + if ($layer == 'ftp' || !isset($this->_registry[$layer])) { + continue; + } + $this->_registry[$layer] = + &new PEAR_Registry($this->get('php_dir', $layer, 'pear.php.net')); + $this->_registry[$layer]->setConfig($this, false); + $this->_regInitialized[$layer] = false; } - $newini[] = $enable . '="' . $binary . '"' . (OS_UNIX ? "\n" : "\r\n"); } - $newini = array_merge($newini, array_slice($ini['all'], $line)); - $fp = @fopen($phpini, 'wb'); - if (!$fp) { - return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing'); + } +} + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Dependency2.php 286494 2009-07-29 06:57:11Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * Required for the PEAR_VALIDATE_* constants + */ +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Validate.php'; + +/** + * Dependency check for PEAR packages + * + * This class handles both version 1.0 and 2.0 dependencies + * WARNING: *any* changes to this class must be duplicated in the + * test_PEAR_Dependency2 class found in tests/PEAR_Dependency2/setup.php.inc, + * or unit tests will not actually validate the changes + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Dependency2 +{ + /** + * One of the PEAR_VALIDATE_* states + * @see PEAR_VALIDATE_NORMAL + * @var integer + */ + var $_state; + + /** + * Command-line options to install/upgrade/uninstall commands + * @param array + */ + var $_options; + + /** + * @var OS_Guess + */ + var $_os; + + /** + * @var PEAR_Registry + */ + var $_registry; + + /** + * @var PEAR_Config + */ + var $_config; + + /** + * @var PEAR_DependencyDB + */ + var $_dependencydb; + + /** + * Output of PEAR_Registry::parsedPackageName() + * @var array + */ + var $_currentPackage; + + /** + * @param PEAR_Config + * @param array installation options + * @param array format of PEAR_Registry::parsedPackageName() + * @param int installation state (one of PEAR_VALIDATE_*) + */ + function PEAR_Dependency2(&$config, $installoptions, $package, + $state = PEAR_VALIDATE_INSTALLING) + { + $this->_config = &$config; + if (!class_exists('PEAR_DependencyDB')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/DependencyDB.php'; } - foreach ($newini as $line) { - fwrite($fp, $line); + + if (isset($installoptions['packagingroot'])) { + // make sure depdb is in the right location + $config->setInstallRoot($installoptions['packagingroot']); } - fclose($fp); - return true; + + $this->_registry = &$config->getRegistry(); + $this->_dependencydb = &PEAR_DependencyDB::singleton($config); + if (isset($installoptions['packagingroot'])) { + $config->setInstallRoot(false); + } + + $this->_options = $installoptions; + $this->_state = $state; + if (!class_exists('OS_Guess')) { + require_once 'phar://install-pear-nozlib.phar/' . 'OS/Guess.php'; + } + + $this->_os = new OS_Guess; + $this->_currentPackage = $package; } - function disableExtension($binaries, $type) + function _getExtraString($dep) { - if (!($phpini = $this->config->get('php_ini', null, 'pear.php.net'))) { - return PEAR::raiseError('configuration option "php_ini" is not set to php.ini location'); - } - $ini = $this->_parseIni($phpini); - if (PEAR::isError($ini)) { - return $ini; + $extra = ' ('; + if (isset($dep['uri'])) { + return ''; } - $line = 0; - if ($type == 'extsrc' || $type == 'extbin') { - $search = 'extensions'; - $enable = 'extension'; + + if (isset($dep['recommended'])) { + $extra .= 'recommended version ' . $dep['recommended']; } else { - $search = 'zend_extensions'; - ob_start(); - phpinfo(INFO_GENERAL); - $info = ob_get_contents(); - ob_end_clean(); - $debug = function_exists('leak') ? '_debug' : ''; - $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : ''; - $enable = 'zend_extension' . $debug . $ts; - } - $found = false; - foreach ($ini[$search] as $line => $extension) { - if (in_array($extension, $binaries, true) || in_array( - $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) { - $found = true; - break; + if (isset($dep['min'])) { + $extra .= 'version >= ' . $dep['min']; + } + + if (isset($dep['max'])) { + if ($extra != ' (') { + $extra .= ', '; + } + $extra .= 'version <= ' . $dep['max']; + } + + if (isset($dep['exclude'])) { + if (!is_array($dep['exclude'])) { + $dep['exclude'] = array($dep['exclude']); + } + + if ($extra != ' (') { + $extra .= ', '; + } + + $extra .= 'excluded versions: '; + foreach ($dep['exclude'] as $i => $exclude) { + if ($i) { + $extra .= ', '; + } + $extra .= $exclude; + } } } - if (!$found) { - // not enabled + + $extra .= ')'; + if ($extra == ' ()') { + $extra = ''; + } + + return $extra; + } + + /** + * This makes unit-testing a heck of a lot easier + */ + function getPHP_OS() + { + return PHP_OS; + } + + /** + * This makes unit-testing a heck of a lot easier + */ + function getsysname() + { + return $this->_os->getSysname(); + } + + /** + * Specify a dependency on an OS. Use arch for detailed os/processor information + * + * There are two generic OS dependencies that will be the most common, unix and windows. + * Other options are linux, freebsd, darwin (OS X), sunos, irix, hpux, aix + */ + function validateOsDependency($dep) + { + if ($this->_state != PEAR_VALIDATE_INSTALLING && $this->_state != PEAR_VALIDATE_DOWNLOADING) { return true; } - $fp = @fopen($phpini, 'wb'); - if (!$fp) { - return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing'); + + if ($dep['name'] == '*') { + return true; } - if ($line) { - $newini = array_slice($ini['all'], 0, $line); - // delete the enable line - $newini = array_merge($newini, array_slice($ini['all'], $line + 1)); - } else { - $newini = array_slice($ini['all'], 1); + + $not = isset($dep['conflicts']) ? true : false; + switch (strtolower($dep['name'])) { + case 'windows' : + if ($not) { + if (strtolower(substr($this->getPHP_OS(), 0, 3)) == 'win') { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError("Cannot install %s on Windows"); + } + + return $this->warning("warning: Cannot install %s on Windows"); + } + } else { + if (strtolower(substr($this->getPHP_OS(), 0, 3)) != 'win') { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError("Can only install %s on Windows"); + } + + return $this->warning("warning: Can only install %s on Windows"); + } + } + break; + case 'unix' : + $unices = array('linux', 'freebsd', 'darwin', 'sunos', 'irix', 'hpux', 'aix'); + if ($not) { + if (in_array($this->getSysname(), $unices)) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError("Cannot install %s on any Unix system"); + } + + return $this->warning( "warning: Cannot install %s on any Unix system"); + } + } else { + if (!in_array($this->getSysname(), $unices)) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError("Can only install %s on a Unix system"); + } + + return $this->warning("warning: Can only install %s on a Unix system"); + } + } + break; + default : + if ($not) { + if (strtolower($dep['name']) == strtolower($this->getSysname())) { + if (!isset($this->_options['nodeps']) && + !isset($this->_options['force'])) { + return $this->raiseError('Cannot install %s on ' . $dep['name'] . + ' operating system'); + } + + return $this->warning('warning: Cannot install %s on ' . + $dep['name'] . ' operating system'); + } + } else { + if (strtolower($dep['name']) != strtolower($this->getSysname())) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('Cannot install %s on ' . + $this->getSysname() . + ' operating system, can only install on ' . $dep['name']); + } + + return $this->warning('warning: Cannot install %s on ' . + $this->getSysname() . + ' operating system, can only install on ' . $dep['name']); + } + } } - foreach ($newini as $line) { - fwrite($fp, $line); + return true; + } + + /** + * This makes unit-testing a heck of a lot easier + */ + function matchSignature($pattern) + { + return $this->_os->matchSignature($pattern); + } + + /** + * Specify a complex dependency on an OS/processor/kernel version, + * Use OS for simple operating system dependency. + * + * This is the only dependency that accepts an eregable pattern. The pattern + * will be matched against the php_uname() output parsed by OS_Guess + */ + function validateArchDependency($dep) + { + if ($this->_state != PEAR_VALIDATE_INSTALLING) { + return true; + } + + $not = isset($dep['conflicts']) ? true : false; + if (!$this->matchSignature($dep['pattern'])) { + if (!$not) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s Architecture dependency failed, does not ' . + 'match "' . $dep['pattern'] . '"'); + } + + return $this->warning('warning: %s Architecture dependency failed, does ' . + 'not match "' . $dep['pattern'] . '"'); + } + + return true; + } + + if ($not) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s Architecture dependency failed, required "' . + $dep['pattern'] . '"'); + } + + return $this->warning('warning: %s Architecture dependency failed, ' . + 'required "' . $dep['pattern'] . '"'); } - fclose($fp); + return true; } - function _parseIni($filename) + /** + * This makes unit-testing a heck of a lot easier + */ + function extension_loaded($name) { - if (!file_exists($filename)) { - return PEAR::raiseError('php.ini "' . $filename . '" does not exist'); - } + return extension_loaded($name); + } - if (filesize($filename) > 300000) { - return PEAR::raiseError('php.ini "' . $filename . '" is too large, aborting'); + /** + * This makes unit-testing a heck of a lot easier + */ + function phpversion($name = null) + { + if ($name !== null) { + return phpversion($name); } - ob_start(); - phpinfo(INFO_GENERAL); - $info = ob_get_contents(); - ob_end_clean(); - $debug = function_exists('leak') ? '_debug' : ''; - $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : ''; - $zend_extension_line = 'zend_extension' . $debug . $ts; - $all = @file($filename); - if (!$all) { - return PEAR::raiseError('php.ini "' . $filename .'" could not be read'); + return phpversion(); + } + + function validateExtensionDependency($dep, $required = true) + { + if ($this->_state != PEAR_VALIDATE_INSTALLING && + $this->_state != PEAR_VALIDATE_DOWNLOADING) { + return true; } - $zend_extensions = $extensions = array(); - // assume this is right, but pull from the php.ini if it is found - $extension_dir = ini_get('extension_dir'); - foreach ($all as $linenum => $line) { - $line = trim($line); - if (!$line) { - continue; - } - if ($line[0] == ';') { - continue; + + $loaded = $this->extension_loaded($dep['name']); + $extra = $this->_getExtraString($dep); + if (isset($dep['exclude'])) { + if (!is_array($dep['exclude'])) { + $dep['exclude'] = array($dep['exclude']); } - if (strtolower(substr($line, 0, 13)) == 'extension_dir') { - $line = trim(substr($line, 13)); - if ($line[0] == '=') { - $x = trim(substr($line, 1)); - $x = explode(';', $x); - $extension_dir = str_replace('"', '', array_shift($x)); - continue; + } + + if (!isset($dep['min']) && !isset($dep['max']) && + !isset($dep['recommended']) && !isset($dep['exclude']) + ) { + if ($loaded) { + if (isset($dep['conflicts'])) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s conflicts with PHP extension "' . + $dep['name'] . '"' . $extra); + } + + return $this->warning('warning: %s conflicts with PHP extension "' . + $dep['name'] . '"' . $extra); } + + return true; } - if (strtolower(substr($line, 0, 9)) == 'extension') { - $line = trim(substr($line, 9)); - if ($line[0] == '=') { - $x = trim(substr($line, 1)); - $x = explode(';', $x); - $extensions[$linenum] = str_replace('"', '', array_shift($x)); - continue; - } + + if (isset($dep['conflicts'])) { + return true; } - if (strtolower(substr($line, 0, strlen($zend_extension_line))) == - $zend_extension_line) { - $line = trim(substr($line, strlen($zend_extension_line))); - if ($line[0] == '=') { - $x = trim(substr($line, 1)); - $x = explode(';', $x); - $zend_extensions[$linenum] = str_replace('"', '', array_shift($x)); - continue; + + if ($required) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires PHP extension "' . + $dep['name'] . '"' . $extra); } + + return $this->warning('warning: %s requires PHP extension "' . + $dep['name'] . '"' . $extra); } + + return $this->warning('%s can optionally use PHP extension "' . + $dep['name'] . '"' . $extra); } - return array( - 'extensions' => $extensions, - 'zend_extensions' => $zend_extensions, - 'extension_dir' => $extension_dir, - 'all' => $all, - ); - } - // {{{ doInstall() + if (!$loaded) { + if (isset($dep['conflicts'])) { + return true; + } - function doInstall($command, $options, $params) - { - if (!class_exists('PEAR_PackageFile')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile.php'; - } + if (!$required) { + return $this->warning('%s can optionally use PHP extension "' . + $dep['name'] . '"' . $extra); + } - if (isset($options['installroot']) && isset($options['packagingroot'])) { - return $this->raiseError('ERROR: cannot use both --installroot and --packagingroot'); - } + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires PHP extension "' . $dep['name'] . + '"' . $extra); + } - $reg = &$this->config->getRegistry(); - $channel = isset($options['channel']) ? $options['channel'] : $this->config->get('default_channel'); - if (!$reg->channelExists($channel)) { - return $this->raiseError('Channel "' . $channel . '" does not exist'); + return $this->warning('warning: %s requires PHP extension "' . $dep['name'] . + '"' . $extra); } - if (empty($this->installer)) { - $this->installer = &$this->getInstaller($this->ui); + $version = (string) $this->phpversion($dep['name']); + if (empty($version)) { + $version = '0'; } - if ($command == 'upgrade' || $command == 'upgrade-all') { - // If people run the upgrade command but pass nothing, emulate a upgrade-all - if ($command == 'upgrade' && empty($params)) { - return $this->doUpgradeAll($command, $options, $params); - } - $options['upgrade'] = true; - } else { - $packages = $params; + $fail = false; + if (isset($dep['min']) && !version_compare($version, $dep['min'], '>=')) { + $fail = true; } - $instreg = &$reg; // instreg used to check if package is installed - if (isset($options['packagingroot']) && !isset($options['upgrade'])) { - $packrootphp_dir = $this->installer->_prependPath( - $this->config->get('php_dir', null, 'pear.php.net'), - $options['packagingroot']); - $instreg = new PEAR_Registry($packrootphp_dir); // other instreg! - - if ($this->config->get('verbose') > 2) { - $this->ui->outputData('using package root: ' . $options['packagingroot']); - } + if (isset($dep['max']) && !version_compare($version, $dep['max'], '<=')) { + $fail = true; } - $abstractpackages = array(); - $otherpackages = array(); - // parse params - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - - foreach ($params as $param) { - if (strpos($param, 'http://') === 0) { - $otherpackages[] = $param; - continue; + if ($fail && !isset($dep['conflicts'])) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires PHP extension "' . $dep['name'] . + '"' . $extra . ', installed version is ' . $version); } - if (strpos($param, 'channel://') === false && @file_exists($param)) { - if (isset($options['force'])) { - $otherpackages[] = $param; - continue; - } - - $pkg = new PEAR_PackageFile($this->config); - $pf = $pkg->fromAnyFile($param, PEAR_VALIDATE_DOWNLOADING); - if (PEAR::isError($pf)) { - $otherpackages[] = $param; - continue; - } - - $exists = $reg->packageExists($pf->getPackage(), $pf->getChannel()); - $pversion = $reg->packageInfo($pf->getPackage(), 'version', $pf->getChannel()); - $version_compare = version_compare($pf->getVersion(), $pversion, '<='); - if ($exists && $version_compare) { - if ($this->config->get('verbose')) { - $this->ui->outputData('Ignoring installed package ' . - $reg->parsedPackageNameToString( - array('package' => $pf->getPackage(), - 'channel' => $pf->getChannel()), true)); - } - continue; - } - $otherpackages[] = $param; - continue; + return $this->warning('warning: %s requires PHP extension "' . $dep['name'] . + '"' . $extra . ', installed version is ' . $version); + } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail && isset($dep['conflicts'])) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s conflicts with PHP extension "' . + $dep['name'] . '"' . $extra . ', installed version is ' . $version); } - $e = $reg->parsePackageName($param, $channel); - if (PEAR::isError($e)) { - $otherpackages[] = $param; - } else { - $abstractpackages[] = $e; - } + return $this->warning('warning: %s conflicts with PHP extension "' . + $dep['name'] . '"' . $extra . ', installed version is ' . $version); } - PEAR::staticPopErrorHandling(); - // if there are any local package .tgz or remote static url, we can't - // filter. The filter only works for abstract packages - if (count($abstractpackages) && !isset($options['force'])) { - // when not being forced, only do necessary upgrades/installs - if (isset($options['upgrade'])) { - $abstractpackages = $this->_filterUptodatePackages($abstractpackages, $command); - } else { - $count = count($abstractpackages); - foreach ($abstractpackages as $i => $package) { - if (isset($package['group'])) { - // do not filter out install groups + if (isset($dep['exclude'])) { + foreach ($dep['exclude'] as $exclude) { + if (version_compare($version, $exclude, '==')) { + if (isset($dep['conflicts'])) { continue; } - if ($instreg->packageExists($package['package'], $package['channel'])) { - if ($count > 1) { - if ($this->config->get('verbose')) { - $this->ui->outputData('Ignoring installed package ' . - $reg->parsedPackageNameToString($package, true)); - } - unset($abstractpackages[$i]); - } elseif ($count === 1) { - // Lets try to upgrade it since it's already installed - $options['upgrade'] = true; - } + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s is not compatible with PHP extension "' . + $dep['name'] . '" version ' . + $exclude); } - } - } - $abstractpackages = - array_map(array($reg, 'parsedPackageNameToString'), $abstractpackages); - } elseif (count($abstractpackages)) { - $abstractpackages = - array_map(array($reg, 'parsedPackageNameToString'), $abstractpackages); - } - - $packages = array_merge($abstractpackages, $otherpackages); - if (!count($packages)) { - $c = ''; - if (isset($options['channel'])){ - $c .= ' in channel "' . $options['channel'] . '"'; - } - $this->ui->outputData('Nothing to ' . $command . $c); - return true; - } - $this->downloader = &$this->getDownloader($this->ui, $options, $this->config); - $errors = $downloaded = $binaries = array(); - $downloaded = &$this->downloader->download($packages); - if (PEAR::isError($downloaded)) { - return $this->raiseError($downloaded); - } + return $this->warning('warning: %s is not compatible with PHP extension "' . + $dep['name'] . '" version ' . + $exclude); + } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s conflicts with PHP extension "' . + $dep['name'] . '"' . $extra . ', installed version is ' . $version); + } - $errors = $this->downloader->getErrorMsgs(); - if (count($errors)) { - $err = array(); - $err['data'] = array(); - foreach ($errors as $error) { - if ($error !== null) { - $err['data'][] = array($error); + return $this->warning('warning: %s conflicts with PHP extension "' . + $dep['name'] . '"' . $extra . ', installed version is ' . $version); } } + } - if (!empty($err['data'])) { - $err['headline'] = 'Install Errors'; - $this->ui->outputData($err); + if (isset($dep['recommended'])) { + if (version_compare($version, $dep['recommended'], '==')) { + return true; } - if (!count($downloaded)) { - return $this->raiseError("$command failed"); + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s dependency: PHP extension ' . $dep['name'] . + ' version "' . $version . '"' . + ' is not the recommended version "' . $dep['recommended'] . + '", but may be compatible, use --force to install'); } + + return $this->warning('warning: %s dependency: PHP extension ' . + $dep['name'] . ' version "' . $version . '"' . + ' is not the recommended version "' . $dep['recommended'].'"'); } - $data = array( - 'headline' => 'Packages that would be Installed' - ); + return true; + } - if (isset($options['pretend'])) { - foreach ($downloaded as $package) { - $data['data'][] = array($reg->parsedPackageNameToString($package->getParsedPackage())); - } - $this->ui->outputData($data, 'pretend'); + function validatePhpDependency($dep) + { + if ($this->_state != PEAR_VALIDATE_INSTALLING && + $this->_state != PEAR_VALIDATE_DOWNLOADING) { return true; } - $this->installer->setOptions($options); - $this->installer->sortPackagesForInstall($downloaded); - if (PEAR::isError($err = $this->installer->setDownloadedPackages($downloaded))) { - $this->raiseError($err->getMessage()); - return true; + $version = $this->phpversion(); + $extra = $this->_getExtraString($dep); + if (isset($dep['exclude'])) { + if (!is_array($dep['exclude'])) { + $dep['exclude'] = array($dep['exclude']); + } } - $extrainfo = array(); - $binaries = array(); - foreach ($downloaded as $param) { - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $info = $this->installer->install($param, $options); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($info)) { - $oldinfo = $info; - $pkg = &$param->getPackageFile(); - if ($info->getCode() != PEAR_INSTALLER_NOBINARY) { - if (!($info = $pkg->installBinary($this->installer))) { - $this->ui->outputData('ERROR: ' .$oldinfo->getMessage()); - continue; - } - - // we just installed a different package than requested, - // let's change the param and info so that the rest of this works - $param = $info[0]; - $info = $info[1]; + if (isset($dep['min'])) { + if (!version_compare($version, $dep['min'], '>=')) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires PHP' . + $extra . ', installed version is ' . $version); } - } - if (!is_array($info)) { - return $this->raiseError("$command failed"); + return $this->warning('warning: %s requires PHP' . + $extra . ', installed version is ' . $version); } + } - if ($param->getPackageType() == 'extsrc' || - $param->getPackageType() == 'extbin' || - $param->getPackageType() == 'zendextsrc' || - $param->getPackageType() == 'zendextbin') { - $pkg = &$param->getPackageFile(); - if ($instbin = $pkg->getInstalledBinary()) { - $instpkg = &$instreg->getPackage($instbin, $pkg->getChannel()); - } else { - $instpkg = &$instreg->getPackage($pkg->getPackage(), $pkg->getChannel()); + if (isset($dep['max'])) { + if (!version_compare($version, $dep['max'], '<=')) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires PHP' . + $extra . ', installed version is ' . $version); } - foreach ($instpkg->getFilelist() as $name => $atts) { - $pinfo = pathinfo($atts['installed_as']); - if (!isset($pinfo['extension']) || - in_array($pinfo['extension'], array('c', 'h'))) { - continue; // make sure we don't match php_blah.h - } + return $this->warning('warning: %s requires PHP' . + $extra . ', installed version is ' . $version); + } + } - if ((strpos($pinfo['basename'], 'php_') === 0 && - $pinfo['extension'] == 'dll') || - // most unices - $pinfo['extension'] == 'so' || - // hp-ux - $pinfo['extension'] == 'sl') { - $binaries[] = array($atts['installed_as'], $pinfo); - break; + if (isset($dep['exclude'])) { + foreach ($dep['exclude'] as $exclude) { + if (version_compare($version, $exclude, '==')) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s is not compatible with PHP version ' . + $exclude); } - } - if (count($binaries)) { - foreach ($binaries as $pinfo) { - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $ret = $this->enableExtension(array($pinfo[0]), $param->getPackageType()); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($ret)) { - $extrainfo[] = $ret->getMessage(); - if ($param->getPackageType() == 'extsrc' || - $param->getPackageType() == 'extbin') { - $exttype = 'extension'; - } else { - ob_start(); - phpinfo(INFO_GENERAL); - $info = ob_get_contents(); - ob_end_clean(); - $debug = function_exists('leak') ? '_debug' : ''; - $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : ''; - $exttype = 'zend_extension' . $debug . $ts; - } - $extrainfo[] = 'You should add "' . $exttype . '=' . - $pinfo[1]['basename'] . '" to php.ini'; - } else { - $extrainfo[] = 'Extension ' . $instpkg->getProvidesExtension() . - ' enabled in php.ini'; - } - } + return $this->warning( + 'warning: %s is not compatible with PHP version ' . + $exclude); } } + } - if ($this->config->get('verbose') > 0) { - $chan = $param->getChannel(); - $label = $reg->parsedPackageNameToString( - array( - 'channel' => $chan, - 'package' => $param->getPackage(), - 'version' => $param->getVersion(), - )); - $out = array('data' => "$command ok: $label"); - if (isset($info['release_warnings'])) { - $out['release_warnings'] = $info['release_warnings']; - } - $this->ui->outputData($out, $command); - - if (!isset($options['register-only']) && !isset($options['offline'])) { - if ($this->config->isDefinedLayer('ftp')) { - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $info = $this->installer->ftpInstall($param); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($info)) { - $this->ui->outputData($info->getMessage()); - $this->ui->outputData("remote install failed: $label"); - } else { - $this->ui->outputData("remote install ok: $label"); - } - } - } - } + return true; + } - $deps = $param->getDeps(); - if ($deps) { - if (isset($deps['group'])) { - $groups = $deps['group']; - if (!isset($groups[0])) { - $groups = array($groups); - } + /** + * This makes unit-testing a heck of a lot easier + */ + function getPEARVersion() + { + return '1.9.0'; + } - foreach ($groups as $group) { - if ($group['attribs']['name'] == 'default') { - // default group is always installed, unless the user - // explicitly chooses to install another group - continue; - } - $extrainfo[] = $param->getPackage() . ': Optional feature ' . - $group['attribs']['name'] . ' available (' . - $group['attribs']['hint'] . ')'; - } + function validatePearinstallerDependency($dep) + { + $pearversion = $this->getPEARVersion(); + $extra = $this->_getExtraString($dep); + if (isset($dep['exclude'])) { + if (!is_array($dep['exclude'])) { + $dep['exclude'] = array($dep['exclude']); + } + } - $extrainfo[] = $param->getPackage() . - ': To install optional features use "pear install ' . - $reg->parsedPackageNameToString( - array('package' => $param->getPackage(), - 'channel' => $param->getChannel()), true) . - '#featurename"'; - } + if (version_compare($pearversion, $dep['min'], '<')) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires PEAR Installer' . $extra . + ', installed version is ' . $pearversion); } - $pkg = &$instreg->getPackage($param->getPackage(), $param->getChannel()); - // $pkg may be NULL if install is a 'fake' install via --packagingroot - if (is_object($pkg)) { - $pkg->setConfig($this->config); - if ($list = $pkg->listPostinstallScripts()) { - $pn = $reg->parsedPackageNameToString(array('channel' => - $param->getChannel(), 'package' => $param->getPackage()), true); - $extrainfo[] = $pn . ' has post-install scripts:'; - foreach ($list as $file) { - $extrainfo[] = $file; - } - $extrainfo[] = $param->getPackage() . - ': Use "pear run-scripts ' . $pn . '" to finish setup.'; - $extrainfo[] = 'DO NOT RUN SCRIPTS FROM UNTRUSTED SOURCES'; + return $this->warning('warning: %s requires PEAR Installer' . $extra . + ', installed version is ' . $pearversion); + } + + if (isset($dep['max'])) { + if (version_compare($pearversion, $dep['max'], '>')) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires PEAR Installer' . $extra . + ', installed version is ' . $pearversion); } + + return $this->warning('warning: %s requires PEAR Installer' . $extra . + ', installed version is ' . $pearversion); } } - if (count($extrainfo)) { - foreach ($extrainfo as $info) { - $this->ui->outputData($info); + if (isset($dep['exclude'])) { + if (!isset($dep['exclude'][0])) { + $dep['exclude'] = array($dep['exclude']); + } + + foreach ($dep['exclude'] as $exclude) { + if (version_compare($exclude, $pearversion, '==')) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s is not compatible with PEAR Installer ' . + 'version ' . $exclude); + } + + return $this->warning('warning: %s is not compatible with PEAR ' . + 'Installer version ' . $exclude); + } } } return true; } - // }}} - // {{{ doUpgradeAll() - - function doUpgradeAll($command, $options, $params) + function validateSubpackageDependency($dep, $required, $params) { - $reg = &$this->config->getRegistry(); - $upgrade = array(); + return $this->validatePackageDependency($dep, $required, $params); + } - if (isset($options['channel'])) { - $channels = array($options['channel']); - } else { - $channels = $reg->listChannels(); + /** + * @param array dependency information (2.0 format) + * @param boolean whether this is a required dependency + * @param array a list of downloaded packages to be installed, if any + * @param boolean if true, then deps on pear.php.net that fail will also check + * against pecl.php.net packages to accomodate extensions that have + * moved to pecl.php.net from pear.php.net + */ + function validatePackageDependency($dep, $required, $params, $depv1 = false) + { + if ($this->_state != PEAR_VALIDATE_INSTALLING && + $this->_state != PEAR_VALIDATE_DOWNLOADING) { + return true; } - foreach ($channels as $channel) { - if ($channel == '__uri') { - continue; - } - - // parse name with channel - foreach ($reg->listPackages($channel) as $name) { - $upgrade[] = $reg->parsedPackageNameToString(array( - 'channel' => $channel, - 'package' => $name - )); + if (isset($dep['providesextension'])) { + if ($this->extension_loaded($dep['providesextension'])) { + $save = $dep; + $subdep = $dep; + $subdep['name'] = $subdep['providesextension']; + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $ret = $this->validateExtensionDependency($subdep, $required); + PEAR::popErrorHandling(); + if (!PEAR::isError($ret)) { + return true; + } } } - $err = $this->doInstall($command, $options, $upgrade); - if (PEAR::isError($err)) { - $this->ui->outputData($err->getMessage(), $command); + if ($this->_state == PEAR_VALIDATE_INSTALLING) { + return $this->_validatePackageInstall($dep, $required, $depv1); } - } - // }}} - // {{{ doUninstall() + if ($this->_state == PEAR_VALIDATE_DOWNLOADING) { + return $this->_validatePackageDownload($dep, $required, $params, $depv1); + } + } - function doUninstall($command, $options, $params) + function _validatePackageDownload($dep, $required, $params, $depv1 = false) { - if (count($params) < 1) { - return $this->raiseError("Please supply the package(s) you want to uninstall"); + $dep['package'] = $dep['name']; + if (isset($dep['uri'])) { + $dep['channel'] = '__uri'; } - if (empty($this->installer)) { - $this->installer = &$this->getInstaller($this->ui); - } + $depname = $this->_registry->parsedPackageNameToString($dep, true); + $found = false; + foreach ($params as $param) { + if ($param->isEqual( + array('package' => $dep['name'], + 'channel' => $dep['channel']))) { + $found = true; + break; + } - if (isset($options['remoteconfig'])) { - $e = $this->config->readFTPConfigFile($options['remoteconfig']); - if (!PEAR::isError($e)) { - $this->installer->setConfig($this->config); + if ($depv1 && $dep['channel'] == 'pear.php.net') { + if ($param->isEqual( + array('package' => $dep['name'], + 'channel' => 'pecl.php.net'))) { + $found = true; + break; + } } } - $reg = &$this->config->getRegistry(); - $newparams = array(); - $binaries = array(); - $badparams = array(); - foreach ($params as $pkg) { - $channel = $this->config->get('default_channel'); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $parsed = $reg->parsePackageName($pkg, $channel); - PEAR::staticPopErrorHandling(); - if (!$parsed || PEAR::isError($parsed)) { - $badparams[] = $pkg; - continue; - } - $package = $parsed['package']; - $channel = $parsed['channel']; - $info = &$reg->getPackage($package, $channel); - if ($info === null && - ($channel == 'pear.php.net' || $channel == 'pecl.php.net')) { - // make sure this isn't a package that has flipped from pear to pecl but - // used a package.xml 1.0 - $testc = ($channel == 'pear.php.net') ? 'pecl.php.net' : 'pear.php.net'; - $info = &$reg->getPackage($package, $testc); - if ($info !== null) { - $channel = $testc; + if (!$found && isset($dep['providesextension'])) { + foreach ($params as $param) { + if ($param->isExtension($dep['providesextension'])) { + $found = true; + break; } } - if ($info === null) { - $badparams[] = $pkg; + } + + if ($found) { + $version = $param->getVersion(); + $installed = false; + $downloaded = true; + } else { + if ($this->_registry->packageExists($dep['name'], $dep['channel'])) { + $installed = true; + $downloaded = false; + $version = $this->_registry->packageinfo($dep['name'], 'version', + $dep['channel']); } else { - $newparams[] = &$info; - // check for binary packages (this is an alias for those packages if so) - if ($installedbinary = $info->getInstalledBinary()) { - $this->ui->log('adding binary package ' . - $reg->parsedPackageNameToString(array('channel' => $channel, - 'package' => $installedbinary), true)); - $newparams[] = &$reg->getPackage($installedbinary, $channel); - } - // add the contents of a dependency group to the list of installed packages - if (isset($parsed['group'])) { - $group = $info->getDependencyGroup($parsed['group']); - if ($group) { - $installed = $reg->getInstalledGroup($group); - if ($installed) { - foreach ($installed as $i => $p) { - $newparams[] = &$installed[$i]; - } - } - } + if ($dep['channel'] == 'pecl.php.net' && $this->_registry->packageExists($dep['name'], + 'pear.php.net')) { + $installed = true; + $downloaded = false; + $version = $this->_registry->packageinfo($dep['name'], 'version', + 'pear.php.net'); + } else { + $version = 'not installed or downloaded'; + $installed = false; + $downloaded = false; } } } - $err = $this->installer->sortPackagesForUninstall($newparams); - if (PEAR::isError($err)) { - $this->ui->outputData($err->getMessage(), $command); - return true; + + $extra = $this->_getExtraString($dep); + if (isset($dep['exclude']) && !is_array($dep['exclude'])) { + $dep['exclude'] = array($dep['exclude']); } - $params = $newparams; - // twist this to use it to check on whether dependent packages are also being uninstalled - // for circular dependencies like subpackages - $this->installer->setUninstallPackages($newparams); - $params = array_merge($params, $badparams); - $binaries = array(); - foreach ($params as $pkg) { - $this->installer->pushErrorHandling(PEAR_ERROR_RETURN); - if ($err = $this->installer->uninstall($pkg, $options)) { - $this->installer->popErrorHandling(); - if (PEAR::isError($err)) { - $this->ui->outputData($err->getMessage(), $command); - continue; - } - if ($pkg->getPackageType() == 'extsrc' || - $pkg->getPackageType() == 'extbin' || - $pkg->getPackageType() == 'zendextsrc' || - $pkg->getPackageType() == 'zendextbin') { - if ($instbin = $pkg->getInstalledBinary()) { - continue; // this will be uninstalled later - } - foreach ($pkg->getFilelist() as $name => $atts) { - $pinfo = pathinfo($atts['installed_as']); - if (!isset($pinfo['extension']) || - in_array($pinfo['extension'], array('c', 'h'))) { - continue; // make sure we don't match php_blah.h - } - if ((strpos($pinfo['basename'], 'php_') === 0 && - $pinfo['extension'] == 'dll') || - // most unices - $pinfo['extension'] == 'so' || - // hp-ux - $pinfo['extension'] == 'sl') { - $binaries[] = array($atts['installed_as'], $pinfo); - break; - } - } - if (count($binaries)) { - foreach ($binaries as $pinfo) { - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $ret = $this->disableExtension(array($pinfo[0]), $pkg->getPackageType()); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($ret)) { - $extrainfo[] = $ret->getMessage(); - if ($pkg->getPackageType() == 'extsrc' || - $pkg->getPackageType() == 'extbin') { - $exttype = 'extension'; - } else { - ob_start(); - phpinfo(INFO_GENERAL); - $info = ob_get_contents(); - ob_end_clean(); - $debug = function_exists('leak') ? '_debug' : ''; - $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : ''; - $exttype = 'zend_extension' . $debug . $ts; - } - $this->ui->outputData('Unable to remove "' . $exttype . '=' . - $pinfo[1]['basename'] . '" from php.ini', $command); - } else { - $this->ui->outputData('Extension ' . $pkg->getProvidesExtension() . - ' disabled in php.ini', $command); - } - } - } - } - $savepkg = $pkg; - if ($this->config->get('verbose') > 0) { - if (is_object($pkg)) { - $pkg = $reg->parsedPackageNameToString($pkg); + if (!isset($dep['min']) && !isset($dep['max']) && + !isset($dep['recommended']) && !isset($dep['exclude']) + ) { + if ($installed || $downloaded) { + $installed = $installed ? 'installed' : 'downloaded'; + if (isset($dep['conflicts'])) { + $rest = ''; + if ($version) { + $rest = ", $installed version is " . $version; } - $this->ui->outputData("uninstall ok: $pkg", $command); - } - if (!isset($options['offline']) && is_object($savepkg) && - defined('PEAR_REMOTEINSTALL_OK')) { - if ($this->config->isDefinedLayer('ftp')) { - $this->installer->pushErrorHandling(PEAR_ERROR_RETURN); - $info = $this->installer->ftpUninstall($savepkg); - $this->installer->popErrorHandling(); - if (PEAR::isError($info)) { - $this->ui->outputData($info->getMessage()); - $this->ui->outputData("remote uninstall failed: $pkg"); - } else { - $this->ui->outputData("remote uninstall ok: $pkg"); - } + + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s conflicts with package "' . $depname . '"' . $extra . $rest); } + + return $this->warning('warning: %s conflicts with package "' . $depname . '"' . $extra . $rest); } - } else { - $this->installer->popErrorHandling(); - if (!is_object($pkg)) { - return $this->raiseError("uninstall failed: $pkg"); - } - $pkg = $reg->parsedPackageNameToString($pkg); - } - } - return true; - } + return true; + } - // }}} + if (isset($dep['conflicts'])) { + return true; + } + if ($required) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires package "' . $depname . '"' . $extra); + } - // }}} - // {{{ doBundle() - /* - (cox) It just downloads and untars the package, does not do - any check that the PEAR_Installer::_installFile() does. - */ + return $this->warning('warning: %s requires package "' . $depname . '"' . $extra); + } - function doBundle($command, $options, $params) - { - $opts = array( - 'force' => true, - 'nodeps' => true, - 'soft' => true, - 'downloadonly' => true - ); - $downloader = &$this->getDownloader($this->ui, $opts, $this->config); - $reg = &$this->config->getRegistry(); - if (count($params) < 1) { - return $this->raiseError("Please supply the package you want to bundle"); + return $this->warning('%s can optionally use package "' . $depname . '"' . $extra); } - if (isset($options['destination'])) { - if (!is_dir($options['destination'])) { - System::mkdir('-p ' . $options['destination']); + if (!$installed && !$downloaded) { + if (isset($dep['conflicts'])) { + return true; } - $dest = realpath($options['destination']); - } else { - $pwd = getcwd(); - $dir = $pwd . DIRECTORY_SEPARATOR . 'ext'; - $dest = is_dir($dir) ? $dir : $pwd; - } - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $err = $downloader->setDownloadDir($dest); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($err)) { - return PEAR::raiseError('download directory "' . $dest . - '" is not writeable.'); + + if ($required) { + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires package "' . $depname . '"' . $extra); + } + + return $this->warning('warning: %s requires package "' . $depname . '"' . $extra); + } + + return $this->warning('%s can optionally use package "' . $depname . '"' . $extra); } - $result = &$downloader->download(array($params[0])); - if (PEAR::isError($result)) { - return $result; + + $fail = false; + if (isset($dep['min']) && version_compare($version, $dep['min'], '<')) { + $fail = true; } - if (!isset($result[0])) { - return $this->raiseError('unable to unpack ' . $params[0]); + + if (isset($dep['max']) && version_compare($version, $dep['max'], '>')) { + $fail = true; } - $pkgfile = &$result[0]->getPackageFile(); - $pkgname = $pkgfile->getName(); - $pkgversion = $pkgfile->getVersion(); - // Unpacking ------------------------------------------------- - $dest .= DIRECTORY_SEPARATOR . $pkgname; - $orig = $pkgname . '-' . $pkgversion; + if ($fail && !isset($dep['conflicts'])) { + $installed = $installed ? 'installed' : 'downloaded'; + $dep['package'] = $dep['name']; + $dep = $this->_registry->parsedPackageNameToString($dep, true); + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s requires package "' . $depname . '"' . + $extra . ", $installed version is " . $version); + } - $tar = &new Archive_Tar($pkgfile->getArchiveFile()); - if (!$tar->extractModify($dest, $orig)) { - return $this->raiseError('unable to unpack ' . $pkgfile->getArchiveFile()); + return $this->warning('warning: %s requires package "' . $depname . '"' . + $extra . ", $installed version is " . $version); + } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail && + isset($dep['conflicts']) && !isset($dep['exclude'])) { + $installed = $installed ? 'installed' : 'downloaded'; + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s conflicts with package "' . $depname . '"' . $extra . + ", $installed version is " . $version); + } + + return $this->warning('warning: %s conflicts with package "' . $depname . '"' . + $extra . ", $installed version is " . $version); } - $this->ui->outputData("Package ready at '$dest'"); - // }}} - } - // }}} + if (isset($dep['exclude'])) { + $installed = $installed ? 'installed' : 'downloaded'; + foreach ($dep['exclude'] as $exclude) { + if (version_compare($version, $exclude, '==') && !isset($dep['conflicts'])) { + if (!isset($this->_options['nodeps']) && + !isset($this->_options['force']) + ) { + return $this->raiseError('%s is not compatible with ' . + $installed . ' package "' . + $depname . '" version ' . + $exclude); + } - function doRunScripts($command, $options, $params) - { - if (!isset($params[0])) { - return $this->raiseError('run-scripts expects 1 parameter: a package name'); - } + return $this->warning('warning: %s is not compatible with ' . + $installed . ' package "' . + $depname . '" version ' . + $exclude); + } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) { + $installed = $installed ? 'installed' : 'downloaded'; + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('%s conflicts with package "' . $depname . '"' . + $extra . ", $installed version is " . $version); + } - $reg = &$this->config->getRegistry(); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel')); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($parsed)) { - return $this->raiseError($parsed); + return $this->warning('warning: %s conflicts with package "' . $depname . '"' . + $extra . ", $installed version is " . $version); + } + } } - $package = &$reg->getPackage($parsed['package'], $parsed['channel']); - if (!is_object($package)) { - return $this->raiseError('Could not retrieve package "' . $params[0] . '" from registry'); + if (isset($dep['recommended'])) { + $installed = $installed ? 'installed' : 'downloaded'; + if (version_compare($version, $dep['recommended'], '==')) { + return true; + } + + if (!$found && $installed) { + $param = $this->_registry->getPackage($dep['name'], $dep['channel']); + } + + if ($param) { + $found = false; + foreach ($params as $parent) { + if ($parent->isEqual($this->_currentPackage)) { + $found = true; + break; + } + } + + if ($found) { + if ($param->isCompatible($parent)) { + return true; + } + } else { // this is for validPackage() calls + $parent = $this->_registry->getPackage($this->_currentPackage['package'], + $this->_currentPackage['channel']); + if ($parent !== null && $param->isCompatible($parent)) { + return true; + } + } + } + + if (!isset($this->_options['nodeps']) && !isset($this->_options['force']) && + !isset($this->_options['loose']) + ) { + return $this->raiseError('%s dependency package "' . $depname . + '" ' . $installed . ' version ' . $version . + ' is not the recommended version ' . $dep['recommended'] . + ', but may be compatible, use --force to install'); + } + + return $this->warning('warning: %s dependency package "' . $depname . + '" ' . $installed . ' version ' . $version . + ' is not the recommended version ' . $dep['recommended']); } - $package->setConfig($this->config); - $package->runPostinstallScripts(); - $this->ui->outputData('Install scripts complete', $command); return true; } + function _validatePackageInstall($dep, $required, $depv1 = false) + { + return $this->_validatePackageDownload($dep, $required, array(), $depv1); + } + /** - * Given a list of packages, filter out those ones that are already up to date + * Verify that uninstalling packages passed in to command line is OK. * - * @param $packages: packages, in parsed array format ! - * @return list of packages that can be upgraded + * @param PEAR_Installer $dl + * @return PEAR_Error|true */ - function _filterUptodatePackages($packages, $command) + function validatePackageUninstall(&$dl) { - $reg = &$this->config->getRegistry(); - $latestReleases = array(); + if (PEAR::isError($this->_dependencydb)) { + return $this->_dependencydb; + } - $ret = array(); - foreach ($packages as $package) { - if (isset($package['group'])) { - $ret[] = $package; - continue; + $params = array(); + // construct an array of "downloaded" packages to fool the package dependency checker + // into using these to validate uninstalls of circular dependencies + $downloaded = &$dl->getUninstallPackages(); + foreach ($downloaded as $i => $pf) { + if (!class_exists('PEAR_Downloader_Package')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Downloader/Package.php'; } + $dp = &new PEAR_Downloader_Package($dl); + $dp->setPackageFile($downloaded[$i]); + $params[$i] = &$dp; + } - $channel = $package['channel']; - $name = $package['package']; - if (!$reg->packageExists($name, $channel)) { - $ret[] = $package; - continue; + // check cache + $memyselfandI = strtolower($this->_currentPackage['channel']) . '/' . + strtolower($this->_currentPackage['package']); + if (isset($dl->___uninstall_package_cache)) { + $badpackages = $dl->___uninstall_package_cache; + if (isset($badpackages[$memyselfandI]['warnings'])) { + foreach ($badpackages[$memyselfandI]['warnings'] as $warning) { + $dl->log(0, $warning[0]); + } } - if (!isset($latestReleases[$channel])) { - // fill in cache for this channel - $chan = &$reg->getChannel($channel); - if (PEAR::isError($chan)) { - return $this->raiseError($chan); + if (isset($badpackages[$memyselfandI]['errors'])) { + foreach ($badpackages[$memyselfandI]['errors'] as $error) { + if (is_array($error)) { + $dl->log(0, $error[0]); + } else { + $dl->log(0, $error->getMessage()); + } } - $preferred_mirror = $this->config->get('preferred_mirror', null, $channel); - if ($chan->supportsREST($preferred_mirror) && - $base = $chan->getBaseURL('REST1.0', $preferred_mirror)) - { - $dorest = true; + if (isset($this->_options['nodeps']) || isset($this->_options['force'])) { + return $this->warning( + 'warning: %s should not be uninstalled, other installed packages depend ' . + 'on this package'); } - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - if (!isset($package['state'])) { - $state = $this->config->get('preferred_state', null, $channel); - } else { - $state = $package['state']; - } + return $this->raiseError( + '%s cannot be uninstalled, other installed packages depend on this package'); + } - if ($dorest) { - $rest = &$this->config->getREST('1.0', array()); - $installed = array_flip($reg->listPackages($channel)); + return true; + } - $latest = $rest->listLatestUpgrades($base, $state, $installed, $channel, $reg); - } + // first, list the immediate parents of each package to be uninstalled + $perpackagelist = array(); + $allparents = array(); + foreach ($params as $i => $param) { + $a = array( + 'channel' => strtolower($param->getChannel()), + 'package' => strtolower($param->getPackage()) + ); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($latest)) { - $this->ui->outputData('Error getting channel info from ' . $channel . - ': ' . $latest->getMessage()); - continue; + $deps = $this->_dependencydb->getDependentPackages($a); + if ($deps) { + foreach ($deps as $d) { + $pardeps = $this->_dependencydb->getDependencies($d); + foreach ($pardeps as $dep) { + if (strtolower($dep['dep']['channel']) == $a['channel'] && + strtolower($dep['dep']['name']) == $a['package']) { + if (!isset($perpackagelist[$a['channel'] . '/' . $a['package']])) { + $perpackagelist[$a['channel'] . '/' . $a['package']] = array(); + } + $perpackagelist[$a['channel'] . '/' . $a['package']][] + = array($d['channel'] . '/' . $d['package'], $dep); + if (!isset($allparents[$d['channel'] . '/' . $d['package']])) { + $allparents[$d['channel'] . '/' . $d['package']] = array(); + } + if (!isset($allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']])) { + $allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']] = array(); + } + $allparents[$d['channel'] . '/' . $d['package']] + [$a['channel'] . '/' . $a['package']][] + = array($d, $dep); + } + } } - - $latestReleases[$channel] = array_change_key_case($latest); } + } - // check package for latest release - $name_lower = strtolower($name); - if (isset($latestReleases[$channel][$name_lower])) { - // if not set, up to date - $inst_version = $reg->packageInfo($name, 'version', $channel); - $channel_version = $latestReleases[$channel][$name_lower]['version']; - if (version_compare($channel_version, $inst_version, 'le')) { - // installed version is up-to-date + // next, remove any packages from the parents list that are not installed + $remove = array(); + foreach ($allparents as $parent => $d1) { + foreach ($d1 as $d) { + if ($this->_registry->packageExists($d[0][0]['package'], $d[0][0]['channel'])) { continue; } + $remove[$parent] = true; + } + } - // maintain BC - if ($command == 'upgrade-all') { - $this->ui->outputData(array('data' => 'Will upgrade ' . - $reg->parsedPackageNameToString($package)), $command); + // next remove any packages from the parents list that are not passed in for + // uninstallation + foreach ($allparents as $parent => $d1) { + foreach ($d1 as $d) { + foreach ($params as $param) { + if (strtolower($param->getChannel()) == $d[0][0]['channel'] && + strtolower($param->getPackage()) == $d[0][0]['package']) { + // found it + continue 3; + } } - $ret[] = $package; + $remove[$parent] = true; } } - return $ret; - } -} - - Install Package - doInstall - i - - - f - will overwrite newer installed packages - - - l - do not check for recommended dependency version - - - n - ignore dependencies, install anyway - - - r - do not install files, only register the package as installed - - - s - soft install, fail silently, or upgrade if already installed - - - B - don't build C extensions - - - Z - request uncompressed files when downloading - - - R - root directory used when installing files (ala PHP's INSTALL_ROOT), use packagingroot for RPM - DIR - - - P - root directory used when packaging files, like RPM packaging - DIR - - - - force install even if there were errors - - - a - install all required and optional dependencies - - - o - install all required dependencies - - - O - do not attempt to download any urls or contact channels - - - p - Only list the packages that would be downloaded - - - [channel/]<package> ... -Installs one or more PEAR packages. You can specify a package to -install in four ways: - -"Package-1.0.tgz" : installs from a local file - -"http://example.com/Package-1.0.tgz" : installs from -anywhere on the net. - -"package.xml" : installs the package described in -package.xml. Useful for testing, or for wrapping a PEAR package in -another package manager such as RPM. - -"Package[-version/state][.tar]" : queries your default channel's server -({config master_server}) and downloads the newest package with -the preferred quality/state ({config preferred_state}). - -To retrieve Package version 1.1, use "Package-1.1," to retrieve -Package state beta, use "Package-beta." To retrieve an uncompressed -file, append .tar (make sure there is no file by the same name first) - -To download a package from another channel, prefix with the channel name like -"channel/Package" - -More than one package may be specified at once. It is ok to mix these -four ways of specifying packages. - - - - Upgrade Package - doInstall - up - - - c - upgrade packages from a specific channel - CHAN - - - f - overwrite newer installed packages - - - l - do not check for recommended dependency version - - - n - ignore dependencies, upgrade anyway - - - r - do not install files, only register the package as upgraded - - - B - don't build C extensions - - - Z - request uncompressed files when downloading - - - R - root directory used when installing files (ala PHP's INSTALL_ROOT) - DIR - - - - force install even if there were errors - - - a - install all required and optional dependencies - - - o - install all required dependencies - - - O - do not attempt to download any urls or contact channels - - - p - Only list the packages that would be downloaded - - - <package> ... -Upgrades one or more PEAR packages. See documentation for the -"install" command for ways to specify a package. - -When upgrading, your package will be updated if the provided new -package has a higher version number (use the -f option if you need to -upgrade anyway). - -More than one package may be specified at once. - - - - Upgrade All Packages [Deprecated in favor of calling upgrade with no parameters] - doUpgradeAll - ua - - - c - upgrade packages from a specific channel - CHAN - - - n - ignore dependencies, upgrade anyway - - - r - do not install files, only register the package as upgraded - - - B - don't build C extensions - - - Z - request uncompressed files when downloading - - - R - root directory used when installing files (ala PHP's INSTALL_ROOT), use packagingroot for RPM - DIR - - - - force install even if there were errors - - - - do not check for recommended dependency version - - - -WARNING: This function is deprecated in favor of using the upgrade command with no params + // remove all packages whose dependencies fail + // save which ones failed for error reporting + $badchildren = array(); + do { + $fail = false; + foreach ($remove as $package => $unused) { + if (!isset($allparents[$package])) { + continue; + } -Upgrades all packages that have a newer release available. Upgrades are -done only if there is a release available of the state specified in -"preferred_state" (currently {config preferred_state}), or a state considered -more stable. - - - - Un-install Package - doUninstall - un - - - n - ignore dependencies, uninstall anyway - - - r - do not remove files, only register the packages as not installed - - - R - root directory used when installing files (ala PHP's INSTALL_ROOT) - DIR - - - f - force install even if there were errors - - - O - do not attempt to uninstall remotely - - - [channel/]<package> ... -Uninstalls one or more PEAR packages. More than one package may be -specified at once. Prefix with channel name to uninstall from a -channel not in your default channel ({config default_channel}) - - - - Unpacks a Pecl Package - doBundle - bun - - - d - Optional destination directory for unpacking (defaults to current path or "ext" if exists) - DIR - - - - Force the unpacking even if there were errors in the package - - - <package> -Unpacks a Pecl Package into the selected location. It will download the -package if needed. - - - - Run Post-Install Scripts bundled with a package - doRunScripts - rs - - <package> -Run post-installation scripts in package <package>, if any exist. - - - - * @author Tomas V. V. Cox - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Common.php,v 1.168 2009/03/27 19:35:47 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1.0 - * @deprecated File deprecated since Release 1.4.0a1 - */ + foreach ($allparents[$package] as $kid => $d1) { + foreach ($d1 as $depinfo) { + if ($depinfo[1]['type'] != 'optional') { + if (isset($badchildren[$kid])) { + continue; + } + $badchildren[$kid] = true; + $remove[$kid] = true; + $fail = true; + continue 2; + } + } + } + if ($fail) { + // start over, we removed some children + continue 2; + } + } + } while ($fail); -/** - * Include error handling - */ -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR.php'; + // next, construct the list of packages that can't be uninstalled + $badpackages = array(); + $save = $this->_currentPackage; + foreach ($perpackagelist as $package => $packagedeps) { + foreach ($packagedeps as $parent) { + if (!isset($remove[$parent[0]])) { + continue; + } -/** - * PEAR_Common error when an invalid PHP file is passed to PEAR_Common::analyzeSourceCode() - */ -define('PEAR_COMMON_ERROR_INVALIDPHP', 1); -define('_PEAR_COMMON_PACKAGE_NAME_PREG', '[A-Za-z][a-zA-Z0-9_]+'); -define('PEAR_COMMON_PACKAGE_NAME_PREG', '/^' . _PEAR_COMMON_PACKAGE_NAME_PREG . '\\z/'); + $packagename = $this->_registry->parsePackageName($parent[0]); + $packagename['channel'] = $this->_registry->channelAlias($packagename['channel']); + $pa = $this->_registry->getPackage($packagename['package'], $packagename['channel']); + $packagename['package'] = $pa->getPackage(); + $this->_currentPackage = $packagename; + // parent is not present in uninstall list, make sure we can actually + // uninstall it (parent dep is optional) + $parentname['channel'] = $this->_registry->channelAlias($parent[1]['dep']['channel']); + $pa = $this->_registry->getPackage($parent[1]['dep']['name'], $parent[1]['dep']['channel']); + $parentname['package'] = $pa->getPackage(); + $parent[1]['dep']['package'] = $parentname['package']; + $parent[1]['dep']['channel'] = $parentname['channel']; + if ($parent[1]['type'] == 'optional') { + $test = $this->_validatePackageUninstall($parent[1]['dep'], false, $dl); + if ($test !== true) { + $badpackages[$package]['warnings'][] = $test; + } + } else { + $test = $this->_validatePackageUninstall($parent[1]['dep'], true, $dl); + if ($test !== true) { + $badpackages[$package]['errors'][] = $test; + } + } + } + } -// this should allow: 1, 1.0, 1.0RC1, 1.0dev, 1.0dev123234234234, 1.0a1, 1.0b1, 1.0pl1 -define('_PEAR_COMMON_PACKAGE_VERSION_PREG', '\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?'); -define('PEAR_COMMON_PACKAGE_VERSION_PREG', '/^' . _PEAR_COMMON_PACKAGE_VERSION_PREG . '\\z/i'); + $this->_currentPackage = $save; + $dl->___uninstall_package_cache = $badpackages; + if (isset($badpackages[$memyselfandI])) { + if (isset($badpackages[$memyselfandI]['warnings'])) { + foreach ($badpackages[$memyselfandI]['warnings'] as $warning) { + $dl->log(0, $warning[0]); + } + } -// XXX far from perfect :-) -define('_PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '(' . _PEAR_COMMON_PACKAGE_NAME_PREG . - ')(-([.0-9a-zA-Z]+))?'); -define('PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_PACKAGE_DOWNLOAD_PREG . - '\\z/'); + if (isset($badpackages[$memyselfandI]['errors'])) { + foreach ($badpackages[$memyselfandI]['errors'] as $error) { + if (is_array($error)) { + $dl->log(0, $error[0]); + } else { + $dl->log(0, $error->getMessage()); + } + } -define('_PEAR_CHANNELS_NAME_PREG', '[A-Za-z][a-zA-Z0-9\.]+'); -define('PEAR_CHANNELS_NAME_PREG', '/^' . _PEAR_CHANNELS_NAME_PREG . '\\z/'); + if (isset($this->_options['nodeps']) || isset($this->_options['force'])) { + return $this->warning( + 'warning: %s should not be uninstalled, other installed packages depend ' . + 'on this package'); + } -// this should allow any dns or IP address, plus a path - NO UNDERSCORES ALLOWED -define('_PEAR_CHANNELS_SERVER_PREG', '[a-zA-Z0-9\-]+(?:\.[a-zA-Z0-9\-]+)*(\/[a-zA-Z0-9\-]+)*'); -define('PEAR_CHANNELS_SERVER_PREG', '/^' . _PEAR_CHANNELS_SERVER_PREG . '\\z/i'); + return $this->raiseError( + '%s cannot be uninstalled, other installed packages depend on this package'); + } + } -define('_PEAR_CHANNELS_PACKAGE_PREG', '(' ._PEAR_CHANNELS_SERVER_PREG . ')\/(' - . _PEAR_COMMON_PACKAGE_NAME_PREG . ')'); -define('PEAR_CHANNELS_PACKAGE_PREG', '/^' . _PEAR_CHANNELS_PACKAGE_PREG . '\\z/i'); + return true; + } -define('_PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '(' . _PEAR_CHANNELS_NAME_PREG . ')::(' - . _PEAR_COMMON_PACKAGE_NAME_PREG . ')(-([.0-9a-zA-Z]+))?'); -define('PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_CHANNEL_DOWNLOAD_PREG . '\\z/'); + function _validatePackageUninstall($dep, $required, $dl) + { + $depname = $this->_registry->parsedPackageNameToString($dep, true); + $version = $this->_registry->packageinfo($dep['package'], 'version', $dep['channel']); + if (!$version) { + return true; + } -/** - * List of temporary files and directories registered by - * PEAR_Common::addTempFile(). - * @var array - */ -$GLOBALS['_PEAR_Common_tempfiles'] = array(); + $extra = $this->_getExtraString($dep); + if (isset($dep['exclude']) && !is_array($dep['exclude'])) { + $dep['exclude'] = array($dep['exclude']); + } -/** - * Valid maintainer roles - * @var array - */ -$GLOBALS['_PEAR_Common_maintainer_roles'] = array('lead','developer','contributor','helper'); + if (isset($dep['conflicts'])) { + return true; // uninstall OK - these packages conflict (probably installed with --force) + } -/** - * Valid release states - * @var array - */ -$GLOBALS['_PEAR_Common_release_states'] = array('alpha','beta','stable','snapshot','devel'); + if (!isset($dep['min']) && !isset($dep['max'])) { + if (!$required) { + return $this->warning('"' . $depname . '" can be optionally used by ' . + 'installed package %s' . $extra); + } -/** - * Valid dependency types - * @var array - */ -$GLOBALS['_PEAR_Common_dependency_types'] = array('pkg','ext','php','prog','ldlib','rtlib','os','websrv','sapi'); + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError('"' . $depname . '" is required by ' . + 'installed package %s' . $extra); + } -/** - * Valid dependency relations - * @var array - */ -$GLOBALS['_PEAR_Common_dependency_relations'] = array('has','eq','lt','le','gt','ge','not', 'ne'); + return $this->warning('warning: "' . $depname . '" is required by ' . + 'installed package %s' . $extra); + } -/** - * Valid file roles - * @var array - */ -$GLOBALS['_PEAR_Common_file_roles'] = array('php','ext','test','doc','data','src','script'); + $fail = false; + if (isset($dep['min']) && version_compare($version, $dep['min'], '>=')) { + $fail = true; + } -/** - * Valid replacement types - * @var array - */ -$GLOBALS['_PEAR_Common_replacement_types'] = array('php-const', 'pear-config', 'package-info'); + if (isset($dep['max']) && version_compare($version, $dep['max'], '<=')) { + $fail = true; + } -/** - * Valid "provide" types - * @var array - */ -$GLOBALS['_PEAR_Common_provide_types'] = array('ext', 'prog', 'class', 'function', 'feature', 'api'); + // we re-use this variable, preserve the original value + $saverequired = $required; + if (!$required) { + return $this->warning($depname . $extra . ' can be optionally used by installed package' . + ' "%s"'); + } -/** - * Valid "provide" types - * @var array - */ -$GLOBALS['_PEAR_Common_script_phases'] = array('pre-install', 'post-install', 'pre-uninstall', 'post-uninstall', 'pre-build', 'post-build', 'pre-configure', 'post-configure', 'pre-setup', 'post-setup'); + if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { + return $this->raiseError($depname . $extra . ' is required by installed package' . + ' "%s"'); + } -/** - * Class providing common functionality for PEAR administration classes. - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Tomas V. V. Cox - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - * @deprecated This class will disappear, and its components will be spread - * into smaller classes, like the AT&T breakup, as of Release 1.4.0a1 - */ -class PEAR_Common extends PEAR -{ - /** - * User Interface object (PEAR_Frontend_* class). If null, - * the log() method uses print. - * @var object - */ - var $ui = null; + return $this->raiseError('warning: ' . $depname . $extra . + ' is required by installed package "%s"'); + } /** - * Configuration object (PEAR_Config). - * @var PEAR_Config + * validate a downloaded package against installed packages + * + * As of PEAR 1.4.3, this will only validate + * + * @param array|PEAR_Downloader_Package|PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * $pkg package identifier (either + * array('package' => blah, 'channel' => blah) or an array with + * index 'info' referencing an object) + * @param PEAR_Downloader $dl + * @param array $params full list of packages to install + * @return true|PEAR_Error */ - var $config = null; - - /** stack of elements, gives some sort of XML context */ - var $element_stack = array(); + function validatePackage($pkg, &$dl, $params = array()) + { + if (is_array($pkg) && isset($pkg['info'])) { + $deps = $this->_dependencydb->getDependentPackageDependencies($pkg['info']); + } else { + $deps = $this->_dependencydb->getDependentPackageDependencies($pkg); + } - /** name of currently parsed XML element */ - var $current_element; + $fail = false; + if ($deps) { + if (!class_exists('PEAR_Downloader_Package')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Downloader/Package.php'; + } - /** array of attributes of the currently parsed XML element */ - var $current_attributes = array(); + $dp = &new PEAR_Downloader_Package($dl); + if (is_object($pkg)) { + $dp->setPackageFile($pkg); + } else { + $dp->setDownloadURL($pkg); + } - /** assoc with information about a package */ - var $pkginfo = array(); + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + foreach ($deps as $channel => $info) { + foreach ($info as $package => $ds) { + foreach ($params as $packd) { + if (strtolower($packd->getPackage()) == strtolower($package) && + $packd->getChannel() == $channel) { + $dl->log(3, 'skipping installed package check of "' . + $this->_registry->parsedPackageNameToString( + array('channel' => $channel, 'package' => $package), + true) . + '", version "' . $packd->getVersion() . '" will be ' . + 'downloaded and installed'); + continue 2; // jump to next package + } + } - var $current_path = null; + foreach ($ds as $d) { + $checker = &new PEAR_Dependency2($this->_config, $this->_options, + array('channel' => $channel, 'package' => $package), $this->_state); + $dep = $d['dep']; + $required = $d['type'] == 'required'; + $ret = $checker->_validatePackageDownload($dep, $required, array(&$dp)); + if (is_array($ret)) { + $dl->log(0, $ret[0]); + } elseif (PEAR::isError($ret)) { + $dl->log(0, $ret->getMessage()); + $fail = true; + } + } + } + } + PEAR::popErrorHandling(); + } - /** - * Flag variable used to mark a valid package file - * @var boolean - * @access private - */ - var $_validPackageFile; + if ($fail) { + return $this->raiseError( + '%s cannot be installed, conflicts with installed packages'); + } - /** - * PEAR_Common constructor - * - * @access public - */ - function PEAR_Common() - { - parent::PEAR(); - $this->config = &PEAR_Config::singleton(); - $this->debug = $this->config->get('verbose'); + return true; } /** - * PEAR_Common destructor - * - * @access private + * validate a package.xml 1.0 dependency */ - function _PEAR_Common() + function validateDependency1($dep, $params = array()) { - // doesn't work due to bug #14744 - //$tempfiles = $this->_tempfiles; - $tempfiles =& $GLOBALS['_PEAR_Common_tempfiles']; - while ($file = array_shift($tempfiles)) { - if (@is_dir($file)) { - if (!class_exists('System')) { - require_once 'phar://install-pear-nozlib.phar/' . 'System.php'; - } + if (!isset($dep['optional'])) { + $dep['optional'] = 'no'; + } - System::rm(array('-rf', $file)); - } elseif (file_exists($file)) { - unlink($file); - } + list($newdep, $type) = $this->normalizeDep($dep); + if (!$newdep) { + return $this->raiseError("Invalid Dependency"); } - } - /** - * Register a temporary file or directory. When the destructor is - * executed, all registered temporary files and directories are - * removed. - * - * @param string $file name of file or directory - * - * @return void - * - * @access public - */ - function addTempFile($file) - { - if (!class_exists('PEAR_Frontend')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Frontend.php'; + if (method_exists($this, "validate{$type}Dependency")) { + return $this->{"validate{$type}Dependency"}($newdep, $dep['optional'] == 'no', + $params, true); } - PEAR_Frontend::addTempFile($file); } /** - * Wrapper to System::mkDir(), creates a directory as well as - * any necessary parent directories. - * - * @param string $dir directory name - * - * @return bool TRUE on success, or a PEAR error - * - * @access public + * Convert a 1.0 dep into a 2.0 dep */ - function mkDirHier($dir) + function normalizeDep($dep) { - // Only used in Installer - move it there ? - $this->log(2, "+ create dir $dir"); - if (!class_exists('System')) { - require_once 'phar://install-pear-nozlib.phar/' . 'System.php'; + $types = array( + 'pkg' => 'Package', + 'ext' => 'Extension', + 'os' => 'Os', + 'php' => 'Php' + ); + + if (!isset($types[$dep['type']])) { + return array(false, false); } - return System::mkDir(array('-p', $dir)); - } - /** - * Logging method. - * - * @param int $level log level (0 is quiet, higher is noisier) - * @param string $msg message to write to the log - * - * @return void - * - * @access public - * @static - */ - function log($level, $msg, $append_crlf = true) - { - if ($this->debug >= $level) { - if (!class_exists('PEAR_Frontend')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Frontend.php'; + $type = $types[$dep['type']]; + + $newdep = array(); + switch ($type) { + case 'Package' : + $newdep['channel'] = 'pear.php.net'; + case 'Extension' : + case 'Os' : + $newdep['name'] = $dep['name']; + break; + } + + $dep['rel'] = PEAR_Dependency2::signOperator($dep['rel']); + switch ($dep['rel']) { + case 'has' : + return array($newdep, $type); + break; + case 'not' : + $newdep['conflicts'] = true; + break; + case '>=' : + case '>' : + $newdep['min'] = $dep['version']; + if ($dep['rel'] == '>') { + $newdep['exclude'] = $dep['version']; + } + break; + case '<=' : + case '<' : + $newdep['max'] = $dep['version']; + if ($dep['rel'] == '<') { + $newdep['exclude'] = $dep['version']; + } + break; + case 'ne' : + case '!=' : + $newdep['min'] = '0'; + $newdep['max'] = '100000'; + $newdep['exclude'] = $dep['version']; + break; + case '==' : + $newdep['min'] = $dep['version']; + $newdep['max'] = $dep['version']; + break; + } + if ($type == 'Php') { + if (!isset($newdep['min'])) { + $newdep['min'] = '4.4.0'; } - $ui = &PEAR_Frontend::singleton(); - if (is_a($ui, 'PEAR_Frontend')) { - $ui->log($msg, $append_crlf); - } else { - print "$msg\n"; + if (!isset($newdep['max'])) { + $newdep['max'] = '6.0.0'; } } + return array($newdep, $type); } /** - * Create and register a temporary directory. - * - * @param string $tmpdir (optional) Directory to use as tmpdir. - * Will use system defaults (for example - * /tmp or c:\windows\temp) if not specified + * Converts text comparing operators to them sign equivalents * - * @return string name of created directory + * Example: 'ge' to '>=' * * @access public + * @param string Operator + * @return string Sign equivalent */ - function mkTempDir($tmpdir = '') + function signOperator($operator) { - $topt = $tmpdir ? array('-t', $tmpdir) : array(); - $topt = array_merge($topt, array('-d', 'pear')); - if (!class_exists('System')) { - require_once 'phar://install-pear-nozlib.phar/' . 'System.php'; + switch($operator) { + case 'lt': return '<'; + case 'le': return '<='; + case 'gt': return '>'; + case 'ge': return '>='; + case 'eq': return '=='; + case 'ne': return '!='; + default: + return $operator; } + } - if (!$tmpdir = System::mktemp($topt)) { - return false; + function raiseError($msg) + { + if (isset($this->_options['ignore-errors'])) { + return $this->warning($msg); } - $this->addTempFile($tmpdir); - return $tmpdir; + return PEAR::raiseError(sprintf($msg, $this->_registry->parsedPackageNameToString( + $this->_currentPackage, true))); } - /** - * Set object that represents the frontend to be used. - * - * @param object Reference of the frontend object - * @return void - * @access public - */ - function setFrontendObject(&$ui) + function warning($msg) { - $this->ui = &$ui; + return array(sprintf($msg, $this->_registry->parsedPackageNameToString( + $this->_currentPackage, true))); } +} + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: DependencyDB.php 286686 2009-08-02 17:38:57Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * Needed for error handling + */ +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR.php'; +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Config.php'; + +$GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'] = array(); +/** + * Track dependency relationships between installed packages + * @category pear + * @package PEAR + * @author Greg Beaver + * @author Tomas V.V.Cox + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_DependencyDB +{ + // {{{ properties /** - * Return an array containing all of the states that are more stable than - * or equal to the passed in state - * - * @param string Release state - * @param boolean Determines whether to include $state in the list - * @return false|array False if $state is not a valid release state + * This is initialized by {@link setConfig()} + * @var PEAR_Config + * @access private */ - function betterStates($state, $include = false) - { - static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable'); - $i = array_search($state, $states); - if ($i === false) { - return false; - } - if ($include) { - $i--; - } - return array_slice($states, $i + 1); - } - + var $_config; /** - * Get the valid roles for a PEAR package maintainer - * - * @return array - * @static + * This is initialized by {@link setConfig()} + * @var PEAR_Registry + * @access private */ - function getUserRoles() - { - return $GLOBALS['_PEAR_Common_maintainer_roles']; - } - + var $_registry; /** - * Get the valid package release states of packages - * - * @return array - * @static + * Filename of the dependency DB (usually .depdb) + * @var string + * @access private */ - function getReleaseStates() - { - return $GLOBALS['_PEAR_Common_release_states']; - } - + var $_depdb = false; /** - * Get the implemented dependency types (php, ext, pkg etc.) - * - * @return array - * @static + * File name of the lockfile (usually .depdblock) + * @var string + * @access private */ - function getDependencyTypes() - { - return $GLOBALS['_PEAR_Common_dependency_types']; - } - + var $_lockfile = false; /** - * Get the implemented dependency relations (has, lt, ge etc.) - * - * @return array - * @static + * Open file resource for locking the lockfile + * @var resource|false + * @access private */ - function getDependencyRelations() - { - return $GLOBALS['_PEAR_Common_dependency_relations']; - } - + var $_lockFp = false; /** - * Get the implemented file roles - * - * @return array - * @static + * API version of this class, used to validate a file on-disk + * @var string + * @access private */ - function getFileRoles() - { - return $GLOBALS['_PEAR_Common_file_roles']; - } - + var $_version = '1.0'; /** - * Get the implemented file replacement types in - * - * @return array - * @static + * Cached dependency database file + * @var array|null + * @access private */ - function getReplacementTypes() - { - return $GLOBALS['_PEAR_Common_replacement_types']; - } + var $_cache; + + // }}} + // {{{ & singleton() /** - * Get the implemented file replacement types in - * - * @return array + * Get a raw dependency database. Calls setConfig() and assertDepsDB() + * @param PEAR_Config + * @param string|false full path to the dependency database, or false to use default + * @return PEAR_DependencyDB|PEAR_Error * @static */ - function getProvideTypes() + function &singleton(&$config, $depdb = false) { - return $GLOBALS['_PEAR_Common_provide_types']; + $phpdir = $config->get('php_dir', null, 'pear.php.net'); + if (!isset($GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir])) { + $a = new PEAR_DependencyDB; + $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir] = &$a; + $a->setConfig($config, $depdb); + $e = $a->assertDepsDB(); + if (PEAR::isError($e)) { + return $e; + } + } + + return $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir]; } /** - * Get the implemented file replacement types in - * - * @return array - * @static + * Set up the registry/location of dependency DB + * @param PEAR_Config|false + * @param string|false full path to the dependency database, or false to use default */ - function getScriptPhases() + function setConfig(&$config, $depdb = false) { - return $GLOBALS['_PEAR_Common_script_phases']; + if (!$config) { + $this->_config = &PEAR_Config::singleton(); + } else { + $this->_config = &$config; + } + + $this->_registry = &$this->_config->getRegistry(); + if (!$depdb) { + $this->_depdb = $this->_config->get('php_dir', null, 'pear.php.net') . + DIRECTORY_SEPARATOR . '.depdb'; + } else { + $this->_depdb = $depdb; + } + + $this->_lockfile = dirname($this->_depdb) . DIRECTORY_SEPARATOR . '.depdblock'; } + // }}} - /** - * Test whether a string contains a valid package name. - * - * @param string $name the package name to test - * - * @return bool - * - * @access public - */ - function validPackageName($name) + function hasWriteAccess() { - return (bool)preg_match(PEAR_COMMON_PACKAGE_NAME_PREG, $name); + if (!file_exists($this->_depdb)) { + $dir = $this->_depdb; + while ($dir && $dir != '.') { + $dir = dirname($dir); // cd .. + if ($dir != '.' && file_exists($dir)) { + if (is_writeable($dir)) { + return true; + } + + return false; + } + } + + return false; + } + + return is_writeable($this->_depdb); } + // {{{ assertDepsDB() + /** - * Test whether a string contains a valid package version. - * - * @param string $ver the package version to test - * - * @return bool - * - * @access public + * Create the dependency database, if it doesn't exist. Error if the database is + * newer than the code reading it. + * @return void|PEAR_Error */ - function validPackageVersion($ver) + function assertDepsDB() { - return (bool)preg_match(PEAR_COMMON_PACKAGE_VERSION_PREG, $ver); + if (!is_file($this->_depdb)) { + $this->rebuildDB(); + return; + } + + $depdb = $this->_getDepDB(); + // Datatype format has been changed, rebuild the Deps DB + if ($depdb['_version'] < $this->_version) { + $this->rebuildDB(); + } + + if ($depdb['_version']{0} > $this->_version{0}) { + return PEAR::raiseError('Dependency database is version ' . + $depdb['_version'] . ', and we are version ' . + $this->_version . ', cannot continue'); + } } /** - * @param string $path relative or absolute include path - * @return boolean - * @static + * Get a list of installed packages that depend on this package + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array + * @return array|false */ - function isIncludeable($path) + function getDependentPackages(&$pkg) { - if (file_exists($path) && is_readable($path)) { - return true; + $data = $this->_getDepDB(); + if (is_object($pkg)) { + $channel = strtolower($pkg->getChannel()); + $package = strtolower($pkg->getPackage()); + } else { + $channel = strtolower($pkg['channel']); + $package = strtolower($pkg['package']); } - $ipath = explode(PATH_SEPARATOR, ini_get('include_path')); - foreach ($ipath as $include) { - $test = realpath($include . DIRECTORY_SEPARATOR . $path); - if (file_exists($test) && is_readable($test)) { - return true; - } + if (isset($data['packages'][$channel][$package])) { + return $data['packages'][$channel][$package]; } return false; } /** - * Returns information about a package file. Expects the name of - * a gzipped tar file as input. - * - * @param string $file name of .tgz file - * - * @return array array with package information - * - * @access public - * @deprecated use PEAR_PackageFile->fromTgzFile() instead - * + * Get a list of the actual dependencies of installed packages that depend on + * a package. + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array + * @return array|false */ - function infoFromTgzFile($file) + function getDependentPackageDependencies(&$pkg) { - $packagefile = &new PEAR_PackageFile($this->config); - $pf = &$packagefile->fromTgzFile($file, PEAR_VALIDATE_NORMAL); - if (PEAR::isError($pf)) { - $errs = $pf->getUserinfo(); - if (is_array($errs)) { - foreach ($errs as $error) { - $e = $this->raiseError($error['message'], $error['code'], null, null, $error); + $data = $this->_getDepDB(); + if (is_object($pkg)) { + $channel = strtolower($pkg->getChannel()); + $package = strtolower($pkg->getPackage()); + } else { + $channel = strtolower($pkg['channel']); + $package = strtolower($pkg['package']); + } + + $depend = $this->getDependentPackages($pkg); + if (!$depend) { + return false; + } + + $dependencies = array(); + foreach ($depend as $info) { + $temp = $this->getDependencies($info); + foreach ($temp as $dep) { + if ( + isset($dep['dep'], $dep['dep']['channel'], $dep['dep']['name']) && + strtolower($dep['dep']['channel']) == $channel && + strtolower($dep['dep']['name']) == $package + ) { + if (!isset($dependencies[$info['channel']])) { + $dependencies[$info['channel']] = array(); + } + + if (!isset($dependencies[$info['channel']][$info['package']])) { + $dependencies[$info['channel']][$info['package']] = array(); + } + $dependencies[$info['channel']][$info['package']][] = $dep; } } - - return $pf; } - return $this->_postProcessValidPackagexml($pf); + return $dependencies; } /** - * Returns information about a package file. Expects the name of - * a package xml file as input. - * - * @param string $descfile name of package xml file - * - * @return array array with package information - * - * @access public - * @deprecated use PEAR_PackageFile->fromPackageFile() instead - * + * Get a list of dependencies of this installed package + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array + * @return array|false */ - function infoFromDescriptionFile($descfile) + function getDependencies(&$pkg) { - $packagefile = &new PEAR_PackageFile($this->config); - $pf = &$packagefile->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL); - if (PEAR::isError($pf)) { - $errs = $pf->getUserinfo(); - if (is_array($errs)) { - foreach ($errs as $error) { - $e = $this->raiseError($error['message'], $error['code'], null, null, $error); - } - } + if (is_object($pkg)) { + $channel = strtolower($pkg->getChannel()); + $package = strtolower($pkg->getPackage()); + } else { + $channel = strtolower($pkg['channel']); + $package = strtolower($pkg['package']); + } - return $pf; + $data = $this->_getDepDB(); + if (isset($data['dependencies'][$channel][$package])) { + return $data['dependencies'][$channel][$package]; } - return $this->_postProcessValidPackagexml($pf); + return false; } /** - * Returns information about a package file. Expects the contents - * of a package xml file as input. - * - * @param string $data contents of package.xml file - * - * @return array array with package information - * - * @access public - * @deprecated use PEAR_PackageFile->fromXmlstring() instead - * + * Determine whether $parent depends on $child, near or deep + * @param array|PEAR_PackageFile_v2|PEAR_PackageFile_v2 + * @param array|PEAR_PackageFile_v2|PEAR_PackageFile_v2 */ - function infoFromString($data) + function dependsOn($parent, $child) { - $packagefile = &new PEAR_PackageFile($this->config); - $pf = &$packagefile->fromXmlString($data, PEAR_VALIDATE_NORMAL, false); - if (PEAR::isError($pf)) { - $errs = $pf->getUserinfo(); - if (is_array($errs)) { - foreach ($errs as $error) { - $e = $this->raiseError($error['message'], $error['code'], null, null, $error); + $c = array(); + $this->_getDepDB(); + return $this->_dependsOn($parent, $child, $c); + } + + function _dependsOn($parent, $child, &$checked) + { + if (is_object($parent)) { + $channel = strtolower($parent->getChannel()); + $package = strtolower($parent->getPackage()); + } else { + $channel = strtolower($parent['channel']); + $package = strtolower($parent['package']); + } + + if (is_object($child)) { + $depchannel = strtolower($child->getChannel()); + $deppackage = strtolower($child->getPackage()); + } else { + $depchannel = strtolower($child['channel']); + $deppackage = strtolower($child['package']); + } + + if (isset($checked[$channel][$package][$depchannel][$deppackage])) { + return false; // avoid endless recursion + } + + $checked[$channel][$package][$depchannel][$deppackage] = true; + if (!isset($this->_cache['dependencies'][$channel][$package])) { + return false; + } + + foreach ($this->_cache['dependencies'][$channel][$package] as $info) { + if (isset($info['dep']['uri'])) { + if (is_object($child)) { + if ($info['dep']['uri'] == $child->getURI()) { + return true; + } + } elseif (isset($child['uri'])) { + if ($info['dep']['uri'] == $child['uri']) { + return true; + } } + return false; } - return $pf; + if (strtolower($info['dep']['channel']) == $depchannel && + strtolower($info['dep']['name']) == $deppackage) { + return true; + } + } + + foreach ($this->_cache['dependencies'][$channel][$package] as $info) { + if (isset($info['dep']['uri'])) { + if ($this->_dependsOn(array( + 'uri' => $info['dep']['uri'], + 'package' => $info['dep']['name']), $child, $checked)) { + return true; + } + } else { + if ($this->_dependsOn(array( + 'channel' => $info['dep']['channel'], + 'package' => $info['dep']['name']), $child, $checked)) { + return true; + } + } } - return $this->_postProcessValidPackagexml($pf); + return false; } /** - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @return array + * Register dependencies of a package that is being installed or upgraded + * @param PEAR_PackageFile_v2|PEAR_PackageFile_v2 */ - function _postProcessValidPackagexml(&$pf) + function installPackage(&$package) { - if (!is_a($pf, 'PEAR_PackageFile_v2')) { - $this->pkginfo = $pf->toArray(); - return $this->pkginfo; - } - - // sort of make this into a package.xml 1.0-style array - // changelog is not converted to old format. - $arr = $pf->toArray(true); - $arr = array_merge($arr, $arr['old']); - unset($arr['old']); - unset($arr['xsdversion']); - unset($arr['contents']); - unset($arr['compatible']); - unset($arr['channel']); - unset($arr['uri']); - unset($arr['dependencies']); - unset($arr['phprelease']); - unset($arr['extsrcrelease']); - unset($arr['zendextsrcrelease']); - unset($arr['extbinrelease']); - unset($arr['zendextbinrelease']); - unset($arr['bundle']); - unset($arr['lead']); - unset($arr['developer']); - unset($arr['helper']); - unset($arr['contributor']); - $arr['filelist'] = $pf->getFilelist(); - $this->pkginfo = $arr; - return $arr; + $data = $this->_getDepDB(); + unset($this->_cache); + $this->_setPackageDeps($data, $package); + $this->_writeDepDB($data); } /** - * Returns package information from different sources - * - * This method is able to extract information about a package - * from a .tgz archive or from a XML package definition file. + * Remove dependencies of a package that is being uninstalled, or upgraded. * - * @access public - * @param string Filename of the source ('package.xml', '.tgz') - * @return string - * @deprecated use PEAR_PackageFile->fromAnyFile() instead + * Upgraded packages first uninstall, then install + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array If an array, then it must have + * indices 'channel' and 'package' */ - function infoFromAny($info) + function uninstallPackage(&$pkg) { - if (is_string($info) && file_exists($info)) { - $packagefile = &new PEAR_PackageFile($this->config); - $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL); - if (PEAR::isError($pf)) { - $errs = $pf->getUserinfo(); - if (is_array($errs)) { - foreach ($errs as $error) { - $e = $this->raiseError($error['message'], $error['code'], null, null, $error); + $data = $this->_getDepDB(); + unset($this->_cache); + if (is_object($pkg)) { + $channel = strtolower($pkg->getChannel()); + $package = strtolower($pkg->getPackage()); + } else { + $channel = strtolower($pkg['channel']); + $package = strtolower($pkg['package']); + } + + if (!isset($data['dependencies'][$channel][$package])) { + return true; + } + + foreach ($data['dependencies'][$channel][$package] as $dep) { + $found = false; + $depchannel = isset($dep['dep']['uri']) ? '__uri' : strtolower($dep['dep']['channel']); + $depname = strtolower($dep['dep']['name']); + if (isset($data['packages'][$depchannel][$depname])) { + foreach ($data['packages'][$depchannel][$depname] as $i => $info) { + if ($info['channel'] == $channel && $info['package'] == $package) { + $found = true; + break; } } + } - return $pf; + if ($found) { + unset($data['packages'][$depchannel][$depname][$i]); + if (!count($data['packages'][$depchannel][$depname])) { + unset($data['packages'][$depchannel][$depname]); + if (!count($data['packages'][$depchannel])) { + unset($data['packages'][$depchannel]); + } + } else { + $data['packages'][$depchannel][$depname] = + array_values($data['packages'][$depchannel][$depname]); + } } + } - return $this->_postProcessValidPackagexml($pf); + unset($data['dependencies'][$channel][$package]); + if (!count($data['dependencies'][$channel])) { + unset($data['dependencies'][$channel]); } - return $info; - } + if (!count($data['dependencies'])) { + unset($data['dependencies']); + } - /** - * Return an XML document based on the package info (as returned - * by the PEAR_Common::infoFrom* methods). - * - * @param array $pkginfo package info - * - * @return string XML data - * - * @access public - * @deprecated use a PEAR_PackageFile_v* object's generator instead - */ - function xmlFromInfo($pkginfo) - { - $config = &PEAR_Config::singleton(); - $packagefile = &new PEAR_PackageFile($config); - $pf = &$packagefile->fromArray($pkginfo); - $gen = &$pf->getDefaultGenerator(); - return $gen->toXml(PEAR_VALIDATE_PACKAGING); + if (!count($data['packages'])) { + unset($data['packages']); + } + + $this->_writeDepDB($data); } /** - * Validate XML package definition file. - * - * @param string $info Filename of the package archive or of the - * package definition file - * @param array $errors Array that will contain the errors - * @param array $warnings Array that will contain the warnings - * @param string $dir_prefix (optional) directory where source files - * may be found, or empty if they are not available - * @access public - * @return boolean - * @deprecated use the validation of PEAR_PackageFile objects + * Rebuild the dependency DB by reading registry entries. + * @return true|PEAR_Error */ - function validatePackageInfo($info, &$errors, &$warnings, $dir_prefix = '') + function rebuildDB() { - $config = &PEAR_Config::singleton(); - $packagefile = &new PEAR_PackageFile($config); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - if (strpos($info, 'fromXmlString($info, PEAR_VALIDATE_NORMAL, ''); - } else { - $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL); + $depdb = array('_version' => $this->_version); + if (!$this->hasWriteAccess()) { + // allow startup for read-only with older Registry + return $depdb; } - PEAR::staticPopErrorHandling(); - if (PEAR::isError($pf)) { - $errs = $pf->getUserinfo(); - if (is_array($errs)) { - foreach ($errs as $error) { - if ($error['level'] == 'error') { - $errors[] = $error['message']; - } else { - $warnings[] = $error['message']; - } + $packages = $this->_registry->listAllPackages(); + if (PEAR::isError($packages)) { + return $packages; + } + + foreach ($packages as $channel => $ps) { + foreach ($ps as $package) { + $package = $this->_registry->getPackage($package, $channel); + if (PEAR::isError($package)) { + return $package; } + $this->_setPackageDeps($depdb, $package); } + } - return false; + $error = $this->_writeDepDB($depdb); + if (PEAR::isError($error)) { + return $error; } + $this->_cache = $depdb; return true; } /** - * Build a "provides" array from data returned by - * analyzeSourceCode(). The format of the built array is like - * this: - * - * array( - * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'), - * ... - * ) - * - * - * @param array $srcinfo array with information about a source file - * as returned by the analyzeSourceCode() method. - * - * @return void - * - * @access public - * + * Register usage of the dependency DB to prevent race conditions + * @param int one of the LOCK_* constants + * @return true|PEAR_Error + * @access private */ - function buildProvidesArray($srcinfo) + function _lock($mode = LOCK_EX) { - $file = basename($srcinfo['source_file']); - $pn = ''; - if (isset($this->_packageName)) { - $pn = $this->_packageName; + if (stristr(php_uname(), 'Windows 9')) { + return true; } - $pnl = strlen($pn); - foreach ($srcinfo['declared_classes'] as $class) { - $key = "class;$class"; - if (isset($this->pkginfo['provides'][$key])) { - continue; - } + if ($mode != LOCK_UN && is_resource($this->_lockFp)) { + // XXX does not check type of lock (LOCK_SH/LOCK_EX) + return true; + } - $this->pkginfo['provides'][$key] = - array('file'=> $file, 'type' => 'class', 'name' => $class); - if (isset($srcinfo['inheritance'][$class])) { - $this->pkginfo['provides'][$key]['extends'] = - $srcinfo['inheritance'][$class]; + $open_mode = 'w'; + // XXX People reported problems with LOCK_SH and 'w' + if ($mode === LOCK_SH) { + if (!file_exists($this->_lockfile)) { + touch($this->_lockfile); + } elseif (!is_file($this->_lockfile)) { + return PEAR::raiseError('could not create Dependency lock file, ' . + 'it exists and is not a regular file'); } + $open_mode = 'r'; } - foreach ($srcinfo['declared_methods'] as $class => $methods) { - foreach ($methods as $method) { - $function = "$class::$method"; - $key = "function;$function"; - if ($method{0} == '_' || !strcasecmp($method, $class) || - isset($this->pkginfo['provides'][$key])) { - continue; - } - - $this->pkginfo['provides'][$key] = - array('file'=> $file, 'type' => 'function', 'name' => $function); - } + if (!is_resource($this->_lockFp)) { + $this->_lockFp = @fopen($this->_lockfile, $open_mode); } - foreach ($srcinfo['declared_functions'] as $function) { - $key = "function;$function"; - if ($function{0} == '_' || isset($this->pkginfo['provides'][$key])) { - continue; - } + if (!is_resource($this->_lockFp)) { + return PEAR::raiseError("could not create Dependency lock file" . + (isset($php_errormsg) ? ": " . $php_errormsg : "")); + } - if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) { - $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\""; + if (!(int)flock($this->_lockFp, $mode)) { + switch ($mode) { + case LOCK_SH: $str = 'shared'; break; + case LOCK_EX: $str = 'exclusive'; break; + case LOCK_UN: $str = 'unlock'; break; + default: $str = 'unknown'; break; } - $this->pkginfo['provides'][$key] = - array('file'=> $file, 'type' => 'function', 'name' => $function); + return PEAR::raiseError("could not acquire $str lock ($this->_lockfile)"); } + + return true; } /** - * Analyze the source code of the given PHP file - * - * @param string Filename of the PHP file - * @return mixed - * @access public + * Release usage of dependency DB + * @return true|PEAR_Error + * @access private */ - function analyzeSourceCode($file) + function _unlock() { - if (!class_exists('PEAR_PackageFile_v2_Validator')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/v2/Validator.php'; + $ret = $this->_lock(LOCK_UN); + if (is_resource($this->_lockFp)) { + fclose($this->_lockFp); } - - $a = new PEAR_PackageFile_v2_Validator; - return $a->analyzeSourceCode($file); + $this->_lockFp = null; + return $ret; } - function detectDependencies($any, $status_callback = null) + /** + * Load the dependency database from disk, or return the cache + * @return array|PEAR_Error + */ + function _getDepDB() { - if (!function_exists("token_get_all")) { - return false; + if (!$this->hasWriteAccess()) { + return array('_version' => $this->_version); } - if (PEAR::isError($info = $this->infoFromAny($any))) { - return $this->raiseError($info); + if (isset($this->_cache)) { + return $this->_cache; } - if (!is_array($info)) { - return false; + if (!$fp = fopen($this->_depdb, 'r')) { + $err = PEAR::raiseError("Could not open dependencies file `".$this->_depdb."'"); + return $err; } - $deps = array(); - $used_c = $decl_c = $decl_f = $decl_m = array(); - foreach ($info['filelist'] as $file => $fa) { - $tmp = $this->analyzeSourceCode($file); - $used_c = @array_merge($used_c, $tmp['used_classes']); - $decl_c = @array_merge($decl_c, $tmp['declared_classes']); - $decl_f = @array_merge($decl_f, $tmp['declared_functions']); - $decl_m = @array_merge($decl_m, $tmp['declared_methods']); - $inheri = @array_merge($inheri, $tmp['inheritance']); + $rt = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + clearstatcache(); + fclose($fp); + $data = unserialize(file_get_contents($this->_depdb)); + set_magic_quotes_runtime($rt); + $this->_cache = $data; + return $data; + } + + /** + * Write out the dependency database to disk + * @param array the database + * @return true|PEAR_Error + * @access private + */ + function _writeDepDB(&$deps) + { + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; } - $used_c = array_unique($used_c); - $decl_c = array_unique($decl_c); - $undecl_c = array_diff($used_c, $decl_c); + if (!$fp = fopen($this->_depdb, 'wb')) { + $this->_unlock(); + return PEAR::raiseError("Could not open dependencies file `".$this->_depdb."' for writing"); + } - return array('used_classes' => $used_c, - 'declared_classes' => $decl_c, - 'declared_methods' => $decl_m, - 'declared_functions' => $decl_f, - 'undeclared_classes' => $undecl_c, - 'inheritance' => $inheri, - ); + $rt = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + fwrite($fp, serialize($deps)); + set_magic_quotes_runtime($rt); + fclose($fp); + $this->_unlock(); + $this->_cache = $deps; + return true; } /** - * Download a file through HTTP. Considers suggested file name in - * Content-disposition: header and can run a callback function for - * different events. The callback will be called with two - * parameters: the callback type, and parameters. The implemented - * callback types are: - * - * 'setup' called at the very beginning, parameter is a UI object - * that should be used for all output - * 'message' the parameter is a string with an informational message - * 'saveas' may be used to save with a different file name, the - * parameter is the filename that is about to be used. - * If a 'saveas' callback returns a non-empty string, - * that file name will be used as the filename instead. - * Note that $save_dir will not be affected by this, only - * the basename of the file. - * 'start' download is starting, parameter is number of bytes - * that are expected, or -1 if unknown - * 'bytesread' parameter is the number of bytes read so far - * 'done' download is complete, parameter is the total number - * of bytes read - * 'connfailed' if the TCP connection fails, this callback is called - * with array(host,port,errno,errmsg) - * 'writefailed' if writing to disk fails, this callback is called - * with array(destfile,errmsg) - * - * If an HTTP proxy has been configured (http_proxy PEAR_Config - * setting), the proxy will be used. - * - * @param string $url the URL to download - * @param object $ui PEAR_Frontend_* instance - * @param object $config PEAR_Config instance - * @param string $save_dir (optional) directory to save file in - * @param mixed $callback (optional) function/method to call for status - * updates - * - * @return string Returns the full path of the downloaded file or a PEAR - * error on failure. If the error is caused by - * socket-related errors, the error object will - * have the fsockopen error code available through - * getCode(). - * - * @access public - * @deprecated in favor of PEAR_Downloader::downloadHttp() + * Register all dependencies from a package in the dependencies database, in essence + * "installing" the package's dependency information + * @param array the database + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @access private */ - function downloadHttp($url, &$ui, $save_dir = '.', $callback = null) + function _setPackageDeps(&$data, &$pkg) { - if (!class_exists('PEAR_Downloader')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Downloader.php'; + $pkg->setConfig($this->_config); + if ($pkg->getPackagexmlVersion() == '1.0') { + $gen = &$pkg->getDefaultGenerator(); + $deps = $gen->dependenciesToV2(); + } else { + $deps = $pkg->getDeps(true); } - return PEAR_Downloader::downloadHttp($url, $ui, $save_dir, $callback); - } -} -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Config.php'; -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile.php'; - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Config.php,v 1.157 2009/02/25 00:23:26 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ + if (!$deps) { + return; + } -/** - * Required for error handling - */ -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR.php'; -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Registry.php'; -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Installer/Role.php'; -require_once 'phar://install-pear-nozlib.phar/' . 'System.php'; + if (!is_array($data)) { + $data = array(); + } -/** - * Last created PEAR_Config instance. - * @var object - */ -$GLOBALS['_PEAR_Config_instance'] = null; -if (!defined('PEAR_INSTALL_DIR') || !PEAR_INSTALL_DIR) { - $PEAR_INSTALL_DIR = PHP_LIBDIR . DIRECTORY_SEPARATOR . 'pear'; -} else { - $PEAR_INSTALL_DIR = PEAR_INSTALL_DIR; -} + if (!isset($data['dependencies'])) { + $data['dependencies'] = array(); + } -// Below we define constants with default values for all configuration -// parameters except username/password. All of them can have their -// defaults set through environment variables. The reason we use the -// PHP_ prefix is for some security, PHP protects environment -// variables starting with PHP_*. + $channel = strtolower($pkg->getChannel()); + $package = strtolower($pkg->getPackage()); -// default channel and preferred mirror is based on whether we are invoked through -// the "pear" or the "pecl" command -if (!defined('PEAR_RUNTYPE')) { - define('PEAR_RUNTYPE', 'pear'); -} + if (!isset($data['dependencies'][$channel])) { + $data['dependencies'][$channel] = array(); + } -if (PEAR_RUNTYPE == 'pear') { - define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pear.php.net'); -} else { - define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pecl.php.net'); -} + $data['dependencies'][$channel][$package] = array(); + if (isset($deps['required']['package'])) { + if (!isset($deps['required']['package'][0])) { + $deps['required']['package'] = array($deps['required']['package']); + } -if (getenv('PHP_PEAR_SYSCONF_DIR')) { - define('PEAR_CONFIG_SYSCONFDIR', getenv('PHP_PEAR_SYSCONF_DIR')); -} elseif (getenv('SystemRoot')) { - define('PEAR_CONFIG_SYSCONFDIR', getenv('SystemRoot')); -} else { - define('PEAR_CONFIG_SYSCONFDIR', PHP_SYSCONFDIR); -} + foreach ($deps['required']['package'] as $dep) { + $this->_registerDep($data, $pkg, $dep, 'required'); + } + } -// Default for master_server -if (getenv('PHP_PEAR_MASTER_SERVER')) { - define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', getenv('PHP_PEAR_MASTER_SERVER')); -} else { - define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', 'pear.php.net'); -} + if (isset($deps['optional']['package'])) { + if (!isset($deps['optional']['package'][0])) { + $deps['optional']['package'] = array($deps['optional']['package']); + } -// Default for http_proxy -if (getenv('PHP_PEAR_HTTP_PROXY')) { - define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('PHP_PEAR_HTTP_PROXY')); -} elseif (getenv('http_proxy')) { - define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('http_proxy')); -} else { - define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', ''); -} + foreach ($deps['optional']['package'] as $dep) { + $this->_registerDep($data, $pkg, $dep, 'optional'); + } + } -// Default for php_dir -if (getenv('PHP_PEAR_INSTALL_DIR')) { - define('PEAR_CONFIG_DEFAULT_PHP_DIR', getenv('PHP_PEAR_INSTALL_DIR')); -} else { - if (@file_exists($PEAR_INSTALL_DIR) && is_dir($PEAR_INSTALL_DIR)) { - define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR); - } else { - define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR); - } -} + if (isset($deps['required']['subpackage'])) { + if (!isset($deps['required']['subpackage'][0])) { + $deps['required']['subpackage'] = array($deps['required']['subpackage']); + } -// Default for ext_dir -if (getenv('PHP_PEAR_EXTENSION_DIR')) { - define('PEAR_CONFIG_DEFAULT_EXT_DIR', getenv('PHP_PEAR_EXTENSION_DIR')); -} else { - if (ini_get('extension_dir')) { - define('PEAR_CONFIG_DEFAULT_EXT_DIR', ini_get('extension_dir')); - } elseif (defined('PEAR_EXTENSION_DIR') && - file_exists(PEAR_EXTENSION_DIR) && is_dir(PEAR_EXTENSION_DIR)) { - define('PEAR_CONFIG_DEFAULT_EXT_DIR', PEAR_EXTENSION_DIR); - } elseif (defined('PHP_EXTENSION_DIR')) { - define('PEAR_CONFIG_DEFAULT_EXT_DIR', PHP_EXTENSION_DIR); - } else { - define('PEAR_CONFIG_DEFAULT_EXT_DIR', '.'); - } -} + foreach ($deps['required']['subpackage'] as $dep) { + $this->_registerDep($data, $pkg, $dep, 'required'); + } + } -// Default for doc_dir -if (getenv('PHP_PEAR_DOC_DIR')) { - define('PEAR_CONFIG_DEFAULT_DOC_DIR', getenv('PHP_PEAR_DOC_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_DOC_DIR', - $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'docs'); -} + if (isset($deps['optional']['subpackage'])) { + if (!isset($deps['optional']['subpackage'][0])) { + $deps['optional']['subpackage'] = array($deps['optional']['subpackage']); + } -// Default for bin_dir -if (getenv('PHP_PEAR_BIN_DIR')) { - define('PEAR_CONFIG_DEFAULT_BIN_DIR', getenv('PHP_PEAR_BIN_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_BIN_DIR', PHP_BINDIR); -} + foreach ($deps['optional']['subpackage'] as $dep) { + $this->_registerDep($data, $pkg, $dep, 'optional'); + } + } -// Default for data_dir -if (getenv('PHP_PEAR_DATA_DIR')) { - define('PEAR_CONFIG_DEFAULT_DATA_DIR', getenv('PHP_PEAR_DATA_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_DATA_DIR', - $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'data'); -} + if (isset($deps['group'])) { + if (!isset($deps['group'][0])) { + $deps['group'] = array($deps['group']); + } -// Default for cfg_dir -if (getenv('PHP_PEAR_CFG_DIR')) { - define('PEAR_CONFIG_DEFAULT_CFG_DIR', getenv('PHP_PEAR_CFG_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_CFG_DIR', - $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'cfg'); -} + foreach ($deps['group'] as $group) { + if (isset($group['package'])) { + if (!isset($group['package'][0])) { + $group['package'] = array($group['package']); + } -// Default for www_dir -if (getenv('PHP_PEAR_WWW_DIR')) { - define('PEAR_CONFIG_DEFAULT_WWW_DIR', getenv('PHP_PEAR_WWW_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_WWW_DIR', - $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'www'); -} + foreach ($group['package'] as $dep) { + $this->_registerDep($data, $pkg, $dep, 'optional', + $group['attribs']['name']); + } + } -// Default for test_dir -if (getenv('PHP_PEAR_TEST_DIR')) { - define('PEAR_CONFIG_DEFAULT_TEST_DIR', getenv('PHP_PEAR_TEST_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_TEST_DIR', - $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'tests'); -} + if (isset($group['subpackage'])) { + if (!isset($group['subpackage'][0])) { + $group['subpackage'] = array($group['subpackage']); + } -// Default for temp_dir -if (getenv('PHP_PEAR_TEMP_DIR')) { - define('PEAR_CONFIG_DEFAULT_TEMP_DIR', getenv('PHP_PEAR_TEMP_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_TEMP_DIR', - System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' . - DIRECTORY_SEPARATOR . 'temp'); -} + foreach ($group['subpackage'] as $dep) { + $this->_registerDep($data, $pkg, $dep, 'optional', + $group['attribs']['name']); + } + } + } + } -// Default for cache_dir -if (getenv('PHP_PEAR_CACHE_DIR')) { - define('PEAR_CONFIG_DEFAULT_CACHE_DIR', getenv('PHP_PEAR_CACHE_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_CACHE_DIR', - System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' . - DIRECTORY_SEPARATOR . 'cache'); -} + if ($data['dependencies'][$channel][$package] == array()) { + unset($data['dependencies'][$channel][$package]); + if (!count($data['dependencies'][$channel])) { + unset($data['dependencies'][$channel]); + } + } + } -// Default for download_dir -if (getenv('PHP_PEAR_DOWNLOAD_DIR')) { - define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR', getenv('PHP_PEAR_DOWNLOAD_DIR')); -} else { - define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR', - System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' . - DIRECTORY_SEPARATOR . 'download'); -} + /** + * @param array the database + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @param array the specific dependency + * @param required|optional whether this is a required or an optional dep + * @param string|false dependency group this dependency is from, or false for ordinary dep + */ + function _registerDep(&$data, &$pkg, $dep, $type, $group = false) + { + $info = array( + 'dep' => $dep, + 'type' => $type, + 'group' => $group + ); -// Default for php_bin -if (getenv('PHP_PEAR_PHP_BIN')) { - define('PEAR_CONFIG_DEFAULT_PHP_BIN', getenv('PHP_PEAR_PHP_BIN')); -} else { - define('PEAR_CONFIG_DEFAULT_PHP_BIN', PEAR_CONFIG_DEFAULT_BIN_DIR. - DIRECTORY_SEPARATOR.'php'.(OS_WINDOWS ? '.exe' : '')); -} + $dep = array_map('strtolower', $dep); + $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri'; + if (!isset($data['dependencies'])) { + $data['dependencies'] = array(); + } -// Default for verbose -if (getenv('PHP_PEAR_VERBOSE')) { - define('PEAR_CONFIG_DEFAULT_VERBOSE', getenv('PHP_PEAR_VERBOSE')); -} else { - define('PEAR_CONFIG_DEFAULT_VERBOSE', 1); -} + $channel = strtolower($pkg->getChannel()); + $package = strtolower($pkg->getPackage()); -// Default for preferred_state -if (getenv('PHP_PEAR_PREFERRED_STATE')) { - define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', getenv('PHP_PEAR_PREFERRED_STATE')); -} else { - define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', 'stable'); -} + if (!isset($data['dependencies'][$channel])) { + $data['dependencies'][$channel] = array(); + } -// Default for umask -if (getenv('PHP_PEAR_UMASK')) { - define('PEAR_CONFIG_DEFAULT_UMASK', getenv('PHP_PEAR_UMASK')); -} else { - define('PEAR_CONFIG_DEFAULT_UMASK', decoct(umask())); -} + if (!isset($data['dependencies'][$channel][$package])) { + $data['dependencies'][$channel][$package] = array(); + } -// Default for cache_ttl -if (getenv('PHP_PEAR_CACHE_TTL')) { - define('PEAR_CONFIG_DEFAULT_CACHE_TTL', getenv('PHP_PEAR_CACHE_TTL')); -} else { - define('PEAR_CONFIG_DEFAULT_CACHE_TTL', 3600); -} + $data['dependencies'][$channel][$package][] = $info; + if (isset($data['packages'][$depchannel][$dep['name']])) { + $found = false; + foreach ($data['packages'][$depchannel][$dep['name']] as $i => $p) { + if ($p['channel'] == $channel && $p['package'] == $package) { + $found = true; + break; + } + } + } else { + if (!isset($data['packages'])) { + $data['packages'] = array(); + } -// Default for sig_type -if (getenv('PHP_PEAR_SIG_TYPE')) { - define('PEAR_CONFIG_DEFAULT_SIG_TYPE', getenv('PHP_PEAR_SIG_TYPE')); -} else { - define('PEAR_CONFIG_DEFAULT_SIG_TYPE', 'gpg'); -} + if (!isset($data['packages'][$depchannel])) { + $data['packages'][$depchannel] = array(); + } -// Default for sig_bin -if (getenv('PHP_PEAR_SIG_BIN')) { - define('PEAR_CONFIG_DEFAULT_SIG_BIN', getenv('PHP_PEAR_SIG_BIN')); -} else { - define('PEAR_CONFIG_DEFAULT_SIG_BIN', - System::which( - 'gpg', OS_WINDOWS ? 'c:\gnupg\gpg.exe' : '/usr/local/bin/gpg')); -} + if (!isset($data['packages'][$depchannel][$dep['name']])) { + $data['packages'][$depchannel][$dep['name']] = array(); + } -// Default for sig_keydir -if (getenv('PHP_PEAR_SIG_KEYDIR')) { - define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR', getenv('PHP_PEAR_SIG_KEYDIR')); -} else { - define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR', - PEAR_CONFIG_SYSCONFDIR . DIRECTORY_SEPARATOR . 'pearkeys'); -} + $found = false; + } + if (!$found) { + $data['packages'][$depchannel][$dep['name']][] = array( + 'channel' => $channel, + 'package' => $package + ); + } + } +} * @author Stig Bakken + * @author Tomas V. V. Cox + * @author Martin Jansen + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Downloader.php 287109 2009-08-11 18:50:30Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.3.0 + */ + +/** + * Needed for constants, extending + */ +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Common.php'; + +define('PEAR_INSTALLER_OK', 1); +define('PEAR_INSTALLER_FAILED', 0); +define('PEAR_INSTALLER_SKIPPED', -1); +define('PEAR_INSTALLER_ERROR_NO_PREF_STATE', 2); + +/** + * Administration class used to download anything from the internet (PEAR Packages, + * static URLs, xml files) + * + * @category pear + * @package PEAR * @author Greg Beaver + * @author Stig Bakken + * @author Tomas V. V. Cox + * @author Martin Jansen * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 + * @since Class available since Release 1.3.0 */ -class PEAR_Config extends PEAR +class PEAR_Downloader extends PEAR_Common { /** - * Array of config files used. - * - * @var array layer => config file + * @var PEAR_Registry + * @access private */ - var $files = array( - 'system' => '', - 'user' => '', - ); - - var $layers = array(); + var $_registry; /** - * Configuration data, two-dimensional array where the first - * dimension is the config layer ('user', 'system' and 'default'), - * and the second dimension is keyname => value. - * - * The order in the first dimension is important! Earlier - * layers will shadow later ones when a config value is - * requested (if a 'user' value exists, it will be returned first, - * then 'system' and finally 'default'). - * - * @var array layer => array(keyname => value, ...) + * Preferred Installation State (snapshot, devel, alpha, beta, stable) + * @var string|null + * @access private */ - var $configuration = array( - 'user' => array(), - 'system' => array(), - 'default' => array(), - ); + var $_preferredState; /** - * Configuration values that can be set for a channel + * Options from command-line passed to Install. * - * All other configuration values can only have a global value - * @var array + * Recognized options:
+ * - onlyreqdeps : install all required dependencies as well + * - alldeps : install all dependencies, including optional + * - installroot : base relative path to install files in + * - force : force a download even if warnings would prevent it + * - nocompress : download uncompressed tarballs + * @see PEAR_Command_Install * @access private + * @var array */ - var $_channelConfigInfo = array( - 'php_dir', 'ext_dir', 'doc_dir', 'bin_dir', 'data_dir', 'cfg_dir', - 'test_dir', 'www_dir', 'php_bin', 'php_prefix', 'php_suffix', 'username', - 'password', 'verbose', 'preferred_state', 'umask', 'preferred_mirror', 'php_ini' - ); + var $_options; /** - * Channels that can be accessed - * @see setChannels() - * @var array + * Downloaded Packages after a call to download(). + * + * Format of each entry: + * + * + * array('pkg' => 'package_name', 'file' => '/path/to/local/file', + * 'info' => array() // parsed package.xml + * ); + * * @access private + * @var array */ - var $_channels = array('pear.php.net', 'pecl.php.net', '__uri'); + var $_downloadedPackages = array(); /** - * This variable is used to control the directory values returned - * @see setInstallRoot(); - * @var string|false + * Packages slated for download. + * + * This is used to prevent downloading a package more than once should it be a dependency + * for two packages to be installed. + * Format of each entry: + * + *
+     * array('package_name1' => parsed package.xml, 'package_name2' => parsed package.xml,
+     * );
+     * 
* @access private + * @var array */ - var $_installRoot = false; + var $_toDownload = array(); /** - * If requested, this will always refer to the registry - * contained in php_dir - * @var PEAR_Registry + * Array of every package installed, with names lower-cased. + * + * Format: + * + * array('package1' => 0, 'package2' => 1, ); + * + * @var array */ - var $_registry = array(); + var $_installed = array(); /** * @var array * @access private */ - var $_regInitialized = array(); + var $_errorStack = array(); /** - * @var bool + * @var boolean * @access private */ - var $_noRegistry = false; + var $_internalDownload = false; /** - * amount of errors found while parsing config - * @var integer + * Temporary variable used in sorting packages by dependency in {@link sortPkgDeps()} + * @var array * @access private */ - var $_errorsFound = 0; - var $_lastError = null; + var $_packageSortTree; /** - * Information about the configuration data. Stores the type, - * default value and a documentation string for each configuration - * value. - * - * @var array layer => array(infotype => value, ...) + * Temporary directory, or configuration value where downloads will occur + * @var string */ - var $configuration_info = array( - // Channels/Internet Access - 'default_channel' => array( - 'type' => 'string', - 'default' => PEAR_CONFIG_DEFAULT_CHANNEL, - 'doc' => 'the default channel to use for all non explicit commands', - 'prompt' => 'Default Channel', - 'group' => 'Internet Access', - ), - 'preferred_mirror' => array( - 'type' => 'string', - 'default' => PEAR_CONFIG_DEFAULT_CHANNEL, - 'doc' => 'the default server or mirror to use for channel actions', - 'prompt' => 'Default Channel Mirror', - 'group' => 'Internet Access', - ), - 'remote_config' => array( - 'type' => 'password', - 'default' => '', - 'doc' => 'ftp url of remote configuration file to use for synchronized install', - 'prompt' => 'Remote Configuration File', - 'group' => 'Internet Access', - ), - 'auto_discover' => array( - 'type' => 'integer', - 'default' => 0, - 'doc' => 'whether to automatically discover new channels', - 'prompt' => 'Auto-discover new Channels', - 'group' => 'Internet Access', - ), - // Internet Access - 'master_server' => array( - 'type' => 'string', - 'default' => 'pear.php.net', - 'doc' => 'name of the main PEAR server [NOT USED IN THIS VERSION]', - 'prompt' => 'PEAR server [DEPRECATED]', - 'group' => 'Internet Access', - ), - 'http_proxy' => array( - 'type' => 'string', - 'default' => PEAR_CONFIG_DEFAULT_HTTP_PROXY, - 'doc' => 'HTTP proxy (host:port) to use when downloading packages', - 'prompt' => 'HTTP Proxy Server Address', - 'group' => 'Internet Access', - ), - // File Locations - 'php_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_PHP_DIR, - 'doc' => 'directory where .php files are installed', - 'prompt' => 'PEAR directory', - 'group' => 'File Locations', - ), - 'ext_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_EXT_DIR, - 'doc' => 'directory where loadable extensions are installed', - 'prompt' => 'PHP extension directory', - 'group' => 'File Locations', - ), - 'doc_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_DOC_DIR, - 'doc' => 'directory where documentation is installed', - 'prompt' => 'PEAR documentation directory', - 'group' => 'File Locations', - ), - 'bin_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_BIN_DIR, - 'doc' => 'directory where executables are installed', - 'prompt' => 'PEAR executables directory', - 'group' => 'File Locations', - ), - 'data_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_DATA_DIR, - 'doc' => 'directory where data files are installed', - 'prompt' => 'PEAR data directory', - 'group' => 'File Locations (Advanced)', - ), - 'cfg_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_CFG_DIR, - 'doc' => 'directory where modifiable configuration files are installed', - 'prompt' => 'PEAR configuration file directory', - 'group' => 'File Locations (Advanced)', - ), - 'www_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_WWW_DIR, - 'doc' => 'directory where www frontend files (html/js) are installed', - 'prompt' => 'PEAR www files directory', - 'group' => 'File Locations (Advanced)', - ), - 'test_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_TEST_DIR, - 'doc' => 'directory where regression tests are installed', - 'prompt' => 'PEAR test directory', - 'group' => 'File Locations (Advanced)', - ), - 'cache_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_CACHE_DIR, - 'doc' => 'directory which is used for web service cache', - 'prompt' => 'PEAR Installer cache directory', - 'group' => 'File Locations (Advanced)', - ), - 'temp_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_TEMP_DIR, - 'doc' => 'directory which is used for all temp files', - 'prompt' => 'PEAR Installer temp directory', - 'group' => 'File Locations (Advanced)', - ), - 'download_dir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR, - 'doc' => 'directory which is used for all downloaded files', - 'prompt' => 'PEAR Installer download directory', - 'group' => 'File Locations (Advanced)', - ), - 'php_bin' => array( - 'type' => 'file', - 'default' => PEAR_CONFIG_DEFAULT_PHP_BIN, - 'doc' => 'PHP CLI/CGI binary for executing scripts', - 'prompt' => 'PHP CLI/CGI binary', - 'group' => 'File Locations (Advanced)', - ), - 'php_prefix' => array( - 'type' => 'string', - 'default' => '', - 'doc' => '--program-prefix for php_bin\'s ./configure, used for pecl installs', - 'prompt' => '--program-prefix passed to PHP\'s ./configure', - 'group' => 'File Locations (Advanced)', - ), - 'php_suffix' => array( - 'type' => 'string', - 'default' => '', - 'doc' => '--program-suffix for php_bin\'s ./configure, used for pecl installs', - 'prompt' => '--program-suffix passed to PHP\'s ./configure', - 'group' => 'File Locations (Advanced)', - ), - 'php_ini' => array( - 'type' => 'file', - 'default' => '', - 'doc' => 'location of php.ini in which to enable PECL extensions on install', - 'prompt' => 'php.ini location', - 'group' => 'File Locations (Advanced)', - ), - // Maintainers - 'username' => array( - 'type' => 'string', - 'default' => '', - 'doc' => '(maintainers) your PEAR account name', - 'prompt' => 'PEAR username (for maintainers)', - 'group' => 'Maintainers', - ), - 'password' => array( - 'type' => 'password', - 'default' => '', - 'doc' => '(maintainers) your PEAR account password', - 'prompt' => 'PEAR password (for maintainers)', - 'group' => 'Maintainers', - ), - // Advanced - 'verbose' => array( - 'type' => 'integer', - 'default' => PEAR_CONFIG_DEFAULT_VERBOSE, - 'doc' => 'verbosity level -0: really quiet -1: somewhat quiet -2: verbose -3: debug', - 'prompt' => 'Debug Log Level', - 'group' => 'Advanced', - ), - 'preferred_state' => array( - 'type' => 'set', - 'default' => PEAR_CONFIG_DEFAULT_PREFERRED_STATE, - 'doc' => 'the installer will prefer releases with this state when installing packages without a version or state specified', - 'valid_set' => array( - 'stable', 'beta', 'alpha', 'devel', 'snapshot'), - 'prompt' => 'Preferred Package State', - 'group' => 'Advanced', - ), - 'umask' => array( - 'type' => 'mask', - 'default' => PEAR_CONFIG_DEFAULT_UMASK, - 'doc' => 'umask used when creating files (Unix-like systems only)', - 'prompt' => 'Unix file mask', - 'group' => 'Advanced', - ), - 'cache_ttl' => array( - 'type' => 'integer', - 'default' => PEAR_CONFIG_DEFAULT_CACHE_TTL, - 'doc' => 'amount of secs where the local cache is used and not updated', - 'prompt' => 'Cache TimeToLive', - 'group' => 'Advanced', - ), - 'sig_type' => array( - 'type' => 'set', - 'default' => PEAR_CONFIG_DEFAULT_SIG_TYPE, - 'doc' => 'which package signature mechanism to use', - 'valid_set' => array('gpg'), - 'prompt' => 'Package Signature Type', - 'group' => 'Maintainers', - ), - 'sig_bin' => array( - 'type' => 'string', - 'default' => PEAR_CONFIG_DEFAULT_SIG_BIN, - 'doc' => 'which package signature mechanism to use', - 'prompt' => 'Signature Handling Program', - 'group' => 'Maintainers', - ), - 'sig_keyid' => array( - 'type' => 'string', - 'default' => '', - 'doc' => 'which key to use for signing with', - 'prompt' => 'Signature Key Id', - 'group' => 'Maintainers', - ), - 'sig_keydir' => array( - 'type' => 'directory', - 'default' => PEAR_CONFIG_DEFAULT_SIG_KEYDIR, - 'doc' => 'directory where signature keys are located', - 'prompt' => 'Signature Key Directory', - 'group' => 'Maintainers', - ), - // __channels is reserved - used for channel-specific configuration - ); + var $_downloadDir; + + /** + * @param PEAR_Frontend_* + * @param array + * @param PEAR_Config + */ + function PEAR_Downloader(&$ui, $options, &$config) + { + parent::PEAR_Common(); + $this->_options = $options; + $this->config = &$config; + $this->_preferredState = $this->config->get('preferred_state'); + $this->ui = &$ui; + if (!$this->_preferredState) { + // don't inadvertantly use a non-set preferred_state + $this->_preferredState = null; + } + + if (isset($this->_options['installroot'])) { + $this->config->setInstallRoot($this->_options['installroot']); + } + $this->_registry = &$config->getRegistry(); + + if (isset($this->_options['alldeps']) || isset($this->_options['onlyreqdeps'])) { + $this->_installed = $this->_registry->listAllPackages(); + foreach ($this->_installed as $key => $unused) { + if (!count($unused)) { + continue; + } + $strtolower = create_function('$a','return strtolower($a);'); + array_walk($this->_installed[$key], $strtolower); + } + } + } /** - * Constructor. - * - * @param string file to read user-defined options from - * @param string file to read system-wide defaults from - * @param bool determines whether a registry object "follows" - * the value of php_dir (is automatically created - * and moved when php_dir is changed) - * @param bool if true, fails if configuration files cannot be loaded - * - * @access public - * - * @see PEAR_Config::singleton + * Attempt to discover a channel's remote capabilities from + * its server name + * @param string + * @return boolean */ - function PEAR_Config($user_file = '', $system_file = '', $ftp_file = false, - $strict = true) + function discover($channel) { - $this->PEAR(); - PEAR_Installer_Role::initializeConfig($this); - $sl = DIRECTORY_SEPARATOR; - if (empty($user_file)) { - if (OS_WINDOWS) { - $user_file = PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini'; - } else { - $user_file = getenv('HOME') . $sl . '.pearrc'; + $this->log(1, 'Attempting to discover channel "' . $channel . '"...'); + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $callback = $this->ui ? array(&$this, '_downloadCallback') : null; + if (!class_exists('System')) { + require_once 'phar://install-pear-nozlib.phar/' . 'System.php'; + } + + $tmp = System::mktemp(array('-d')); + $a = $this->downloadHttp('http://' . $channel . '/channel.xml', $this->ui, $tmp, $callback, false); + PEAR::popErrorHandling(); + if (PEAR::isError($a)) { + // Attempt to fallback to https automatically. + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $this->log(1, 'Attempting fallback to https instead of http on channel "' . $channel . '"...'); + $a = $this->downloadHttp('https://' . $channel . '/channel.xml', $this->ui, $tmp, $callback, false); + PEAR::popErrorHandling(); + if (PEAR::isError($a)) { + return false; } } - if (empty($system_file)) { - $system_file = PEAR_CONFIG_SYSCONFDIR . $sl; - if (OS_WINDOWS) { - $system_file .= 'pearsys.ini'; - } else { - $system_file .= 'pear.conf'; + list($a, $lastmodified) = $a; + if (!class_exists('PEAR_ChannelFile')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/ChannelFile.php'; + } + + $b = new PEAR_ChannelFile; + if ($b->fromXmlFile($a)) { + unlink($a); + if ($this->config->get('auto_discover')) { + $this->_registry->addChannel($b, $lastmodified); + $alias = $b->getName(); + if ($b->getName() == $this->_registry->channelName($b->getAlias())) { + $alias = $b->getAlias(); + } + + $this->log(1, 'Auto-discovered channel "' . $channel . + '", alias "' . $alias . '", adding to registry'); } + + return true; } - $this->layers = array_keys($this->configuration); - $this->files['user'] = $user_file; - $this->files['system'] = $system_file; - if ($user_file && file_exists($user_file)) { - $this->pushErrorHandling(PEAR_ERROR_RETURN); - $this->readConfigFile($user_file, 'user', $strict); - $this->popErrorHandling(); - if ($this->_errorsFound > 0) { - return; + unlink($a); + return false; + } + + /** + * For simpler unit-testing + * @param PEAR_Downloader + * @return PEAR_Downloader_Package + */ + function &newDownloaderPackage(&$t) + { + if (!class_exists('PEAR_Downloader_Package')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Downloader/Package.php'; + } + $a = &new PEAR_Downloader_Package($t); + return $a; + } + + /** + * For simpler unit-testing + * @param PEAR_Config + * @param array + * @param array + * @param int + */ + function &getDependency2Object(&$c, $i, $p, $s) + { + if (!class_exists('PEAR_Dependency2')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Dependency2.php'; + } + $z = &new PEAR_Dependency2($c, $i, $p, $s); + return $z; + } + + function &download($params) + { + if (!count($params)) { + $a = array(); + return $a; + } + + if (!isset($this->_registry)) { + $this->_registry = &$this->config->getRegistry(); + } + + $channelschecked = array(); + // convert all parameters into PEAR_Downloader_Package objects + foreach ($params as $i => $param) { + $params[$i] = &$this->newDownloaderPackage($this); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $err = $params[$i]->initialize($param); + PEAR::staticPopErrorHandling(); + if (!$err) { + // skip parameters that were missed by preferred_state + continue; + } + + if (PEAR::isError($err)) { + if (!isset($this->_options['soft']) && $err->getMessage() !== '') { + $this->log(0, $err->getMessage()); + } + + $params[$i] = false; + if (is_object($param)) { + $param = $param->getChannel() . '/' . $param->getPackage(); + } + + if (!isset($this->_options['soft'])) { + $this->log(2, 'Package "' . $param . '" is not valid'); + } + + // Message logged above in a specific verbose mode, passing null to not show up on CLI + $this->pushError(null, PEAR_INSTALLER_SKIPPED); + } else { + do { + if ($params[$i] && $params[$i]->getType() == 'local') { + // bug #7090 skip channel.xml check for local packages + break; + } + + if ($params[$i] && !isset($channelschecked[$params[$i]->getChannel()]) && + !isset($this->_options['offline']) + ) { + $channelschecked[$params[$i]->getChannel()] = true; + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + if (!class_exists('System')) { + require_once 'phar://install-pear-nozlib.phar/' . 'System.php'; + } + + $curchannel = &$this->_registry->getChannel($params[$i]->getChannel()); + if (PEAR::isError($curchannel)) { + PEAR::staticPopErrorHandling(); + return $this->raiseError($curchannel); + } + + if (PEAR::isError($dir = $this->getDownloadDir())) { + PEAR::staticPopErrorHandling(); + break; + } + + $mirror = $this->config->get('preferred_mirror', null, $params[$i]->getChannel()); + $url = 'http://' . $mirror . '/channel.xml'; + $a = $this->downloadHttp($url, $this->ui, $dir, null, $curchannel->lastModified()); + + PEAR::staticPopErrorHandling(); + if (PEAR::isError($a) || !$a) { + // Attempt fallback to https automatically + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $a = $this->downloadHttp('https://' . $mirror . + '/channel.xml', $this->ui, $dir, null, $curchannel->lastModified()); + + PEAR::staticPopErrorHandling(); + if (PEAR::isError($a) || !$a) { + break; + } + } + $this->log(0, 'WARNING: channel "' . $params[$i]->getChannel() . '" has ' . + 'updated its protocols, use "' . PEAR_RUNTYPE . ' channel-update ' . $params[$i]->getChannel() . + '" to update'); + } + } while (false); + + if ($params[$i] && !isset($this->_options['downloadonly'])) { + if (isset($this->_options['packagingroot'])) { + $checkdir = $this->_prependPath( + $this->config->get('php_dir', null, $params[$i]->getChannel()), + $this->_options['packagingroot']); + } else { + $checkdir = $this->config->get('php_dir', + null, $params[$i]->getChannel()); + } + + while ($checkdir && $checkdir != '/' && !file_exists($checkdir)) { + $checkdir = dirname($checkdir); + } + + if ($checkdir == '.') { + $checkdir = '/'; + } + + if (!is_writeable($checkdir)) { + return PEAR::raiseError('Cannot install, php_dir for channel "' . + $params[$i]->getChannel() . '" is not writeable by the current user'); + } + } } } - if ($system_file && @file_exists($system_file)) { - $this->mergeConfigFile($system_file, false, 'system', $strict); - if ($this->_errorsFound > 0) { - return; + unset($channelschecked); + PEAR_Downloader_Package::removeDuplicates($params); + if (!count($params)) { + $a = array(); + return $a; + } + + if (!isset($this->_options['nodeps']) && !isset($this->_options['offline'])) { + $reverify = true; + while ($reverify) { + $reverify = false; + foreach ($params as $i => $param) { + //PHP Bug 40768 / PEAR Bug #10944 + //Nested foreaches fail in PHP 5.2.1 + key($params); + $ret = $params[$i]->detectDependencies($params); + if (PEAR::isError($ret)) { + $reverify = true; + $params[$i] = false; + PEAR_Downloader_Package::removeDuplicates($params); + if (!isset($this->_options['soft'])) { + $this->log(0, $ret->getMessage()); + } + continue 2; + } + } } + } + if (isset($this->_options['offline'])) { + $this->log(3, 'Skipping dependency download check, --offline specified'); } - if (!$ftp_file) { - $ftp_file = $this->get('remote_config'); + if (!count($params)) { + $a = array(); + return $a; } - if ($ftp_file && defined('PEAR_REMOTEINSTALL_OK')) { - $this->readFTPConfigFile($ftp_file); + while (PEAR_Downloader_Package::mergeDependencies($params)); + PEAR_Downloader_Package::removeDuplicates($params, true); + $errorparams = array(); + if (PEAR_Downloader_Package::detectStupidDuplicates($params, $errorparams)) { + if (count($errorparams)) { + foreach ($errorparams as $param) { + $name = $this->_registry->parsedPackageNameToString($param->getParsedPackage()); + $this->pushError('Duplicate package ' . $name . ' found', PEAR_INSTALLER_FAILED); + } + $a = array(); + return $a; + } } - foreach ($this->configuration_info as $key => $info) { - $this->configuration['default'][$key] = $info['default']; + PEAR_Downloader_Package::removeInstalled($params); + if (!count($params)) { + $this->pushError('No valid packages found', PEAR_INSTALLER_FAILED); + $a = array(); + return $a; } - $this->_registry['default'] = &new PEAR_Registry($this->configuration['default']['php_dir']); - $this->_registry['default']->setConfig($this, false); - $this->_regInitialized['default'] = false; - //$GLOBALS['_PEAR_Config_instance'] = &$this; - } + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $err = $this->analyzeDependencies($params); + PEAR::popErrorHandling(); + if (!count($params)) { + $this->pushError('No valid packages found', PEAR_INSTALLER_FAILED); + $a = array(); + return $a; + } - /** - * Return the default locations of user and system configuration files - * @static - */ - function getDefaultConfigFiles() - { - $sl = DIRECTORY_SEPARATOR; - if (OS_WINDOWS) { - return array( - 'user' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini', - 'system' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pearsys.ini' - ); + $ret = array(); + $newparams = array(); + if (isset($this->_options['pretend'])) { + return $params; } - return array( - 'user' => getenv('HOME') . $sl . '.pearrc', - 'system' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.conf' - ); - } + $somefailed = false; + foreach ($params as $i => $package) { + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $pf = &$params[$i]->download(); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($pf)) { + if (!isset($this->_options['soft'])) { + $this->log(1, $pf->getMessage()); + $this->log(0, 'Error: cannot download "' . + $this->_registry->parsedPackageNameToString($package->getParsedPackage(), + true) . + '"'); + } + $somefailed = true; + continue; + } - /** - * Static singleton method. If you want to keep only one instance - * of this class in use, this method will give you a reference to - * the last created PEAR_Config object if one exists, or create a - * new object. - * - * @param string (optional) file to read user-defined options from - * @param string (optional) file to read system-wide defaults from - * - * @return object an existing or new PEAR_Config instance - * - * @access public - * - * @see PEAR_Config::PEAR_Config - */ - function &singleton($user_file = '', $system_file = '', $strict = true) - { - if (is_object($GLOBALS['_PEAR_Config_instance'])) { - return $GLOBALS['_PEAR_Config_instance']; + $newparams[] = &$params[$i]; + $ret[] = array( + 'file' => $pf->getArchiveFile(), + 'info' => &$pf, + 'pkg' => $pf->getPackage() + ); } - $t_conf = &new PEAR_Config($user_file, $system_file, false, $strict); - if ($t_conf->_errorsFound > 0) { - return $t_conf->lastError; + if ($somefailed) { + // remove params that did not download successfully + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $err = $this->analyzeDependencies($newparams, true); + PEAR::popErrorHandling(); + if (!count($newparams)) { + $this->pushError('Download failed', PEAR_INSTALLER_FAILED); + $a = array(); + return $a; + } } - $GLOBALS['_PEAR_Config_instance'] = &$t_conf; - return $GLOBALS['_PEAR_Config_instance']; + $this->_downloadedPackages = $ret; + return $newparams; } /** - * Determine whether any configuration files have been detected, and whether a - * registry object can be retrieved from this configuration. - * @return bool - * @since PEAR 1.4.0a1 + * @param array all packages to be installed */ - function validConfiguration() + function analyzeDependencies(&$params, $force = false) { - if ($this->isDefinedLayer('user') || $this->isDefinedLayer('system')) { - return true; + $hasfailed = $failed = false; + if (isset($this->_options['downloadonly'])) { + return; } - return false; - } + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $redo = true; + $reset = false; + while ($redo) { + $redo = false; + foreach ($params as $i => $param) { + $deps = $param->getDeps(); + if (!$deps) { + $depchecker = &$this->getDependency2Object($this->config, $this->getOptions(), + $param->getParsedPackage(), PEAR_VALIDATE_DOWNLOADING); + $send = $param->getPackageFile(); + + $installcheck = $depchecker->validatePackage($send, $this, $params); + if (PEAR::isError($installcheck)) { + if (!isset($this->_options['soft'])) { + $this->log(0, $installcheck->getMessage()); + } + $hasfailed = true; + $params[$i] = false; + $reset = true; + $redo = true; + $failed = false; + PEAR_Downloader_Package::removeDuplicates($params); + continue 2; + } + continue; + } + + if (!$reset && $param->alreadyValidated() && !$force) { + continue; + } + + if (count($deps)) { + $depchecker = &$this->getDependency2Object($this->config, $this->getOptions(), + $param->getParsedPackage(), PEAR_VALIDATE_DOWNLOADING); + $send = $param->getPackageFile(); + if ($send === null) { + $send = $param->getDownloadURL(); + } + + $installcheck = $depchecker->validatePackage($send, $this, $params); + if (PEAR::isError($installcheck)) { + if (!isset($this->_options['soft'])) { + $this->log(0, $installcheck->getMessage()); + } + $hasfailed = true; + $params[$i] = false; + $reset = true; + $redo = true; + $failed = false; + PEAR_Downloader_Package::removeDuplicates($params); + continue 2; + } + + $failed = false; + if (isset($deps['required'])) { + foreach ($deps['required'] as $type => $dep) { + // note: Dependency2 will never return a PEAR_Error if ignore-errors + // is specified, so soft is needed to turn off logging + if (!isset($dep[0])) { + if (PEAR::isError($e = $depchecker->{"validate{$type}Dependency"}($dep, + true, $params))) { + $failed = true; + if (!isset($this->_options['soft'])) { + $this->log(0, $e->getMessage()); + } + } elseif (is_array($e) && !$param->alreadyValidated()) { + if (!isset($this->_options['soft'])) { + $this->log(0, $e[0]); + } + } + } else { + foreach ($dep as $d) { + if (PEAR::isError($e = + $depchecker->{"validate{$type}Dependency"}($d, + true, $params))) { + $failed = true; + if (!isset($this->_options['soft'])) { + $this->log(0, $e->getMessage()); + } + } elseif (is_array($e) && !$param->alreadyValidated()) { + if (!isset($this->_options['soft'])) { + $this->log(0, $e[0]); + } + } + } + } + } + + if (isset($deps['optional'])) { + foreach ($deps['optional'] as $type => $dep) { + if (!isset($dep[0])) { + if (PEAR::isError($e = + $depchecker->{"validate{$type}Dependency"}($dep, + false, $params))) { + $failed = true; + if (!isset($this->_options['soft'])) { + $this->log(0, $e->getMessage()); + } + } elseif (is_array($e) && !$param->alreadyValidated()) { + if (!isset($this->_options['soft'])) { + $this->log(0, $e[0]); + } + } + } else { + foreach ($dep as $d) { + if (PEAR::isError($e = + $depchecker->{"validate{$type}Dependency"}($d, + false, $params))) { + $failed = true; + if (!isset($this->_options['soft'])) { + $this->log(0, $e->getMessage()); + } + } elseif (is_array($e) && !$param->alreadyValidated()) { + if (!isset($this->_options['soft'])) { + $this->log(0, $e[0]); + } + } + } + } + } + } + + $groupname = $param->getGroup(); + if (isset($deps['group']) && $groupname) { + if (!isset($deps['group'][0])) { + $deps['group'] = array($deps['group']); + } - /** - * Reads configuration data from a file. All existing values in - * the config layer are discarded and replaced with data from the - * file. - * @param string file to read from, if NULL or not specified, the - * last-used file for the same layer (second param) is used - * @param string config layer to insert data into ('user' or 'system') - * @return bool TRUE on success or a PEAR error on failure - */ - function readConfigFile($file = null, $layer = 'user', $strict = true) - { - if (empty($this->files[$layer])) { - return $this->raiseError("unknown config layer `$layer'"); - } + $found = false; + foreach ($deps['group'] as $group) { + if ($group['attribs']['name'] == $groupname) { + $found = true; + break; + } + } - if ($file === null) { - $file = $this->files[$layer]; - } + if ($found) { + unset($group['attribs']); + foreach ($group as $type => $dep) { + if (!isset($dep[0])) { + if (PEAR::isError($e = + $depchecker->{"validate{$type}Dependency"}($dep, + false, $params))) { + $failed = true; + if (!isset($this->_options['soft'])) { + $this->log(0, $e->getMessage()); + } + } elseif (is_array($e) && !$param->alreadyValidated()) { + if (!isset($this->_options['soft'])) { + $this->log(0, $e[0]); + } + } + } else { + foreach ($dep as $d) { + if (PEAR::isError($e = + $depchecker->{"validate{$type}Dependency"}($d, + false, $params))) { + $failed = true; + if (!isset($this->_options['soft'])) { + $this->log(0, $e->getMessage()); + } + } elseif (is_array($e) && !$param->alreadyValidated()) { + if (!isset($this->_options['soft'])) { + $this->log(0, $e[0]); + } + } + } + } + } + } + } + } else { + foreach ($deps as $dep) { + if (PEAR::isError($e = $depchecker->validateDependency1($dep, $params))) { + $failed = true; + if (!isset($this->_options['soft'])) { + $this->log(0, $e->getMessage()); + } + } elseif (is_array($e) && !$param->alreadyValidated()) { + if (!isset($this->_options['soft'])) { + $this->log(0, $e[0]); + } + } + } + } + $params[$i]->setValidated(); + } - $data = $this->_readConfigDataFrom($file); - if (PEAR::isError($data)) { - if (!$strict) { - return true; + if ($failed) { + $hasfailed = true; + $params[$i] = false; + $reset = true; + $redo = true; + $failed = false; + PEAR_Downloader_Package::removeDuplicates($params); + continue 2; + } } - - $this->_errorsFound++; - $this->lastError = $data; - - return $data; } - - $this->files[$layer] = $file; - $this->_decodeInput($data); - $this->configuration[$layer] = $data; - $this->_setupChannels(); - if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) { - $this->_registry[$layer] = &new PEAR_Registry($phpdir); - $this->_registry[$layer]->setConfig($this, false); - $this->_regInitialized[$layer] = false; - } else { - unset($this->_registry[$layer]); + PEAR::staticPopErrorHandling(); + if ($hasfailed && (isset($this->_options['ignore-errors']) || + isset($this->_options['nodeps']))) { + // this is probably not needed, but just in case + if (!isset($this->_options['soft'])) { + $this->log(0, 'WARNING: dependencies failed'); + } } - return true; } /** - * @param string url to the remote config file, like ftp://www.example.com/pear/config.ini - * @return true|PEAR_Error + * Retrieve the directory that downloads will happen in + * @access private + * @return string */ - function readFTPConfigFile($path) + function getDownloadDir() { - do { // poor man's try - if (!class_exists('PEAR_FTP')) { - if (!class_exists('PEAR_Common')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Common.php'; - } - if (PEAR_Common::isIncludeable('PEAR/FTP.php')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/FTP.php'; - } - } - - if (!class_exists('PEAR_FTP')) { - return PEAR::raiseError('PEAR_RemoteInstaller must be installed to use remote config'); - } - - $this->_ftp = &new PEAR_FTP; - $this->_ftp->pushErrorHandling(PEAR_ERROR_RETURN); - $e = $this->_ftp->init($path); - if (PEAR::isError($e)) { - $this->_ftp->popErrorHandling(); - return $e; - } - - $tmp = System::mktemp('-d'); - PEAR_Common::addTempFile($tmp); - $e = $this->_ftp->get(basename($path), $tmp . DIRECTORY_SEPARATOR . - 'pear.ini', false, FTP_BINARY); - if (PEAR::isError($e)) { - $this->_ftp->popErrorHandling(); - return $e; + if (isset($this->_downloadDir)) { + return $this->_downloadDir; + } + $downloaddir = $this->config->get('download_dir'); + if (empty($downloaddir) || (is_dir($downloaddir) && !is_writable($downloaddir))) { + if (is_dir($downloaddir) && !is_writable($downloaddir)) { + $this->log(0, 'WARNING: configuration download directory "' . $downloaddir . + '" is not writeable. Change download_dir config variable to ' . + 'a writeable dir to avoid this warning'); } - - PEAR_Common::addTempFile($tmp . DIRECTORY_SEPARATOR . 'pear.ini'); - $this->_ftp->disconnect(); - $this->_ftp->popErrorHandling(); - $this->files['ftp'] = $tmp . DIRECTORY_SEPARATOR . 'pear.ini'; - $e = $this->readConfigFile(null, 'ftp'); - if (PEAR::isError($e)) { - return $e; + if (!class_exists('System')) { + require_once 'phar://install-pear-nozlib.phar/' . 'System.php'; } - - $fail = array(); - foreach ($this->configuration_info as $key => $val) { - if (in_array($this->getGroup($key), - array('File Locations', 'File Locations (Advanced)')) && - $this->getType($key) == 'directory') { - // any directory configs must be set for this to work - if (!isset($this->configuration['ftp'][$key])) { - $fail[] = $key; - } - } + if (PEAR::isError($downloaddir = System::mktemp('-d'))) { + return $downloaddir; } - - if (!count($fail)) { - return true; + $this->log(3, '+ tmp dir created at ' . $downloaddir); + } + if (!is_writable($downloaddir)) { + if (PEAR::isError(System::mkdir(array('-p', $downloaddir))) || + !is_writable($downloaddir)) { + return PEAR::raiseError('download directory "' . $downloaddir . + '" is not writeable. Change download_dir config variable to ' . + 'a writeable dir'); } - - $fail = '"' . implode('", "', $fail) . '"'; - unset($this->files['ftp']); - unset($this->configuration['ftp']); - return PEAR::raiseError('ERROR: Ftp configuration file must set all ' . - 'directory configuration variables. These variables were not set: ' . - $fail); - } while (false); // poor man's catch - unset($this->files['ftp']); - return PEAR::raiseError('no remote host specified'); + } + return $this->_downloadDir = $downloaddir; } - /** - * Reads the existing configurations and creates the _channels array from it - */ - function _setupChannels() + function setDownloadDir($dir) { - $set = array_flip(array_values($this->_channels)); - foreach ($this->configuration as $layer => $data) { - $i = 1000; - if (isset($data['__channels']) && is_array($data['__channels'])) { - foreach ($data['__channels'] as $channel => $info) { - $set[$channel] = $i++; - } + if (!@is_writable($dir)) { + if (PEAR::isError(System::mkdir(array('-p', $dir)))) { + return PEAR::raiseError('download directory "' . $dir . + '" is not writeable. Change download_dir config variable to ' . + 'a writeable dir'); } } - $this->_channels = array_values(array_flip($set)); - $this->setChannels($this->_channels); + $this->_downloadDir = $dir; } - function deleteChannel($channel) + function configSet($key, $value, $layer = 'user', $channel = false) { - $ch = strtolower($channel); - foreach ($this->configuration as $layer => $data) { - if (isset($data['__channels']) && isset($data['__channels'][$ch])) { - unset($this->configuration[$layer]['__channels'][$ch]); - } + $this->config->set($key, $value, $layer, $channel); + $this->_preferredState = $this->config->get('preferred_state', null, $channel); + if (!$this->_preferredState) { + // don't inadvertantly use a non-set preferred_state + $this->_preferredState = null; } - - $this->_channels = array_flip($this->_channels); - unset($this->_channels[$ch]); - $this->_channels = array_flip($this->_channels); } - /** - * Merges data into a config layer from a file. Does the same - * thing as readConfigFile, except it does not replace all - * existing values in the config layer. - * @param string file to read from - * @param bool whether to overwrite existing data (default TRUE) - * @param string config layer to insert data into ('user' or 'system') - * @param string if true, errors are returned if file opening fails - * @return bool TRUE on success or a PEAR error on failure - */ - function mergeConfigFile($file, $override = true, $layer = 'user', $strict = true) + function setOptions($options) { - if (empty($this->files[$layer])) { - return $this->raiseError("unknown config layer `$layer'"); - } - - if ($file === null) { - $file = $this->files[$layer]; - } - - $data = $this->_readConfigDataFrom($file); - if (PEAR::isError($data)) { - if (!$strict) { - return true; - } - - $this->_errorsFound++; - $this->lastError = $data; - - return $data; - } - - $this->_decodeInput($data); - if ($override) { - $this->configuration[$layer] = - PEAR_Config::arrayMergeRecursive($this->configuration[$layer], $data); - } else { - $this->configuration[$layer] = - PEAR_Config::arrayMergeRecursive($data, $this->configuration[$layer]); - } + $this->_options = $options; + } - $this->_setupChannels(); - if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) { - $this->_registry[$layer] = &new PEAR_Registry($phpdir); - $this->_registry[$layer]->setConfig($this, false); - $this->_regInitialized[$layer] = false; - } else { - unset($this->_registry[$layer]); - } - return true; + // }}} + // {{{ setOptions() + function getOptions() + { + return $this->_options; } /** - * @param array - * @param array - * @return array - * @static + * For simpler unit-testing + * @param PEAR_Config + * @param int + * @param string */ - function arrayMergeRecursive($arr2, $arr1) + function &getPackagefileObject(&$c, $d, $t = false) { - $ret = array(); - foreach ($arr2 as $key => $data) { - if (!isset($arr1[$key])) { - $ret[$key] = $data; - unset($arr1[$key]); - continue; - } - if (is_array($data)) { - if (!is_array($arr1[$key])) { - $ret[$key] = $arr1[$key]; - unset($arr1[$key]); - continue; - } - $ret[$key] = PEAR_Config::arrayMergeRecursive($arr1[$key], $arr2[$key]); - unset($arr1[$key]); - } + if (!class_exists('PEAR_PackageFile')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile.php'; } - - return array_merge($ret, $arr1); + $a = &new PEAR_PackageFile($c, $d, $t); + return $a; } /** - * Writes data into a config layer from a file. - * - * @param string|null file to read from, or null for default - * @param string config layer to insert data into ('user' or - * 'system') - * @param string|null data to write to config file or null for internal data [DEPRECATED] - * @return bool TRUE on success or a PEAR error on failure + * @param array output of {@link parsePackageName()} + * @access private */ - function writeConfigFile($file = null, $layer = 'user', $data = null) + function _getPackageDownloadUrl($parr) { - $this->_lazyChannelSetup($layer); - if ($layer == 'both' || $layer == 'all') { - foreach ($this->files as $type => $file) { - $err = $this->writeConfigFile($file, $type, $data); - if (PEAR::isError($err)) { - return $err; + $curchannel = $this->config->get('default_channel'); + $this->configSet('default_channel', $parr['channel']); + // getDownloadURL returns an array. On error, it only contains information + // on the latest release as array(version, info). On success it contains + // array(version, info, download url string) + $state = isset($parr['state']) ? $parr['state'] : $this->config->get('preferred_state'); + if (!$this->_registry->channelExists($parr['channel'])) { + do { + if ($this->config->get('auto_discover') && $this->discover($parr['channel'])) { + break; } - } - return true; + + $this->configSet('default_channel', $curchannel); + return PEAR::raiseError('Unknown remote channel: ' . $parr['channel']); + } while (false); } - if (empty($this->files[$layer])) { - return $this->raiseError("unknown config file type `$layer'"); + $chan = &$this->_registry->getChannel($parr['channel']); + if (PEAR::isError($chan)) { + return $chan; } - if ($file === null) { - $file = $this->files[$layer]; + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $version = $this->_registry->packageInfo($parr['package'], 'version', $parr['channel']); + $stability = $this->_registry->packageInfo($parr['package'], 'stability', $parr['channel']); + // package is installed - use the installed release stability level + if (!isset($parr['state']) && $stability !== null) { + $state = $stability['release']; } + PEAR::staticPopErrorHandling(); + $base2 = false; - $data = ($data === null) ? $this->configuration[$layer] : $data; - $this->_encodeOutput($data); - $opt = array('-p', dirname($file)); - if (!@System::mkDir($opt)) { - return $this->raiseError("could not create directory: " . dirname($file)); + $preferred_mirror = $this->config->get('preferred_mirror'); + if (!$chan->supportsREST($preferred_mirror) || + ( + !($base2 = $chan->getBaseURL('REST1.3', $preferred_mirror)) + && + !($base = $chan->getBaseURL('REST1.0', $preferred_mirror)) + ) + ) { + return $this->raiseError($parr['channel'] . ' is using a unsupported protocol - This should never happen.'); } - if (file_exists($file) && is_file($file) && !is_writeable($file)) { - return $this->raiseError("no write access to $file!"); + if ($base2) { + $rest = &$this->config->getREST('1.3', $this->_options); + $base = $base2; + } else { + $rest = &$this->config->getREST('1.0', $this->_options); } - $fp = @fopen($file, "w"); - if (!$fp) { - return $this->raiseError("PEAR_Config::writeConfigFile fopen('$file','w') failed ($php_errormsg)"); + $downloadVersion = false; + if (!isset($parr['version']) && !isset($parr['state']) && $version + && !PEAR::isError($version) + && !isset($this->_options['downloadonly']) + ) { + $downloadVersion = $version; } - $contents = "#PEAR_Config 0.9\n" . serialize($data); - if (!@fwrite($fp, $contents)) { - return $this->raiseError("PEAR_Config::writeConfigFile: fwrite failed ($php_errormsg)"); + $url = $rest->getDownloadURL($base, $parr, $state, $downloadVersion, $chan->getName()); + if (PEAR::isError($url)) { + $this->configSet('default_channel', $curchannel); + return $url; } - return true; - } - /** - * Reads configuration data from a file and returns the parsed data - * in an array. - * - * @param string file to read from - * @return array configuration data or a PEAR error on failure - * @access private - */ - function _readConfigDataFrom($file) - { - $fp = false; - if (file_exists($file)) { - $fp = @fopen($file, "r"); + if ($parr['channel'] != $curchannel) { + $this->configSet('default_channel', $curchannel); } - if (!$fp) { - return $this->raiseError("PEAR_Config::readConfigFile fopen('$file','r') failed"); + if (!is_array($url)) { + return $url; } - $size = filesize($file); - $rt = get_magic_quotes_runtime(); - set_magic_quotes_runtime(0); - fclose($fp); - $contents = file_get_contents($file); - if (empty($contents)) { - return $this->raiseError('Configuration file "' . $file . '" is empty'); + $url['raw'] = false; // no checking is necessary for REST + if (!is_array($url['info'])) { + return PEAR::raiseError('Invalid remote dependencies retrieved from REST - ' . + 'this should never happen'); } - set_magic_quotes_runtime($rt); + if (!isset($this->_options['force']) && + !isset($this->_options['downloadonly']) && + $version && + !PEAR::isError($version) && + !isset($parr['group']) + ) { + if (version_compare($version, $url['version'], '=')) { + return PEAR::raiseError($this->_registry->parsedPackageNameToString( + $parr, true) . ' is already installed and is the same as the ' . + 'released version ' . $url['version'], -976); + } - $version = false; - if (preg_match('/^#PEAR_Config\s+(\S+)\s+/si', $contents, $matches)) { - $version = $matches[1]; - $contents = substr($contents, strlen($matches[0])); - } else { - // Museum config file - if (substr($contents,0,2) == 'a:') { - $version = '0.1'; + if (version_compare($version, $url['version'], '>')) { + return PEAR::raiseError($this->_registry->parsedPackageNameToString( + $parr, true) . ' is already installed and is newer than detected ' . + 'released version ' . $url['version'], -976); } } - if ($version && version_compare("$version", '1', '<')) { - // no '@', it is possible that unserialize - // raises a notice but it seems to block IO to - // STDOUT if a '@' is used and a notice is raise - $data = unserialize($contents); - - if (!is_array($data) && !$data) { - if ($contents == serialize(false)) { - $data = array(); - } else { - $err = $this->raiseError("PEAR_Config: bad data in $file"); - return $err; - } + if (isset($url['info']['required']) || $url['compatible']) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/v2.php'; + $pf = new PEAR_PackageFile_v2; + $pf->setRawChannel($parr['channel']); + if ($url['compatible']) { + $pf->setRawCompatible($url['compatible']); } - if (!is_array($data)) { - if (strlen(trim($contents)) > 0) { - $error = "PEAR_Config: bad data in $file"; - $err = $this->raiseError($error); - return $err; - } + } else { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/v1.php'; + $pf = new PEAR_PackageFile_v1; + } - $data = array(); - } - // add parsing of newer formats here... + $pf->setRawPackage($url['package']); + $pf->setDeps($url['info']); + if ($url['compatible']) { + $pf->setCompatible($url['compatible']); + } + + $pf->setRawState($url['stability']); + $url['info'] = &$pf; + if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) { + $ext = '.tar'; } else { - $err = $this->raiseError("$file: unknown version `$version'"); - return $err; + $ext = '.tgz'; } - return $data; - } + if (is_array($url) && isset($url['url'])) { + $url['url'] .= $ext; + } - /** - * Gets the file used for storing the config for a layer - * - * @param string $layer 'user' or 'system' - */ - function getConfFile($layer) - { - return $this->files[$layer]; + return $url; } /** - * @param string Configuration class name, used for detecting duplicate calls - * @param array information on a role as parsed from its xml file - * @return true|PEAR_Error + * @param array dependency array * @access private */ - function _addConfigVars($class, $vars) + function _getDepPackageDownloadUrl($dep, $parr) { - static $called = array(); - if (isset($called[$class])) { - return; - } + $xsdversion = isset($dep['rel']) ? '1.0' : '2.0'; + $curchannel = $this->config->get('default_channel'); + if (isset($dep['uri'])) { + $xsdversion = '2.0'; + $chan = &$this->_registry->getChannel('__uri'); + if (PEAR::isError($chan)) { + return $chan; + } - $called[$class] = 1; - if (count($vars) > 3) { - return $this->raiseError('Roles can only define 3 new config variables or less'); - } + $version = $this->_registry->packageInfo($dep['name'], 'version', '__uri'); + $this->configSet('default_channel', '__uri'); + } else { + if (isset($dep['channel'])) { + $remotechannel = $dep['channel']; + } else { + $remotechannel = 'pear.php.net'; + } - foreach ($vars as $name => $var) { - if (!is_array($var)) { - return $this->raiseError('Configuration information must be an array'); + if (!$this->_registry->channelExists($remotechannel)) { + do { + if ($this->config->get('auto_discover')) { + if ($this->discover($remotechannel)) { + break; + } + } + return PEAR::raiseError('Unknown remote channel: ' . $remotechannel); + } while (false); } - if (!isset($var['type'])) { - return $this->raiseError('Configuration information must contain a type'); - } elseif (!in_array($var['type'], - array('string', 'mask', 'password', 'directory', 'file', 'set'))) { - return $this->raiseError( - 'Configuration type must be one of directory, file, string, ' . - 'mask, set, or password'); + $chan = &$this->_registry->getChannel($remotechannel); + if (PEAR::isError($chan)) { + return $chan; } - if (!isset($var['default'])) { - return $this->raiseError( - 'Configuration information must contain a default value ("default" index)'); + + $version = $this->_registry->packageInfo($dep['name'], 'version', $remotechannel); + $this->configSet('default_channel', $remotechannel); + } + + $state = isset($parr['state']) ? $parr['state'] : $this->config->get('preferred_state'); + if (isset($parr['state']) && isset($parr['version'])) { + unset($parr['state']); + } + + if (isset($dep['uri'])) { + $info = &$this->newDownloaderPackage($this); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $err = $info->initialize($dep); + PEAR::staticPopErrorHandling(); + if (!$err) { + // skip parameters that were missed by preferred_state + return PEAR::raiseError('Cannot initialize dependency'); } - if (is_array($var['default'])) { - $real_default = ''; - foreach ($var['default'] as $config_var => $val) { - if (strpos($config_var, 'text') === 0) { - $real_default .= $val; - } elseif (strpos($config_var, 'constant') === 0) { - if (!defined($val)) { - return $this->raiseError( - 'Unknown constant "' . $val . '" requested in ' . - 'default value for configuration variable "' . - $name . '"'); - } + if (PEAR::isError($err)) { + if (!isset($this->_options['soft'])) { + $this->log(0, $err->getMessage()); + } - $real_default .= constant($val); - } elseif (isset($this->configuration_info[$config_var])) { - $real_default .= - $this->configuration_info[$config_var]['default']; - } else { - return $this->raiseError( - 'Unknown request for "' . $config_var . '" value in ' . - 'default value for configuration variable "' . - $name . '"'); - } + if (is_object($info)) { + $param = $info->getChannel() . '/' . $info->getPackage(); } - $var['default'] = $real_default; + return PEAR::raiseError('Package "' . $param . '" is not valid'); + } + return $info; + } elseif ($chan->supportsREST($this->config->get('preferred_mirror')) + && $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror')) + ) { + $rest = &$this->config->getREST('1.0', $this->_options); + $url = $rest->getDepDownloadURL($base, $xsdversion, $dep, $parr, + $state, $version, $chan->getName()); + if (PEAR::isError($url)) { + return $url; } - if ($var['type'] == 'integer') { - $var['default'] = (integer) $var['default']; + if ($parr['channel'] != $curchannel) { + $this->configSet('default_channel', $curchannel); } - if (!isset($var['doc'])) { - return $this->raiseError( - 'Configuration information must contain a summary ("doc" index)'); + if (!is_array($url)) { + return $url; } - if (!isset($var['prompt'])) { - return $this->raiseError( - 'Configuration information must contain a simple prompt ("prompt" index)'); + $url['raw'] = false; // no checking is necessary for REST + if (!is_array($url['info'])) { + return PEAR::raiseError('Invalid remote dependencies retrieved from REST - ' . + 'this should never happen'); } - if (!isset($var['group'])) { - return $this->raiseError( - 'Configuration information must contain a simple group ("group" index)'); + if (isset($url['info']['required'])) { + if (!class_exists('PEAR_PackageFile_v2')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/v2.php'; + } + $pf = new PEAR_PackageFile_v2; + $pf->setRawChannel($remotechannel); + } else { + if (!class_exists('PEAR_PackageFile_v1')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/v1.php'; + } + $pf = new PEAR_PackageFile_v1; + + } + $pf->setRawPackage($url['package']); + $pf->setDeps($url['info']); + if ($url['compatible']) { + $pf->setCompatible($url['compatible']); } - if (isset($this->configuration_info[$name])) { - return $this->raiseError('Configuration variable "' . $name . - '" already exists'); + $pf->setRawState($url['stability']); + $url['info'] = &$pf; + if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) { + $ext = '.tar'; + } else { + $ext = '.tgz'; } - $this->configuration_info[$name] = $var; - // fix bug #7351: setting custom config variable in a channel fails - $this->_channelConfigInfo[] = $name; + if (is_array($url) && isset($url['url'])) { + $url['url'] .= $ext; + } + + return $url; } - return true; + return $this->raiseError($parr['channel'] . ' is using a unsupported protocol - This should never happen.'); } /** - * Encodes/scrambles configuration data before writing to files. - * Currently, 'password' values will be base64-encoded as to avoid - * that people spot cleartext passwords by accident. - * - * @param array (reference) array to encode values in - * @return bool TRUE on success - * @access private + * @deprecated in favor of _getPackageDownloadUrl */ - function _encodeOutput(&$data) + function getPackageDownloadUrl($package, $version = null, $channel = false) { - foreach ($data as $key => $value) { - if ($key == '__channels') { - foreach ($data['__channels'] as $channel => $blah) { - $this->_encodeOutput($data['__channels'][$channel]); - } - } - - if (!isset($this->configuration_info[$key])) { - continue; - } - - $type = $this->configuration_info[$key]['type']; - switch ($type) { - // we base64-encode passwords so they are at least - // not shown in plain by accident - case 'password': { - $data[$key] = base64_encode($data[$key]); - break; - } - case 'mask': { - $data[$key] = octdec($data[$key]); - break; - } + if ($version) { + $package .= "-$version"; + } + if ($this === null || $this->_registry === null) { + $package = "http://pear.php.net/get/$package"; + } else { + $chan = $this->_registry->getChannel($channel); + if (PEAR::isError($chan)) { + return ''; } + $package = "http://" . $chan->getServer() . "/get/$package"; } - - return true; + if (!extension_loaded("zlib")) { + $package .= '?uncompress=yes'; + } + return $package; } /** - * Decodes/unscrambles configuration data after reading from files. - * - * @param array (reference) array to encode values in - * @return bool TRUE on success - * @access private + * Retrieve a list of downloaded packages after a call to {@link download()}. * - * @see PEAR_Config::_encodeOutput + * Also resets the list of downloaded packages. + * @return array */ - function _decodeInput(&$data) + function getDownloadedPackages() { - if (!is_array($data)) { - return true; - } + $ret = $this->_downloadedPackages; + $this->_downloadedPackages = array(); + $this->_toDownload = array(); + return $ret; + } - foreach ($data as $key => $value) { - if ($key == '__channels') { - foreach ($data['__channels'] as $channel => $blah) { - $this->_decodeInput($data['__channels'][$channel]); + function _downloadCallback($msg, $params = null) + { + switch ($msg) { + case 'saveas': + $this->log(1, "downloading $params ..."); + break; + case 'done': + $this->log(1, '...done: ' . number_format($params, 0, '', ',') . ' bytes'); + break; + case 'bytesread': + static $bytes; + if (empty($bytes)) { + $bytes = 0; } - } - - if (!isset($this->configuration_info[$key])) { - continue; - } - - $type = $this->configuration_info[$key]['type']; - switch ($type) { - case 'password': { - $data[$key] = base64_decode($data[$key]); - break; + if (!($bytes % 10240)) { + $this->log(1, '.', false); } - case 'mask': { - $data[$key] = decoct($data[$key]); - break; + $bytes += $params; + break; + case 'start': + if($params[1] == -1) { + $length = "Unknown size"; + } else { + $length = number_format($params[1], 0, '', ',')." bytes"; } - } + $this->log(1, "Starting to download {$params[0]} ($length)"); + break; } - - return true; + if (method_exists($this->ui, '_downloadCallback')) + $this->ui->_downloadCallback($msg, $params); } - /** - * Retrieve the default channel. - * - * On startup, channels are not initialized, so if the default channel is not - * pear.php.net, then initialize the config. - * @param string registry layer - * @return string|false - */ - function getDefaultChannel($layer = null) + function _prependPath($path, $prepend) { - $ret = false; - if ($layer === null) { - foreach ($this->layers as $layer) { - if (isset($this->configuration[$layer]['default_channel'])) { - $ret = $this->configuration[$layer]['default_channel']; - break; + if (strlen($prepend) > 0) { + if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) { + if (preg_match('/^[a-z]:/i', $prepend)) { + $prepend = substr($prepend, 2); + } elseif ($prepend{0} != '\\') { + $prepend = "\\$prepend"; } + $path = substr($path, 0, 2) . $prepend . substr($path, 2); + } else { + $path = $prepend . $path; } - } elseif (isset($this->configuration[$layer]['default_channel'])) { - $ret = $this->configuration[$layer]['default_channel']; - } - - if ($ret == 'pear.php.net' && defined('PEAR_RUNTYPE') && PEAR_RUNTYPE == 'pecl') { - $ret = 'pecl.php.net'; } + return $path; + } - if ($ret) { - if ($ret != 'pear.php.net') { - $this->_lazyChannelSetup(); - } + /** + * @param string + * @param integer + */ + function pushError($errmsg, $code = -1) + { + array_push($this->_errorStack, array($errmsg, $code)); + } - return $ret; + function getErrorMsgs() + { + $msgs = array(); + $errs = $this->_errorStack; + foreach ($errs as $err) { + $msgs[] = $err[0]; } - - return PEAR_CONFIG_DEFAULT_CHANNEL; + $this->_errorStack = array(); + return $msgs; } /** - * Returns a configuration value, prioritizing layers as per the - * layers property. + * for BC * - * @param string config key - * @return mixed the config value, or NULL if not found - * @access public + * @deprecated */ - function get($key, $layer = null, $channel = false) + function sortPkgDeps(&$packages, $uninstall = false) { - if (!isset($this->configuration_info[$key])) { - return null; - } + $uninstall ? + $this->sortPackagesForUninstall($packages) : + $this->sortPackagesForInstall($packages); + } - if ($key == '__channels') { - return null; + /** + * Sort a list of arrays of array(downloaded packagefilename) by dependency. + * + * This uses the topological sort method from graph theory, and the + * Structures_Graph package to properly sort dependencies for installation. + * @param array an array of downloaded PEAR_Downloader_Packages + * @return array array of array(packagefilename, package.xml contents) + */ + function sortPackagesForInstall(&$packages) + { + require_once 'phar://install-pear-nozlib.phar/' . 'Structures/Graph.php'; + require_once 'phar://install-pear-nozlib.phar/' . 'Structures/Graph/Node.php'; + require_once 'phar://install-pear-nozlib.phar/' . 'Structures/Graph/Manipulator/TopologicalSorter.php'; + $depgraph = new Structures_Graph(true); + $nodes = array(); + $reg = &$this->config->getRegistry(); + foreach ($packages as $i => $package) { + $pname = $reg->parsedPackageNameToString( + array( + 'channel' => $package->getChannel(), + 'package' => strtolower($package->getPackage()), + )); + $nodes[$pname] = new Structures_Graph_Node; + $nodes[$pname]->setData($packages[$i]); + $depgraph->addNode($nodes[$pname]); } - if ($key == 'default_channel') { - return $this->getDefaultChannel($layer); - } + $deplinks = array(); + foreach ($nodes as $package => $node) { + $pf = &$node->getData(); + $pdeps = $pf->getDeps(true); + if (!$pdeps) { + continue; + } - if (!$channel) { - $channel = $this->getDefaultChannel(); - } elseif ($channel != 'pear.php.net') { - $this->_lazyChannelSetup(); - } - $channel = strtolower($channel); + if ($pf->getPackagexmlVersion() == '1.0') { + foreach ($pdeps as $dep) { + if ($dep['type'] != 'pkg' || + (isset($dep['optional']) && $dep['optional'] == 'yes')) { + continue; + } - $test = (in_array($key, $this->_channelConfigInfo)) ? - $this->_getChannelValue($key, $layer, $channel) : - null; - if ($test !== null) { - if ($this->_installRoot) { - if (in_array($this->getGroup($key), - array('File Locations', 'File Locations (Advanced)')) && - $this->getType($key) == 'directory') { - return $this->_prependPath($test, $this->_installRoot); - } - } - return $test; - } + $dname = $reg->parsedPackageNameToString( + array( + 'channel' => 'pear.php.net', + 'package' => strtolower($dep['name']), + )); - if ($layer === null) { - foreach ($this->layers as $layer) { - if (isset($this->configuration[$layer][$key])) { - $test = $this->configuration[$layer][$key]; - if ($this->_installRoot) { - if (in_array($this->getGroup($key), - array('File Locations', 'File Locations (Advanced)')) && - $this->getType($key) == 'directory') { - return $this->_prependPath($test, $this->_installRoot); + if (isset($nodes[$dname])) { + if (!isset($deplinks[$dname])) { + $deplinks[$dname] = array(); } + + $deplinks[$dname][$package] = 1; + // dependency is in installed packages + continue; } - if ($key == 'preferred_mirror') { - $reg = &$this->getRegistry(); - if (is_object($reg)) { - $chan = &$reg->getChannel($channel); - if (PEAR::isError($chan)) { - return $channel; - } + $dname = $reg->parsedPackageNameToString( + array( + 'channel' => 'pecl.php.net', + 'package' => strtolower($dep['name']), + )); - if (!$chan->getMirror($test) && $chan->getName() != $test) { - return $channel; // mirror does not exist - } + if (isset($nodes[$dname])) { + if (!isset($deplinks[$dname])) { + $deplinks[$dname] = array(); } + + $deplinks[$dname][$package] = 1; + // dependency is in installed packages + continue; } - return $test; } - } - } elseif (isset($this->configuration[$layer][$key])) { - $test = $this->configuration[$layer][$key]; - if ($this->_installRoot) { - if (in_array($this->getGroup($key), - array('File Locations', 'File Locations (Advanced)')) && - $this->getType($key) == 'directory') { - return $this->_prependPath($test, $this->_installRoot); + } else { + // the only ordering we care about is: + // 1) subpackages must be installed before packages that depend on them + // 2) required deps must be installed before packages that depend on them + if (isset($pdeps['required']['subpackage'])) { + $t = $pdeps['required']['subpackage']; + if (!isset($t[0])) { + $t = array($t); + } + + $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); } - } - if ($key == 'preferred_mirror') { - $reg = &$this->getRegistry(); - if (is_object($reg)) { - $chan = &$reg->getChannel($channel); - if (PEAR::isError($chan)) { - return $channel; + if (isset($pdeps['group'])) { + if (!isset($pdeps['group'][0])) { + $pdeps['group'] = array($pdeps['group']); } - if (!$chan->getMirror($test) && $chan->getName() != $test) { - return $channel; // mirror does not exist + foreach ($pdeps['group'] as $group) { + if (isset($group['subpackage'])) { + $t = $group['subpackage']; + if (!isset($t[0])) { + $t = array($t); + } + + $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); + } } } - } - return $test; - } + if (isset($pdeps['optional']['subpackage'])) { + $t = $pdeps['optional']['subpackage']; + if (!isset($t[0])) { + $t = array($t); + } - return null; - } + $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); + } - /** - * Returns a channel-specific configuration value, prioritizing layers as per the - * layers property. - * - * @param string config key - * @return mixed the config value, or NULL if not found - * @access private - */ - function _getChannelValue($key, $layer, $channel) - { - if ($key == '__channels' || $channel == 'pear.php.net') { - return null; - } + if (isset($pdeps['required']['package'])) { + $t = $pdeps['required']['package']; + if (!isset($t[0])) { + $t = array($t); + } - $ret = null; - if ($layer === null) { - foreach ($this->layers as $ilayer) { - if (isset($this->configuration[$ilayer]['__channels'][$channel][$key])) { - $ret = $this->configuration[$ilayer]['__channels'][$channel][$key]; - break; + $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); } - } - } elseif (isset($this->configuration[$layer]['__channels'][$channel][$key])) { - $ret = $this->configuration[$layer]['__channels'][$channel][$key]; - } - - if ($key != 'preferred_mirror') { - return $ret; - } + if (isset($pdeps['group'])) { + if (!isset($pdeps['group'][0])) { + $pdeps['group'] = array($pdeps['group']); + } - if ($ret !== null) { - $reg = &$this->getRegistry($layer); - if (is_object($reg)) { - $chan = &$reg->getChannel($channel); - if (PEAR::isError($chan)) { - return $channel; - } + foreach ($pdeps['group'] as $group) { + if (isset($group['package'])) { + $t = $group['package']; + if (!isset($t[0])) { + $t = array($t); + } - if (!$chan->getMirror($ret) && $chan->getName() != $ret) { - return $channel; // mirror does not exist + $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); + } + } } } + } - return $ret; + $this->_detectDepCycle($deplinks); + foreach ($deplinks as $dependent => $parents) { + foreach ($parents as $parent => $unused) { + $nodes[$dependent]->connectTo($nodes[$parent]); + } } - if ($channel != $this->getDefaultChannel($layer)) { - return $channel; // we must use the channel name as the preferred mirror - // if the user has not chosen an alternate + $installOrder = Structures_Graph_Manipulator_TopologicalSorter::sort($depgraph); + $ret = array(); + for ($i = 0, $count = count($installOrder); $i < $count; $i++) { + foreach ($installOrder[$i] as $index => $sortedpackage) { + $data = &$installOrder[$i][$index]->getData(); + $ret[] = &$nodes[$reg->parsedPackageNameToString( + array( + 'channel' => $data->getChannel(), + 'package' => strtolower($data->getPackage()), + ))]->getData(); + } } - return $this->getDefaultChannel($layer); + $packages = $ret; + return; } /** - * Set a config value in a specific layer (defaults to 'user'). - * Enforces the types defined in the configuration_info array. An - * integer config variable will be cast to int, and a set config - * variable will be validated against its legal values. + * Detect recursive links between dependencies and break the cycles * - * @param string config key - * @param string config value - * @param string (optional) config layer - * @param string channel to set this value for, or null for global value - * @return bool TRUE on success, FALSE on failure + * @param array + * @access private */ - function set($key, $value, $layer = 'user', $channel = false) + function _detectDepCycle(&$deplinks) { - if ($key == '__channels') { - return false; + do { + $keepgoing = false; + foreach ($deplinks as $dep => $parents) { + foreach ($parents as $parent => $unused) { + // reset the parent cycle detector + $this->_testCycle(null, null, null); + if ($this->_testCycle($dep, $deplinks, $parent)) { + $keepgoing = true; + unset($deplinks[$dep][$parent]); + if (count($deplinks[$dep]) == 0) { + unset($deplinks[$dep]); + } + + continue 3; + } + } + } + } while ($keepgoing); + } + + function _testCycle($test, $deplinks, $dep) + { + static $visited = array(); + if ($test === null) { + $visited = array(); + return; } - if (!isset($this->configuration[$layer])) { + // this happens when a parent has a dep cycle on another dependency + // but the child is not part of the cycle + if (isset($visited[$dep])) { return false; } - if ($key == 'default_channel') { - // can only set this value globally - $channel = 'pear.php.net'; - if ($value != 'pear.php.net') { - $this->_lazyChannelSetup($layer); - } + $visited[$dep] = 1; + if ($test == $dep) { + return true; } - if ($key == 'preferred_mirror') { - if ($channel == '__uri') { - return false; // can't set the __uri pseudo-channel's mirror - } - - $reg = &$this->getRegistry($layer); - if (is_object($reg)) { - $chan = &$reg->getChannel($channel ? $channel : 'pear.php.net'); - if (PEAR::isError($chan)) { - return false; - } - - if (!$chan->getMirror($value) && $chan->getName() != $value) { - return false; // mirror does not exist - } + if (isset($deplinks[$dep])) { + if (in_array($test, array_keys($deplinks[$dep]), true)) { + return true; } - } - - if (!isset($this->configuration_info[$key])) { - return false; - } - extract($this->configuration_info[$key]); - switch ($type) { - case 'integer': - $value = (int)$value; - break; - case 'set': { - // If a valid_set is specified, require the value to - // be in the set. If there is no valid_set, accept - // any value. - if ($valid_set) { - reset($valid_set); - if ((key($valid_set) === 0 && !in_array($value, $valid_set)) || - (key($valid_set) !== 0 && empty($valid_set[$value]))) - { - return false; - } + foreach ($deplinks[$dep] as $parent => $unused) { + if ($this->_testCycle($test, $deplinks, $parent)) { + return true; } - break; } } - if (!$channel) { - $channel = $this->get('default_channel', null, 'pear.php.net'); - } + return false; + } - if (!in_array($channel, $this->_channels)) { - $this->_lazyChannelSetup($layer); - $reg = &$this->getRegistry($layer); - if ($reg) { - $channel = $reg->channelName($channel); - } + /** + * Set up the dependency for installation parsing + * + * @param array $t dependency information + * @param PEAR_Registry $reg + * @param array $deplinks list of dependency links already established + * @param array $nodes all existing package nodes + * @param string $package parent package name + * @access private + */ + function _setupGraph($t, $reg, &$deplinks, &$nodes, $package) + { + foreach ($t as $dep) { + $depchannel = !isset($dep['channel']) ? '__uri': $dep['channel']; + $dname = $reg->parsedPackageNameToString( + array( + 'channel' => $depchannel, + 'package' => strtolower($dep['name']), + )); - if (!in_array($channel, $this->_channels)) { - return false; + if (isset($nodes[$dname])) { + if (!isset($deplinks[$dname])) { + $deplinks[$dname] = array(); + } + $deplinks[$dname][$package] = 1; } } + } - if ($channel != 'pear.php.net') { - if (in_array($key, $this->_channelConfigInfo)) { - $this->configuration[$layer]['__channels'][$channel][$key] = $value; - return true; - } + function _dependsOn($a, $b) + { + return $this->_checkDepTree(strtolower($a->getChannel()), strtolower($a->getPackage()), $b); + } + function _checkDepTree($channel, $package, $b, $checked = array()) + { + $checked[$channel][$package] = true; + if (!isset($this->_depTree[$channel][$package])) { return false; } - if ($key == 'default_channel') { - if (!isset($reg)) { - $reg = &$this->getRegistry($layer); - if (!$reg) { - $reg = &$this->getRegistry(); - } - } - - if ($reg) { - $value = $reg->channelName($value); - } - - if (!$value) { - return false; - } + if (isset($this->_depTree[$channel][$package][strtolower($b->getChannel())] + [strtolower($b->getPackage())])) { + return true; } - $this->configuration[$layer][$key] = $value; - if ($key == 'php_dir' && !$this->_noRegistry) { - if (!isset($this->_registry[$layer]) || - $value != $this->_registry[$layer]->install_dir) { - $this->_registry[$layer] = &new PEAR_Registry($value); - $this->_regInitialized[$layer] = false; - $this->_registry[$layer]->setConfig($this, false); + foreach ($this->_depTree[$channel][$package] as $ch => $packages) { + foreach ($packages as $pa => $true) { + if ($this->_checkDepTree($ch, $pa, $b, $checked)) { + return true; + } } } - return true; + return false; } - function _lazyChannelSetup($uselayer = false) + function _sortInstall($a, $b) { - if ($this->_noRegistry) { - return; + if (!$a->getDeps() && !$b->getDeps()) { + return 0; // neither package has dependencies, order is insignificant } - - $merge = false; - foreach ($this->_registry as $layer => $p) { - if ($uselayer && $uselayer != $layer) { - continue; - } - - if (!$this->_regInitialized[$layer]) { - if ($layer == 'default' && isset($this->_registry['user']) || - isset($this->_registry['system'])) { - // only use the default registry if there are no alternatives - continue; - } - - if (!is_object($this->_registry[$layer])) { - if ($phpdir = $this->get('php_dir', $layer, 'pear.php.net')) { - $this->_registry[$layer] = &new PEAR_Registry($phpdir); - $this->_registry[$layer]->setConfig($this, false); - $this->_regInitialized[$layer] = false; - } else { - unset($this->_registry[$layer]); - return; - } - } - - $this->setChannels($this->_registry[$layer]->listChannels(), $merge); - $this->_regInitialized[$layer] = true; - $merge = true; - } + if ($a->getDeps() && !$b->getDeps()) { + return 1; // $a must be installed after $b because $a has dependencies + } + if (!$a->getDeps() && $b->getDeps()) { + return -1; // $b must be installed after $a because $b has dependencies + } + // both packages have dependencies + if ($this->_dependsOn($a, $b)) { + return 1; } + if ($this->_dependsOn($b, $a)) { + return -1; + } + return 0; } /** - * Set the list of channels. + * Download a file through HTTP. Considers suggested file name in + * Content-disposition: header and can run a callback function for + * different events. The callback will be called with two + * parameters: the callback type, and parameters. The implemented + * callback types are: * - * This should be set via a call to {@link PEAR_Registry::listChannels()} - * @param array - * @param bool - * @return bool success of operation + * 'setup' called at the very beginning, parameter is a UI object + * that should be used for all output + * 'message' the parameter is a string with an informational message + * 'saveas' may be used to save with a different file name, the + * parameter is the filename that is about to be used. + * If a 'saveas' callback returns a non-empty string, + * that file name will be used as the filename instead. + * Note that $save_dir will not be affected by this, only + * the basename of the file. + * 'start' download is starting, parameter is number of bytes + * that are expected, or -1 if unknown + * 'bytesread' parameter is the number of bytes read so far + * 'done' download is complete, parameter is the total number + * of bytes read + * 'connfailed' if the TCP/SSL connection fails, this callback is called + * with array(host,port,errno,errmsg) + * 'writefailed' if writing to disk fails, this callback is called + * with array(destfile,errmsg) + * + * If an HTTP proxy has been configured (http_proxy PEAR_Config + * setting), the proxy will be used. + * + * @param string $url the URL to download + * @param object $ui PEAR_Frontend_* instance + * @param object $config PEAR_Config instance + * @param string $save_dir directory to save file in + * @param mixed $callback function/method to call for status + * updates + * @param false|string|array $lastmodified header values to check against for caching + * use false to return the header values from this download + * @param false|array $accept Accept headers to send + * @param false|string $channel Channel to use for retrieving authentication + * @return string|array Returns the full path of the downloaded file or a PEAR + * error on failure. If the error is caused by + * socket-related errors, the error object will + * have the fsockopen error code available through + * getCode(). If caching is requested, then return the header + * values. + * + * @access public */ - function setChannels($channels, $merge = false) + function downloadHttp($url, &$ui, $save_dir = '.', $callback = null, $lastmodified = null, + $accept = false, $channel = false) { - if (!is_array($channels)) { - return false; + static $redirect = 0; + // always reset , so we are clean case of error + $wasredirect = $redirect; + $redirect = 0; + if ($callback) { + call_user_func($callback, 'setup', array(&$ui)); } - if ($merge) { - $this->_channels = array_merge($this->_channels, $channels); + $info = parse_url($url); + if (!isset($info['scheme']) || !in_array($info['scheme'], array('http', 'https'))) { + return PEAR::raiseError('Cannot download non-http URL "' . $url . '"'); + } + + if (!isset($info['host'])) { + return PEAR::raiseError('Cannot download from non-URL "' . $url . '"'); + } + + $host = isset($info['host']) ? $info['host'] : null; + $port = isset($info['port']) ? $info['port'] : null; + $path = isset($info['path']) ? $info['path'] : null; + + if (isset($this)) { + $config = &$this->config; } else { - $this->_channels = $channels; + $config = &PEAR_Config::singleton(); } - foreach ($channels as $channel) { - $channel = strtolower($channel); - if ($channel == 'pear.php.net') { - continue; + $proxy_host = $proxy_port = $proxy_user = $proxy_pass = ''; + if ($config->get('http_proxy') && + $proxy = parse_url($config->get('http_proxy'))) { + $proxy_host = isset($proxy['host']) ? $proxy['host'] : null; + if (isset($proxy['scheme']) && $proxy['scheme'] == 'https') { + $proxy_host = 'ssl://' . $proxy_host; } + $proxy_port = isset($proxy['port']) ? $proxy['port'] : 8080; + $proxy_user = isset($proxy['user']) ? urldecode($proxy['user']) : null; + $proxy_pass = isset($proxy['pass']) ? urldecode($proxy['pass']) : null; - foreach ($this->layers as $layer) { - if (!isset($this->configuration[$layer]['__channels'])) { - $this->configuration[$layer]['__channels'] = array(); - } - if (!isset($this->configuration[$layer]['__channels'][$channel]) - || !is_array($this->configuration[$layer]['__channels'][$channel])) { - $this->configuration[$layer]['__channels'][$channel] = array(); - } + if ($callback) { + call_user_func($callback, 'message', "Using HTTP proxy $host:$port"); } } - return true; - } - - /** - * Get the type of a config value. - * - * @param string config key - * - * @return string type, one of "string", "integer", "file", - * "directory", "set" or "password". - * - * @access public - * - */ - function getType($key) - { - if (isset($this->configuration_info[$key])) { - return $this->configuration_info[$key]['type']; + if (empty($port)) { + $port = (isset($info['scheme']) && $info['scheme'] == 'https') ? 443 : 80; } - return false; - } - /** - * Get the documentation for a config value. - * - * @param string config key - * @return string documentation string - * - * @access public - * - */ - function getDocs($key) - { - if (isset($this->configuration_info[$key])) { - return $this->configuration_info[$key]['doc']; - } + $scheme = (isset($info['scheme']) && $info['scheme'] == 'https') ? 'https' : 'http'; - return false; - } + if ($proxy_host != '') { + $fp = @fsockopen($proxy_host, $proxy_port, $errno, $errstr); + if (!$fp) { + if ($callback) { + call_user_func($callback, 'connfailed', array($proxy_host, $proxy_port, + $errno, $errstr)); + } + return PEAR::raiseError("Connection to `$proxy_host:$proxy_port' failed: $errstr", $errno); + } - /** - * Get the short documentation for a config value. - * - * @param string config key - * @return string short documentation string - * - * @access public - * - */ - function getPrompt($key) - { - if (isset($this->configuration_info[$key])) { - return $this->configuration_info[$key]['prompt']; + if ($lastmodified === false || $lastmodified) { + $request = "GET $url HTTP/1.1\r\n"; + $request .= "Host: $host:$port\r\n"; + } else { + $request = "GET $url HTTP/1.0\r\n"; + $request .= "Host: $host\r\n"; + } + } else { + $network_host = $host; + if (isset($info['scheme']) && $info['scheme'] == 'https') { + $network_host = 'ssl://' . $host; + } + + $fp = @fsockopen($network_host, $port, $errno, $errstr); + if (!$fp) { + if ($callback) { + call_user_func($callback, 'connfailed', array($host, $port, + $errno, $errstr)); + } + return PEAR::raiseError("Connection to `$host:$port' failed: $errstr", $errno); + } + + if ($lastmodified === false || $lastmodified) { + $request = "GET $path HTTP/1.1\r\n"; + $request .= "Host: $host:$port\r\n"; + } else { + $request = "GET $path HTTP/1.0\r\n"; + $request .= "Host: $host\r\n"; + } } - return false; - } + $ifmodifiedsince = ''; + if (is_array($lastmodified)) { + if (isset($lastmodified['Last-Modified'])) { + $ifmodifiedsince = 'If-Modified-Since: ' . $lastmodified['Last-Modified'] . "\r\n"; + } - /** - * Get the parameter group for a config key. - * - * @param string config key - * @return string parameter group - * - * @access public - * - */ - function getGroup($key) - { - if (isset($this->configuration_info[$key])) { - return $this->configuration_info[$key]['group']; + if (isset($lastmodified['ETag'])) { + $ifmodifiedsince .= "If-None-Match: $lastmodified[ETag]\r\n"; + } + } else { + $ifmodifiedsince = ($lastmodified ? "If-Modified-Since: $lastmodified\r\n" : ''); } - return false; - } + $request .= $ifmodifiedsince . + "User-Agent: PEAR/1.9.0/PHP/" . PHP_VERSION . "\r\n"; - /** - * Get the list of parameter groups. - * - * @return array list of parameter groups - * - * @access public - * - */ - function getGroups() - { - $tmp = array(); - foreach ($this->configuration_info as $key => $info) { - $tmp[$info['group']] = 1; + if (isset($this)) { // only pass in authentication for non-static calls + $username = $config->get('username', null, $channel); + $password = $config->get('password', null, $channel); + if ($username && $password) { + $tmp = base64_encode("$username:$password"); + $request .= "Authorization: Basic $tmp\r\n"; + } } - return array_keys($tmp); - } + if ($proxy_host != '' && $proxy_user != '') { + $request .= 'Proxy-Authorization: Basic ' . + base64_encode($proxy_user . ':' . $proxy_pass) . "\r\n"; + } - /** - * Get the list of the parameters in a group. - * - * @param string $group parameter group - * @return array list of parameters in $group - * - * @access public - * - */ - function getGroupKeys($group) - { - $keys = array(); - foreach ($this->configuration_info as $key => $info) { - if ($info['group'] == $group) { - $keys[] = $key; - } + if ($accept) { + $request .= 'Accept: ' . implode(', ', $accept) . "\r\n"; } - return $keys; - } + $request .= "Connection: close\r\n"; + $request .= "\r\n"; + fwrite($fp, $request); + $headers = array(); + $reply = 0; + while (trim($line = fgets($fp, 1024))) { + if (preg_match('/^([^:]+):\s+(.*)\s*\\z/', $line, $matches)) { + $headers[strtolower($matches[1])] = trim($matches[2]); + } elseif (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) { + $reply = (int)$matches[1]; + if ($reply == 304 && ($lastmodified || ($lastmodified === false))) { + return false; + } - /** - * Get the list of allowed set values for a config value. Returns - * NULL for config values that are not sets. - * - * @param string config key - * @return array enumerated array of set values, or NULL if the - * config key is unknown or not a set - * - * @access public - * - */ - function getSetValues($key) - { - if (isset($this->configuration_info[$key]) && - isset($this->configuration_info[$key]['type']) && - $this->configuration_info[$key]['type'] == 'set') - { - $valid_set = $this->configuration_info[$key]['valid_set']; - reset($valid_set); - if (key($valid_set) === 0) { - return $valid_set; + if (!in_array($reply, array(200, 301, 302, 303, 305, 307))) { + return PEAR::raiseError("File $scheme://$host:$port$path not valid (received: $line)"); + } } - - return array_keys($valid_set); } - return null; - } + if ($reply != 200) { + if (!isset($headers['location'])) { + return PEAR::raiseError("File $scheme://$host:$port$path not valid (redirected but no location)"); + } - /** - * Get all the current config keys. - * - * @return array simple array of config keys - * - * @access public - */ - function getKeys() - { - $keys = array(); - foreach ($this->layers as $layer) { - $test = $this->configuration[$layer]; - if (isset($test['__channels'])) { - foreach ($test['__channels'] as $channel => $configs) { - $keys = array_merge($keys, $configs); - } + if ($wasredirect > 4) { + return PEAR::raiseError("File $scheme://$host:$port$path not valid (redirection looped more than 5 times)"); } - unset($test['__channels']); - $keys = array_merge($keys, $test); + $redirect = $wasredirect + 1; + return $this->downloadHttp($headers['location'], + $ui, $save_dir, $callback, $lastmodified, $accept); + } + if (isset($headers['content-disposition']) && + preg_match('/\sfilename=\"([^;]*\S)\"\s*(;|\\z)/', $headers['content-disposition'], $matches)) { + $save_as = basename($matches[1]); + } else { + $save_as = basename($url); } - return array_keys($keys); - } - /** - * Remove the a config key from a specific config layer. - * - * @param string config key - * @param string (optional) config layer - * @return bool TRUE on success, FALSE on failure - * - * @access public - */ - function remove($key, $layer = 'user') - { - $channel = $this->getDefaultChannel(); - if ($channel !== 'pear.php.net') { - if (isset($this->configuration[$layer]['__channels'][$channel][$key])) { - unset($this->configuration[$layer]['__channels'][$channel][$key]); - return true; + if ($callback) { + $tmp = call_user_func($callback, 'saveas', $save_as); + if ($tmp) { + $save_as = $tmp; } } - if (isset($this->configuration[$layer][$key])) { - unset($this->configuration[$layer][$key]); - return true; + $dest_file = $save_dir . DIRECTORY_SEPARATOR . $save_as; + if (!$wp = @fopen($dest_file, 'wb')) { + fclose($fp); + if ($callback) { + call_user_func($callback, 'writefailed', array($dest_file, $php_errormsg)); + } + return PEAR::raiseError("could not open $dest_file for writing"); } - return false; - } + $length = isset($headers['content-length']) ? $headers['content-length'] : -1; - /** - * Temporarily remove an entire config layer. USE WITH CARE! - * - * @param string config key - * @param string (optional) config layer - * @return bool TRUE on success, FALSE on failure - * - * @access public - */ - function removeLayer($layer) - { - if (isset($this->configuration[$layer])) { - $this->configuration[$layer] = array(); - return true; + $bytes = 0; + if ($callback) { + call_user_func($callback, 'start', array(basename($dest_file), $length)); } - return false; - } + while ($data = fread($fp, 1024)) { + $bytes += strlen($data); + if ($callback) { + call_user_func($callback, 'bytesread', $bytes); + } + if (!@fwrite($wp, $data)) { + fclose($fp); + if ($callback) { + call_user_func($callback, 'writefailed', array($dest_file, $php_errormsg)); + } + return PEAR::raiseError("$dest_file: write failed ($php_errormsg)"); + } + } - /** - * Stores configuration data in a layer. - * - * @param string config layer to store - * @return bool TRUE on success, or PEAR error on failure - * - * @access public - */ - function store($layer = 'user', $data = null) - { - return $this->writeConfigFile(null, $layer, $data); - } + fclose($fp); + fclose($wp); + if ($callback) { + call_user_func($callback, 'done', $bytes); + } - /** - * Tells what config layer that gets to define a key. - * - * @param string config key - * @param boolean return the defining channel - * - * @return string|array the config layer, or an empty string if not found. - * - * if $returnchannel, the return is an array array('layer' => layername, - * 'channel' => channelname), or an empty string if not found - * - * @access public - */ - function definedBy($key, $returnchannel = false) - { - foreach ($this->layers as $layer) { - $channel = $this->getDefaultChannel(); - if ($channel !== 'pear.php.net') { - if (isset($this->configuration[$layer]['__channels'][$channel][$key])) { - if ($returnchannel) { - return array('layer' => $layer, 'channel' => $channel); - } - return $layer; - } + if ($lastmodified === false || $lastmodified) { + if (isset($headers['etag'])) { + $lastmodified = array('ETag' => $headers['etag']); } - if (isset($this->configuration[$layer][$key])) { - if ($returnchannel) { - return array('layer' => $layer, 'channel' => 'pear.php.net'); + if (isset($headers['last-modified'])) { + if (is_array($lastmodified)) { + $lastmodified['Last-Modified'] = $headers['last-modified']; + } else { + $lastmodified = $headers['last-modified']; } - return $layer; } + return array($dest_file, $lastmodified, $headers); } - - return ''; + return $dest_file; } +} +// }}} + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Package.php 287560 2009-08-21 22:36:18Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * Error code when parameter initialization fails because no releases + * exist within preferred_state, but releases do exist + */ +define('PEAR_DOWNLOADER_PACKAGE_STATE', -1003); +/** + * Error code when parameter initialization fails because no releases + * exist that will work with the existing PHP version + */ +define('PEAR_DOWNLOADER_PACKAGE_PHPVERSION', -1004); +/** + * Coordinates download parameters and manages their dependencies + * prior to downloading them. + * + * Input can come from three sources: + * + * - local files (archives or package.xml) + * - remote files (downloadable urls) + * - abstract package names + * + * The first two elements are handled cleanly by PEAR_PackageFile, but the third requires + * accessing pearweb's xml-rpc interface to determine necessary dependencies, and the + * format returned of dependencies is slightly different from that used in package.xml. + * + * This class hides the differences between these elements, and makes automatic + * dependency resolution a piece of cake. It also manages conflicts when + * two classes depend on incompatible dependencies, or differing versions of the same + * package dependency. In addition, download will not be attempted if the php version is + * not supported, PEAR installer version is not supported, or non-PECL extensions are not + * installed. + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Downloader_Package +{ /** - * Tells whether a given key exists as a config value. - * - * @param string config key - * @return bool whether exists in this object - * - * @access public + * @var PEAR_Downloader */ - function isDefined($key) - { - foreach ($this->layers as $layer) { - if (isset($this->configuration[$layer][$key])) { - return true; - } - } - - return false; - } - + var $_downloader; /** - * Tells whether a given config layer exists. - * - * @param string config layer - * @return bool whether exists in this object - * - * @access public + * @var PEAR_Config */ - function isDefinedLayer($layer) - { - return isset($this->configuration[$layer]); - } - + var $_config; /** - * Returns the layers defined (except the 'default' one) + * @var PEAR_Registry + */ + var $_registry; + /** + * Used to implement packagingroot properly + * @var PEAR_Registry + */ + var $_installRegistry; + /** + * @var PEAR_PackageFile_v1|PEAR_PackageFile|v2 + */ + var $_packagefile; + /** + * @var array + */ + var $_parsedname; + /** + * @var array + */ + var $_downloadURL; + /** + * @var array + */ + var $_downloadDeps = array(); + /** + * @var boolean + */ + var $_valid = false; + /** + * @var boolean + */ + var $_analyzed = false; + /** + * if this or a parent package was invoked with Package-state, this is set to the + * state variable. * - * @return array of the defined layers + * This allows temporary reassignment of preferred_state for a parent package and all of + * its dependencies. + * @var string|false */ - function getLayers() - { - $cf = $this->configuration; - unset($cf['default']); - return array_keys($cf); - } - - function apiVersion() - { - return '1.1'; - } + var $_explicitState = false; + /** + * If this package is invoked with Package#group, this variable will be true + */ + var $_explicitGroup = false; + /** + * Package type local|url + * @var string + */ + var $_type; + /** + * Contents of package.xml, if downloaded from a remote channel + * @var string|false + * @access private + */ + var $_rawpackagefile; + /** + * @var boolean + * @access private + */ + var $_validated = false; /** - * @return PEAR_Registry + * @param PEAR_Downloader */ - function &getRegistry($use = null) + function PEAR_Downloader_Package(&$downloader) { - $layer = $use === null ? 'user' : $use; - if (isset($this->_registry[$layer])) { - return $this->_registry[$layer]; - } elseif ($use === null && isset($this->_registry['system'])) { - return $this->_registry['system']; - } elseif ($use === null && isset($this->_registry['default'])) { - return $this->_registry['default']; - } elseif ($use) { - $a = false; - return $a; + $this->_downloader = &$downloader; + $this->_config = &$this->_downloader->config; + $this->_registry = &$this->_config->getRegistry(); + $options = $downloader->getOptions(); + if (isset($options['packagingroot'])) { + $this->_config->setInstallRoot($options['packagingroot']); + $this->_installRegistry = &$this->_config->getRegistry(); + $this->_config->setInstallRoot(false); + } else { + $this->_installRegistry = &$this->_registry; } - - // only go here if null was passed in - echo "CRITICAL ERROR: Registry could not be initialized from any value"; - exit(1); + $this->_valid = $this->_analyzed = false; } /** - * This is to allow customization like the use of installroot - * @param PEAR_Registry - * @return bool + * Parse the input and determine whether this is a local file, a remote uri, or an + * abstract package name. + * + * This is the heart of the PEAR_Downloader_Package(), and is used in + * {@link PEAR_Downloader::download()} + * @param string + * @return bool|PEAR_Error */ - function setRegistry(&$reg, $layer = 'user') + function initialize($param) { - if ($this->_noRegistry) { - return false; + $origErr = $this->_fromFile($param); + if ($this->_valid) { + return true; } - if (!in_array($layer, array('user', 'system'))) { - return false; + $options = $this->_downloader->getOptions(); + if (isset($options['offline'])) { + if (PEAR::isError($origErr) && !isset($options['soft'])) { + foreach ($origErr->getUserInfo() as $userInfo) { + if (isset($userInfo['message'])) { + $this->_downloader->log(0, $userInfo['message']); + } + } + + $this->_downloader->log(0, $origErr->getMessage()); + } + + return PEAR::raiseError('Cannot download non-local package "' . $param . '"'); } - $this->_registry[$layer] = &$reg; - if (is_object($reg)) { - $this->_registry[$layer]->setConfig($this, false); - } + $err = $this->_fromUrl($param); + if (PEAR::isError($err) || !$this->_valid) { + if ($this->_type == 'url') { + if (PEAR::isError($err) && !isset($options['soft'])) { + $this->_downloader->log(0, $err->getMessage()); + } + + return PEAR::raiseError("Invalid or missing remote package file"); + } + + $err = $this->_fromString($param); + if (PEAR::isError($err) || !$this->_valid) { + if (PEAR::isError($err) && $err->getCode() == PEAR_DOWNLOADER_PACKAGE_STATE) { + return false; // instruct the downloader to silently skip + } + + if (isset($this->_type) && $this->_type == 'local' && PEAR::isError($origErr)) { + if (is_array($origErr->getUserInfo())) { + foreach ($origErr->getUserInfo() as $err) { + if (is_array($err)) { + $err = $err['message']; + } + + if (!isset($options['soft'])) { + $this->_downloader->log(0, $err); + } + } + } - return true; - } + if (!isset($options['soft'])) { + $this->_downloader->log(0, $origErr->getMessage()); + } - function noRegistry() - { - $this->_noRegistry = true; - } + if (is_array($param)) { + $param = $this->_registry->parsedPackageNameToString($param, true); + } - /** - * @return PEAR_REST - */ - function &getREST($version, $options = array()) - { - $version = str_replace('.', '', $version); - if (!class_exists($class = 'PEAR_REST_' . $version)) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/REST/' . $version . '.php'; - } + if (!isset($options['soft'])) { + $this->_downloader->log(2, "Cannot initialize '$param', invalid or missing package file"); + } - $remote = &new $class($this, $options); - return $remote; - } + // Passing no message back - already logged above + return PEAR::raiseError(); + } - /** - * The ftp server is set in {@link readFTPConfigFile()}. It exists only if a - * remote configuration file has been specified - * @return PEAR_FTP|false - */ - function &getFTP() - { - if (isset($this->_ftp)) { - return $this->_ftp; - } + if (PEAR::isError($err) && !isset($options['soft'])) { + $this->_downloader->log(0, $err->getMessage()); + } - $a = false; - return $a; - } + if (is_array($param)) { + $param = $this->_registry->parsedPackageNameToString($param, true); + } - function _prependPath($path, $prepend) - { - if (strlen($prepend) > 0) { - if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) { - if (preg_match('/^[a-z]:/i', $prepend)) { - $prepend = substr($prepend, 2); - } elseif ($prepend{0} != '\\') { - $prepend = "\\$prepend"; + if (!isset($options['soft'])) { + $this->_downloader->log(2, "Cannot initialize '$param', invalid or missing package file"); } - $path = substr($path, 0, 2) . $prepend . substr($path, 2); - } else { - $path = $prepend . $path; + + // Passing no message back - already logged above + return PEAR::raiseError(); } } - return $path; + + return true; } /** - * @param string|false installation directory to prepend to all _dir variables, or false to - * disable + * Retrieve any non-local packages + * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|PEAR_Error */ - function setInstallRoot($root) + function &download() { - if (substr($root, -1) == DIRECTORY_SEPARATOR) { - $root = substr($root, 0, -1); + if (isset($this->_packagefile)) { + return $this->_packagefile; } - $old = $this->_installRoot; - $this->_installRoot = $root; - if (($old != $root) && !$this->_noRegistry) { - foreach (array_keys($this->_registry) as $layer) { - if ($layer == 'ftp' || !isset($this->_registry[$layer])) { - continue; - } - $this->_registry[$layer] = - &new PEAR_Registry($this->get('php_dir', $layer, 'pear.php.net')); - $this->_registry[$layer]->setConfig($this, false); - $this->_regInitialized[$layer] = false; + + if (isset($this->_downloadURL['url'])) { + $this->_isvalid = false; + $info = $this->getParsedPackage(); + foreach ($info as $i => $p) { + $info[$i] = strtolower($p); } - } - } -} - - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Dependency2.php,v 1.59 2009/02/24 23:38:22 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * Required for the PEAR_VALIDATE_* constants - */ -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Validate.php'; + $err = $this->_fromUrl($this->_downloadURL['url'], + $this->_registry->parsedPackageNameToString($this->_parsedname, true)); + $newinfo = $this->getParsedPackage(); + foreach ($newinfo as $i => $p) { + $newinfo[$i] = strtolower($p); + } -/** - * Dependency check for PEAR packages - * - * This class handles both version 1.0 and 2.0 dependencies - * WARNING: *any* changes to this class must be duplicated in the - * test_PEAR_Dependency2 class found in tests/PEAR_Dependency2/setup.php.inc, - * or unit tests will not actually validate the changes - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Dependency2 -{ - /** - * One of the PEAR_VALIDATE_* states - * @see PEAR_VALIDATE_NORMAL - * @var integer - */ - var $_state; + if ($info != $newinfo) { + do { + if ($info['channel'] == 'pecl.php.net' && $newinfo['channel'] == 'pear.php.net') { + $info['channel'] = 'pear.php.net'; + if ($info == $newinfo) { + // skip the channel check if a pecl package says it's a PEAR package + break; + } + } + if ($info['channel'] == 'pear.php.net' && $newinfo['channel'] == 'pecl.php.net') { + $info['channel'] = 'pecl.php.net'; + if ($info == $newinfo) { + // skip the channel check if a pecl package says it's a PEAR package + break; + } + } - /** - * Command-line options to install/upgrade/uninstall commands - * @param array - */ - var $_options; + return PEAR::raiseError('CRITICAL ERROR: We are ' . + $this->_registry->parsedPackageNameToString($info) . ', but the file ' . + 'downloaded claims to be ' . + $this->_registry->parsedPackageNameToString($this->getParsedPackage())); + } while (false); + } - /** - * @var OS_Guess - */ - var $_os; + if (PEAR::isError($err) || !$this->_valid) { + return $err; + } + } - /** - * @var PEAR_Registry - */ - var $_registry; + $this->_type = 'local'; + return $this->_packagefile; + } - /** - * @var PEAR_Config - */ - var $_config; + function &getPackageFile() + { + return $this->_packagefile; + } - /** - * @var PEAR_DependencyDB - */ - var $_dependencydb; + function &getDownloader() + { + return $this->_downloader; + } - /** - * Output of PEAR_Registry::parsedPackageName() - * @var array - */ - var $_currentPackage; + function getType() + { + return $this->_type; + } /** - * @param PEAR_Config - * @param array installation options - * @param array format of PEAR_Registry::parsedPackageName() - * @param int installation state (one of PEAR_VALIDATE_*) + * Like {@link initialize()}, but operates on a dependency */ - function PEAR_Dependency2(&$config, $installoptions, $package, - $state = PEAR_VALIDATE_INSTALLING) + function fromDepURL($dep) { - $this->_config = &$config; - if (!class_exists('PEAR_DependencyDB')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/DependencyDB.php'; - } + $this->_downloadURL = $dep; + if (isset($dep['uri'])) { + $options = $this->_downloader->getOptions(); + if (!extension_loaded("zlib") || isset($options['nocompress'])) { + $ext = '.tar'; + } else { + $ext = '.tgz'; + } - if (isset($installoptions['packagingroot'])) { - // make sure depdb is in the right location - $config->setInstallRoot($installoptions['packagingroot']); - } + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $err = $this->_fromUrl($dep['uri'] . $ext); + PEAR::popErrorHandling(); + if (PEAR::isError($err)) { + if (!isset($options['soft'])) { + $this->_downloader->log(0, $err->getMessage()); + } - $this->_registry = &$config->getRegistry(); - $this->_dependencydb = &PEAR_DependencyDB::singleton($config); - if (isset($installoptions['packagingroot'])) { - $config->setInstallRoot(false); - } + return PEAR::raiseError('Invalid uri dependency "' . $dep['uri'] . $ext . '", ' . + 'cannot download'); + } + } else { + $this->_parsedname = + array( + 'package' => $dep['info']->getPackage(), + 'channel' => $dep['info']->getChannel(), + 'version' => $dep['version'] + ); + if (!isset($dep['nodefault'])) { + $this->_parsedname['group'] = 'default'; // download the default dependency group + $this->_explicitGroup = false; + } - $this->_options = $installoptions; - $this->_state = $state; - if (!class_exists('OS_Guess')) { - require_once 'phar://install-pear-nozlib.phar/' . 'OS/Guess.php'; + $this->_rawpackagefile = $dep['raw']; } - - $this->_os = new OS_Guess; - $this->_currentPackage = $package; } - function _getExtraString($dep) + function detectDependencies($params) { - $extra = ' ('; - if (isset($dep['uri'])) { - return ''; + $options = $this->_downloader->getOptions(); + if (isset($options['downloadonly'])) { + return; } - if (isset($dep['recommended'])) { - $extra .= 'recommended version ' . $dep['recommended']; - } else { - if (isset($dep['min'])) { - $extra .= 'version >= ' . $dep['min']; - } - - if (isset($dep['max'])) { - if ($extra != ' (') { - $extra .= ', '; - } - $extra .= 'version <= ' . $dep['max']; - } - - if (isset($dep['exclude'])) { - if (!is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); - } + if (isset($options['offline'])) { + $this->_downloader->log(3, 'Skipping dependency download check, --offline specified'); + return; + } - if ($extra != ' (') { - $extra .= ', '; - } + $pname = $this->getParsedPackage(); + if (!$pname) { + return; + } - $extra .= 'excluded versions: '; - foreach ($dep['exclude'] as $i => $exclude) { - if ($i) { - $extra .= ', '; - } - $extra .= $exclude; - } - } + $deps = $this->getDeps(); + if (!$deps) { + return; } - $extra .= ')'; - if ($extra == ' ()') { - $extra = ''; + if (isset($deps['required'])) { // package.xml 2.0 + return $this->_detect2($deps, $pname, $options, $params); } - return $extra; + return $this->_detect1($deps, $pname, $options, $params); } - /** - * This makes unit-testing a heck of a lot easier - */ - function getPHP_OS() + function setValidated() { - return PHP_OS; + $this->_validated = true; } - /** - * This makes unit-testing a heck of a lot easier - */ - function getsysname() + function alreadyValidated() { - return $this->_os->getSysname(); + return $this->_validated; } /** - * Specify a dependency on an OS. Use arch for detailed os/processor information - * - * There are two generic OS dependencies that will be the most common, unix and windows. - * Other options are linux, freebsd, darwin (OS X), sunos, irix, hpux, aix + * Remove packages to be downloaded that are already installed + * @param array of PEAR_Downloader_Package objects + * @static */ - function validateOsDependency($dep) + function removeInstalled(&$params) { - if ($this->_state != PEAR_VALIDATE_INSTALLING && $this->_state != PEAR_VALIDATE_DOWNLOADING) { - return true; + if (!isset($params[0])) { + return; } - if ($dep['name'] == '*') { - return true; + $options = $params[0]->_downloader->getOptions(); + if (!isset($options['downloadonly'])) { + foreach ($params as $i => $param) { + $package = $param->getPackage(); + $channel = $param->getChannel(); + // remove self if already installed with this version + // this does not need any pecl magic - we only remove exact matches + if ($param->_installRegistry->packageExists($package, $channel)) { + $packageVersion = $param->_installRegistry->packageInfo($package, 'version', $channel); + if (version_compare($packageVersion, $param->getVersion(), '==')) { + if (!isset($options['force'])) { + $info = $param->getParsedPackage(); + unset($info['version']); + unset($info['state']); + if (!isset($options['soft'])) { + $param->_downloader->log(1, 'Skipping package "' . + $param->getShortName() . + '", already installed as version ' . $packageVersion); + } + $params[$i] = false; + } + } elseif (!isset($options['force']) && !isset($options['upgrade']) && + !isset($options['soft'])) { + $info = $param->getParsedPackage(); + $param->_downloader->log(1, 'Skipping package "' . + $param->getShortName() . + '", already installed as version ' . $packageVersion); + $params[$i] = false; + } + } + } } - $not = isset($dep['conflicts']) ? true : false; - switch (strtolower($dep['name'])) { - case 'windows' : - if ($not) { - if (strtolower(substr($this->getPHP_OS(), 0, 3)) == 'win') { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError("Cannot install %s on Windows"); - } + PEAR_Downloader_Package::removeDuplicates($params); + } - return $this->warning("warning: Cannot install %s on Windows"); + function _detect2($deps, $pname, $options, $params) + { + $this->_downloadDeps = array(); + $groupnotfound = false; + foreach (array('package', 'subpackage') as $packagetype) { + // get required dependency group + if (isset($deps['required'][$packagetype])) { + if (isset($deps['required'][$packagetype][0])) { + foreach ($deps['required'][$packagetype] as $dep) { + if (isset($dep['conflicts'])) { + // skip any package that this package conflicts with + continue; + } + $ret = $this->_detect2Dep($dep, $pname, 'required', $params); + if (is_array($ret)) { + $this->_downloadDeps[] = $ret; + } elseif (PEAR::isError($ret) && !isset($options['soft'])) { + $this->_downloader->log(0, $ret->getMessage()); + } } } else { - if (strtolower(substr($this->getPHP_OS(), 0, 3)) != 'win') { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError("Can only install %s on Windows"); + $dep = $deps['required'][$packagetype]; + if (!isset($dep['conflicts'])) { + // skip any package that this package conflicts with + $ret = $this->_detect2Dep($dep, $pname, 'required', $params); + if (is_array($ret)) { + $this->_downloadDeps[] = $ret; + } elseif (PEAR::isError($ret) && !isset($options['soft'])) { + $this->_downloader->log(0, $ret->getMessage()); } + } + } + } - return $this->warning("warning: Can only install %s on Windows"); + // get optional dependency group, if any + if (isset($deps['optional'][$packagetype])) { + $skipnames = array(); + if (!isset($deps['optional'][$packagetype][0])) { + $deps['optional'][$packagetype] = array($deps['optional'][$packagetype]); + } + + foreach ($deps['optional'][$packagetype] as $dep) { + $skip = false; + if (!isset($options['alldeps'])) { + $dep['package'] = $dep['name']; + if (!isset($options['soft'])) { + $this->_downloader->log(3, 'Notice: package "' . + $this->_registry->parsedPackageNameToString($this->getParsedPackage(), + true) . '" optional dependency "' . + $this->_registry->parsedPackageNameToString(array('package' => + $dep['name'], 'channel' => 'pear.php.net'), true) . + '" will not be automatically downloaded'); + } + $skipnames[] = $this->_registry->parsedPackageNameToString($dep, true); + $skip = true; + unset($dep['package']); + } + + $ret = $this->_detect2Dep($dep, $pname, 'optional', $params); + if (PEAR::isError($ret) && !isset($options['soft'])) { + $this->_downloader->log(0, $ret->getMessage()); + } + + if (!$ret) { + $dep['package'] = $dep['name']; + $skip = count($skipnames) ? + $skipnames[count($skipnames) - 1] : ''; + if ($skip == + $this->_registry->parsedPackageNameToString($dep, true)) { + array_pop($skipnames); + } + } + + if (!$skip && is_array($ret)) { + $this->_downloadDeps[] = $ret; } } - break; - case 'unix' : - $unices = array('linux', 'freebsd', 'darwin', 'sunos', 'irix', 'hpux', 'aix'); - if ($not) { - if (in_array($this->getSysname(), $unices)) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError("Cannot install %s on any Unix system"); + + if (count($skipnames)) { + if (!isset($options['soft'])) { + $this->_downloader->log(1, 'Did not download optional dependencies: ' . + implode(', ', $skipnames) . + ', use --alldeps to download automatically'); + } + } + } + + // get requested dependency group, if any + $groupname = $this->getGroup(); + $explicit = $this->_explicitGroup; + if (!$groupname) { + if (!$this->canDefault()) { + continue; + } + + $groupname = 'default'; // try the default dependency group + } + + if ($groupnotfound) { + continue; + } + + if (isset($deps['group'])) { + if (isset($deps['group']['attribs'])) { + if (strtolower($deps['group']['attribs']['name']) == strtolower($groupname)) { + $group = $deps['group']; + } elseif ($explicit) { + if (!isset($options['soft'])) { + $this->_downloader->log(0, 'Warning: package "' . + $this->_registry->parsedPackageNameToString($pname, true) . + '" has no dependency ' . 'group named "' . $groupname . '"'); } - return $this->warning( "warning: Cannot install %s on any Unix system"); + $groupnotfound = true; + continue; } } else { - if (!in_array($this->getSysname(), $unices)) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError("Can only install %s on a Unix system"); + $found = false; + foreach ($deps['group'] as $group) { + if (strtolower($group['attribs']['name']) == strtolower($groupname)) { + $found = true; + break; } + } - return $this->warning("warning: Can only install %s on a Unix system"); + if (!$found) { + if ($explicit) { + if (!isset($options['soft'])) { + $this->_downloader->log(0, 'Warning: package "' . + $this->_registry->parsedPackageNameToString($pname, true) . + '" has no dependency ' . 'group named "' . $groupname . '"'); + } + } + + $groupnotfound = true; + continue; } } - break; - default : - if ($not) { - if (strtolower($dep['name']) == strtolower($this->getSysname())) { - if (!isset($this->_options['nodeps']) && - !isset($this->_options['force'])) { - return $this->raiseError('Cannot install %s on ' . $dep['name'] . - ' operating system'); - } + } - return $this->warning('warning: Cannot install %s on ' . - $dep['name'] . ' operating system'); + if (isset($group) && isset($group[$packagetype])) { + if (isset($group[$packagetype][0])) { + foreach ($group[$packagetype] as $dep) { + $ret = $this->_detect2Dep($dep, $pname, 'dependency group "' . + $group['attribs']['name'] . '"', $params); + if (is_array($ret)) { + $this->_downloadDeps[] = $ret; + } elseif (PEAR::isError($ret) && !isset($options['soft'])) { + $this->_downloader->log(0, $ret->getMessage()); + } } } else { - if (strtolower($dep['name']) != strtolower($this->getSysname())) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('Cannot install %s on ' . - $this->getSysname() . - ' operating system, can only install on ' . $dep['name']); - } - - return $this->warning('warning: Cannot install %s on ' . - $this->getSysname() . - ' operating system, can only install on ' . $dep['name']); + $ret = $this->_detect2Dep($group[$packagetype], $pname, + 'dependency group "' . + $group['attribs']['name'] . '"', $params); + if (is_array($ret)) { + $this->_downloadDeps[] = $ret; + } elseif (PEAR::isError($ret) && !isset($options['soft'])) { + $this->_downloader->log(0, $ret->getMessage()); } } + } } - return true; - } - - /** - * This makes unit-testing a heck of a lot easier - */ - function matchSignature($pattern) - { - return $this->_os->matchSignature($pattern); } - /** - * Specify a complex dependency on an OS/processor/kernel version, - * Use OS for simple operating system dependency. - * - * This is the only dependency that accepts an eregable pattern. The pattern - * will be matched against the php_uname() output parsed by OS_Guess - */ - function validateArchDependency($dep) + function _detect2Dep($dep, $pname, $group, $params) { - if ($this->_state != PEAR_VALIDATE_INSTALLING) { + if (isset($dep['conflicts'])) { return true; } - $not = isset($dep['conflicts']) ? true : false; - if (!$this->matchSignature($dep['pattern'])) { - if (!$not) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s Architecture dependency failed, does not ' . - 'match "' . $dep['pattern'] . '"'); - } + $options = $this->_downloader->getOptions(); + if (isset($dep['uri'])) { + return array('uri' => $dep['uri'], 'dep' => $dep);; + } - return $this->warning('warning: %s Architecture dependency failed, does ' . - 'not match "' . $dep['pattern'] . '"'); + $testdep = $dep; + $testdep['package'] = $dep['name']; + if (PEAR_Downloader_Package::willDownload($testdep, $params)) { + $dep['package'] = $dep['name']; + if (!isset($options['soft'])) { + $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group . + ' dependency "' . + $this->_registry->parsedPackageNameToString($dep, true) . + '", will be installed'); } + return false; + } - return true; + $options = $this->_downloader->getOptions(); + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + if ($this->_explicitState) { + $pname['state'] = $this->_explicitState; } - if ($not) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s Architecture dependency failed, required "' . - $dep['pattern'] . '"'); + $url = $this->_downloader->_getDepPackageDownloadUrl($dep, $pname); + if (PEAR::isError($url)) { + PEAR::popErrorHandling(); + return $url; + } + + $dep['package'] = $dep['name']; + $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params, $group == 'optional' && + !isset($options['alldeps']), true); + PEAR::popErrorHandling(); + if (PEAR::isError($ret)) { + if (!isset($options['soft'])) { + $this->_downloader->log(0, $ret->getMessage()); } - return $this->warning('warning: %s Architecture dependency failed, ' . - 'required "' . $dep['pattern'] . '"'); + return false; } - return true; - } + // check to see if a dep is already installed and is the same or newer + if (!isset($dep['min']) && !isset($dep['max']) && !isset($dep['recommended'])) { + $oper = 'has'; + } else { + $oper = 'gt'; + } - /** - * This makes unit-testing a heck of a lot easier - */ - function extension_loaded($name) - { - return extension_loaded($name); - } + // do not try to move this before getDepPackageDownloadURL + // we can't determine whether upgrade is necessary until we know what + // version would be downloaded + if (!isset($options['force']) && $this->isInstalled($ret, $oper)) { + $version = $this->_installRegistry->packageInfo($dep['name'], 'version', $dep['channel']); + $dep['package'] = $dep['name']; + if (!isset($options['soft'])) { + $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group . + ' dependency "' . + $this->_registry->parsedPackageNameToString($dep, true) . + '" version ' . $url['version'] . ', already installed as version ' . + $version); + } - /** - * This makes unit-testing a heck of a lot easier - */ - function phpversion($name = null) - { - if ($name !== null) { - return phpversion($name); + return false; } - return phpversion(); + if (isset($dep['nodefault'])) { + $ret['nodefault'] = true; + } + + return $ret; } - function validateExtensionDependency($dep, $required = true) + function _detect1($deps, $pname, $options, $params) { - if ($this->_state != PEAR_VALIDATE_INSTALLING && - $this->_state != PEAR_VALIDATE_DOWNLOADING) { - return true; - } + $this->_downloadDeps = array(); + $skipnames = array(); + foreach ($deps as $dep) { + $nodownload = false; + if (isset ($dep['type']) && $dep['type'] === 'pkg') { + $dep['channel'] = 'pear.php.net'; + $dep['package'] = $dep['name']; + switch ($dep['rel']) { + case 'not' : + continue 2; + case 'ge' : + case 'eq' : + case 'gt' : + case 'has' : + $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ? + 'required' : + 'optional'; + if (PEAR_Downloader_Package::willDownload($dep, $params)) { + $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group + . ' dependency "' . + $this->_registry->parsedPackageNameToString($dep, true) . + '", will be installed'); + continue 2; + } + $fakedp = new PEAR_PackageFile_v1; + $fakedp->setPackage($dep['name']); + // skip internet check if we are not upgrading (bug #5810) + if (!isset($options['upgrade']) && $this->isInstalled( + $fakedp, $dep['rel'])) { + $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group + . ' dependency "' . + $this->_registry->parsedPackageNameToString($dep, true) . + '", is already installed'); + continue 2; + } + } - $loaded = $this->extension_loaded($dep['name']); - $extra = $this->_getExtraString($dep); - if (isset($dep['exclude'])) { - if (!is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); - } - } + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + if ($this->_explicitState) { + $pname['state'] = $this->_explicitState; + } - if (!isset($dep['min']) && !isset($dep['max']) && - !isset($dep['recommended']) && !isset($dep['exclude'])) { - if ($loaded) { - if (isset($dep['conflicts'])) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s conflicts with PHP extension "' . - $dep['name'] . '"' . $extra); + $url = $this->_downloader->_getDepPackageDownloadUrl($dep, $pname); + $chan = 'pear.php.net'; + if (PEAR::isError($url)) { + // check to see if this is a pecl package that has jumped + // from pear.php.net to pecl.php.net channel + if (!class_exists('PEAR_Dependency2')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Dependency2.php'; } - return $this->warning('warning: %s conflicts with PHP extension "' . - $dep['name'] . '"' . $extra); + $newdep = PEAR_Dependency2::normalizeDep($dep); + $newdep = $newdep[0]; + $newdep['channel'] = 'pecl.php.net'; + $chan = 'pecl.php.net'; + $url = $this->_downloader->_getDepPackageDownloadUrl($newdep, $pname); + $obj = &$this->_installRegistry->getPackage($dep['name']); + if (PEAR::isError($url)) { + PEAR::popErrorHandling(); + if ($obj !== null && $this->isInstalled($obj, $dep['rel'])) { + $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ? + 'required' : + 'optional'; + $dep['package'] = $dep['name']; + if (!isset($options['soft'])) { + $this->_downloader->log(3, $this->getShortName() . + ': Skipping ' . $group . ' dependency "' . + $this->_registry->parsedPackageNameToString($dep, true) . + '", already installed as version ' . $obj->getVersion()); + } + $skip = count($skipnames) ? + $skipnames[count($skipnames) - 1] : ''; + if ($skip == + $this->_registry->parsedPackageNameToString($dep, true)) { + array_pop($skipnames); + } + continue; + } else { + if (isset($dep['optional']) && $dep['optional'] == 'yes') { + $this->_downloader->log(2, $this->getShortName() . + ': Skipping optional dependency "' . + $this->_registry->parsedPackageNameToString($dep, true) . + '", no releases exist'); + continue; + } else { + return $url; + } + } + } } - return true; - } else { - if (isset($dep['conflicts'])) { - return true; + PEAR::popErrorHandling(); + if (!isset($options['alldeps'])) { + if (isset($dep['optional']) && $dep['optional'] == 'yes') { + if (!isset($options['soft'])) { + $this->_downloader->log(3, 'Notice: package "' . + $this->getShortName() . + '" optional dependency "' . + $this->_registry->parsedPackageNameToString( + array('channel' => $chan, 'package' => + $dep['name']), true) . + '" will not be automatically downloaded'); + } + $skipnames[] = $this->_registry->parsedPackageNameToString( + array('channel' => $chan, 'package' => + $dep['name']), true); + $nodownload = true; + } } - if ($required) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires PHP extension "' . - $dep['name'] . '"' . $extra); + if (!isset($options['alldeps']) && !isset($options['onlyreqdeps'])) { + if (!isset($dep['optional']) || $dep['optional'] == 'no') { + if (!isset($options['soft'])) { + $this->_downloader->log(3, 'Notice: package "' . + $this->getShortName() . + '" required dependency "' . + $this->_registry->parsedPackageNameToString( + array('channel' => $chan, 'package' => + $dep['name']), true) . + '" will not be automatically downloaded'); + } + $skipnames[] = $this->_registry->parsedPackageNameToString( + array('channel' => $chan, 'package' => + $dep['name']), true); + $nodownload = true; } + } - return $this->warning('warning: %s requires PHP extension "' . - $dep['name'] . '"' . $extra); + // check to see if a dep is already installed + // do not try to move this before getDepPackageDownloadURL + // we can't determine whether upgrade is necessary until we know what + // version would be downloaded + if (!isset($options['force']) && $this->isInstalled( + $url, $dep['rel'])) { + $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ? + 'required' : + 'optional'; + $dep['package'] = $dep['name']; + if (isset($newdep)) { + $version = $this->_installRegistry->packageInfo($newdep['name'], 'version', $newdep['channel']); + } else { + $version = $this->_installRegistry->packageInfo($dep['name'], 'version'); + } + + $dep['version'] = $url['version']; + if (!isset($options['soft'])) { + $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group . + ' dependency "' . + $this->_registry->parsedPackageNameToString($dep, true) . + '", already installed as version ' . $version); + } + + $skip = count($skipnames) ? + $skipnames[count($skipnames) - 1] : ''; + if ($skip == + $this->_registry->parsedPackageNameToString($dep, true)) { + array_pop($skipnames); + } + + continue; } - return $this->warning('%s can optionally use PHP extension "' . - $dep['name'] . '"' . $extra); + if ($nodownload) { + continue; + } + + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + if (isset($newdep)) { + $dep = $newdep; + } + + $dep['package'] = $dep['name']; + $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params, + isset($dep['optional']) && $dep['optional'] == 'yes' && + !isset($options['alldeps']), true); + PEAR::popErrorHandling(); + if (PEAR::isError($ret)) { + if (!isset($options['soft'])) { + $this->_downloader->log(0, $ret->getMessage()); + } + continue; + } + + $this->_downloadDeps[] = $ret; } } - if (!$loaded) { - if (isset($dep['conflicts'])) { - return true; + if (count($skipnames)) { + if (!isset($options['soft'])) { + $this->_downloader->log(1, 'Did not download dependencies: ' . + implode(', ', $skipnames) . + ', use --alldeps or --onlyreqdeps to download automatically'); } + } + } - if (!$required) { - return $this->warning('%s can optionally use PHP extension "' . - $dep['name'] . '"' . $extra); - } + function setDownloadURL($pkg) + { + $this->_downloadURL = $pkg; + } - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires PHP extension "' . $dep['name'] . - '"' . $extra); - } + /** + * Set the package.xml object for this downloaded package + * + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 $pkg + */ + function setPackageFile(&$pkg) + { + $this->_packagefile = &$pkg; + } - return $this->warning('warning: %s requires PHP extension "' . $dep['name'] . - '"' . $extra); - } + function getShortName() + { + return $this->_registry->parsedPackageNameToString(array('channel' => $this->getChannel(), + 'package' => $this->getPackage()), true); + } - $version = (string) $this->phpversion($dep['name']); - if (empty($version)) { - $version = '0'; + function getParsedPackage() + { + if (isset($this->_packagefile) || isset($this->_parsedname)) { + return array('channel' => $this->getChannel(), + 'package' => $this->getPackage(), + 'version' => $this->getVersion()); } - $fail = false; - if (isset($dep['min']) && !version_compare($version, $dep['min'], '>=')) { - $fail = true; - } + return false; + } - if (isset($dep['max']) && !version_compare($version, $dep['max'], '<=')) { - $fail = true; - } + function getDownloadURL() + { + return $this->_downloadURL; + } - if ($fail && !isset($dep['conflicts'])) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires PHP extension "' . $dep['name'] . - '"' . $extra . ', installed version is ' . $version); - } + function canDefault() + { + if (isset($this->_downloadURL) && isset($this->_downloadURL['nodefault'])) { + return false; + } - return $this->warning('warning: %s requires PHP extension "' . $dep['name'] . - '"' . $extra . ', installed version is ' . $version); - } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail && isset($dep['conflicts'])) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s conflicts with PHP extension "' . - $dep['name'] . '"' . $extra . ', installed version is ' . $version); - } + return true; + } - return $this->warning('warning: %s conflicts with PHP extension "' . - $dep['name'] . '"' . $extra . ', installed version is ' . $version); + function getPackage() + { + if (isset($this->_packagefile)) { + return $this->_packagefile->getPackage(); + } elseif (isset($this->_downloadURL['info'])) { + return $this->_downloadURL['info']->getPackage(); } - if (isset($dep['exclude'])) { - foreach ($dep['exclude'] as $exclude) { - if (version_compare($version, $exclude, '==')) { - if (isset($dep['conflicts'])) { - continue; - } + return false; + } - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s is not compatible with PHP extension "' . - $dep['name'] . '" version ' . - $exclude); - } + /** + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + */ + function isSubpackage(&$pf) + { + if (isset($this->_packagefile)) { + return $this->_packagefile->isSubpackage($pf); + } elseif (isset($this->_downloadURL['info'])) { + return $this->_downloadURL['info']->isSubpackage($pf); + } - return $this->warning('warning: %s is not compatible with PHP extension "' . - $dep['name'] . '" version ' . - $exclude); - } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s conflicts with PHP extension "' . - $dep['name'] . '"' . $extra . ', installed version is ' . $version); - } + return false; + } - return $this->warning('warning: %s conflicts with PHP extension "' . - $dep['name'] . '"' . $extra . ', installed version is ' . $version); - } - } + function getPackageType() + { + if (isset($this->_packagefile)) { + return $this->_packagefile->getPackageType(); + } elseif (isset($this->_downloadURL['info'])) { + return $this->_downloadURL['info']->getPackageType(); } - if (isset($dep['recommended'])) { - if (version_compare($version, $dep['recommended'], '==')) { - return true; - } - - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s dependency: PHP extension ' . $dep['name'] . - ' version "' . $version . '"' . - ' is not the recommended version "' . $dep['recommended'] . - '", but may be compatible, use --force to install'); - } + return false; + } - return $this->warning('warning: %s dependency: PHP extension ' . - $dep['name'] . ' version "' . $version . '"' . - ' is not the recommended version "' . $dep['recommended'].'"'); + function isBundle() + { + if (isset($this->_packagefile)) { + return $this->_packagefile->getPackageType() == 'bundle'; } - return true; + return false; } - function validatePhpDependency($dep) + function getPackageXmlVersion() { - if ($this->_state != PEAR_VALIDATE_INSTALLING && - $this->_state != PEAR_VALIDATE_DOWNLOADING) { - return true; + if (isset($this->_packagefile)) { + return $this->_packagefile->getPackagexmlVersion(); + } elseif (isset($this->_downloadURL['info'])) { + return $this->_downloadURL['info']->getPackagexmlVersion(); } - $version = $this->phpversion(); - $extra = $this->_getExtraString($dep); - if (isset($dep['exclude'])) { - if (!is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); - } + return '1.0'; + } + + function getChannel() + { + if (isset($this->_packagefile)) { + return $this->_packagefile->getChannel(); + } elseif (isset($this->_downloadURL['info'])) { + return $this->_downloadURL['info']->getChannel(); } - if (isset($dep['min'])) { - if (!version_compare($version, $dep['min'], '>=')) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires PHP' . - $extra . ', installed version is ' . $version); - } + return false; + } - return $this->warning('warning: %s requires PHP' . - $extra . ', installed version is ' . $version); - } + function getURI() + { + if (isset($this->_packagefile)) { + return $this->_packagefile->getURI(); + } elseif (isset($this->_downloadURL['info'])) { + return $this->_downloadURL['info']->getURI(); } - if (isset($dep['max'])) { - if (!version_compare($version, $dep['max'], '<=')) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires PHP' . - $extra . ', installed version is ' . $version); - } + return false; + } - return $this->warning('warning: %s requires PHP' . - $extra . ', installed version is ' . $version); - } + function getVersion() + { + if (isset($this->_packagefile)) { + return $this->_packagefile->getVersion(); + } elseif (isset($this->_downloadURL['version'])) { + return $this->_downloadURL['version']; } - if (isset($dep['exclude'])) { - foreach ($dep['exclude'] as $exclude) { - if (version_compare($version, $exclude, '==')) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s is not compatible with PHP version ' . - $exclude); - } + return false; + } - return $this->warning( - 'warning: %s is not compatible with PHP version ' . - $exclude); - } - } + function isCompatible($pf) + { + if (isset($this->_packagefile)) { + return $this->_packagefile->isCompatible($pf); + } elseif (isset($this->_downloadURL['info'])) { + return $this->_downloadURL['info']->isCompatible($pf); } return true; } - /** - * This makes unit-testing a heck of a lot easier - */ - function getPEARVersion() + function setGroup($group) { - return '1.8.0'; + $this->_parsedname['group'] = $group; } - function validatePearinstallerDependency($dep) + function getGroup() { - $pearversion = $this->getPEARVersion(); - $extra = $this->_getExtraString($dep); - if (isset($dep['exclude'])) { - if (!is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); - } + if (isset($this->_parsedname['group'])) { + return $this->_parsedname['group']; } - if (version_compare($pearversion, $dep['min'], '<')) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires PEAR Installer' . $extra . - ', installed version is ' . $pearversion); + return ''; + } + + function isExtension($name) + { + if (isset($this->_packagefile)) { + return $this->_packagefile->isExtension($name); + } elseif (isset($this->_downloadURL['info'])) { + if ($this->_downloadURL['info']->getPackagexmlVersion() == '2.0') { + return $this->_downloadURL['info']->getProvidesExtension() == $name; } - return $this->warning('warning: %s requires PEAR Installer' . $extra . - ', installed version is ' . $pearversion); + return false; } - if (isset($dep['max'])) { - if (version_compare($pearversion, $dep['max'], '>')) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires PEAR Installer' . $extra . - ', installed version is ' . $pearversion); - } + return false; + } - return $this->warning('warning: %s requires PEAR Installer' . $extra . - ', installed version is ' . $pearversion); + function getDeps() + { + if (isset($this->_packagefile)) { + $ver = $this->_packagefile->getPackagexmlVersion(); + if (version_compare($ver, '2.0', '>=')) { + return $this->_packagefile->getDeps(true); } - } - if (isset($dep['exclude'])) { - if (!isset($dep['exclude'][0])) { - $dep['exclude'] = array($dep['exclude']); + return $this->_packagefile->getDeps(); + } elseif (isset($this->_downloadURL['info'])) { + $ver = $this->_downloadURL['info']->getPackagexmlVersion(); + if (version_compare($ver, '2.0', '>=')) { + return $this->_downloadURL['info']->getDeps(true); } - foreach ($dep['exclude'] as $exclude) { - if (version_compare($exclude, $pearversion, '==')) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s is not compatible with PEAR Installer ' . - 'version ' . $exclude); - } - - return $this->warning('warning: %s is not compatible with PEAR ' . - 'Installer version ' . $exclude); - } - } + return $this->_downloadURL['info']->getDeps(); } - return true; - } - - function validateSubpackageDependency($dep, $required, $params) - { - return $this->validatePackageDependency($dep, $required, $params); + return array(); } /** - * @param array dependency information (2.0 format) - * @param boolean whether this is a required dependency - * @param array a list of downloaded packages to be installed, if any - * @param boolean if true, then deps on pear.php.net that fail will also check - * against pecl.php.net packages to accomodate extensions that have - * moved to pecl.php.net from pear.php.net + * @param array Parsed array from {@link PEAR_Registry::parsePackageName()} or a dependency + * returned from getDepDownloadURL() */ - function validatePackageDependency($dep, $required, $params, $depv1 = false) + function isEqual($param) { - if ($this->_state != PEAR_VALIDATE_INSTALLING && - $this->_state != PEAR_VALIDATE_DOWNLOADING) { - return true; + if (is_object($param)) { + $channel = $param->getChannel(); + $package = $param->getPackage(); + if ($param->getURI()) { + $param = array( + 'channel' => $param->getChannel(), + 'package' => $param->getPackage(), + 'version' => $param->getVersion(), + 'uri' => $param->getURI(), + ); + } else { + $param = array( + 'channel' => $param->getChannel(), + 'package' => $param->getPackage(), + 'version' => $param->getVersion(), + ); + } + } else { + if (isset($param['uri'])) { + if ($this->getChannel() != '__uri') { + return false; + } + return $param['uri'] == $this->getURI(); + } + + $package = isset($param['package']) ? $param['package'] : $param['info']->getPackage(); + $channel = isset($param['channel']) ? $param['channel'] : $param['info']->getChannel(); + if (isset($param['rel'])) { + if (!class_exists('PEAR_Dependency2')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Dependency2.php'; + } + + $newdep = PEAR_Dependency2::normalizeDep($param); + $newdep = $newdep[0]; + } elseif (isset($param['min'])) { + $newdep = $param; + } } - if (isset($dep['providesextension'])) { - if ($this->extension_loaded($dep['providesextension'])) { - $save = $dep; - $subdep = $dep; - $subdep['name'] = $subdep['providesextension']; - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $ret = $this->validateExtensionDependency($subdep, $required); - PEAR::popErrorHandling(); - if (!PEAR::isError($ret)) { - return true; + if (isset($newdep)) { + if (!isset($newdep['min'])) { + $newdep['min'] = '0'; + } + + if (!isset($newdep['max'])) { + $newdep['max'] = '100000000000000000000'; + } + + // use magic to support pecl packages suddenly jumping to the pecl channel + // we need to support both dependency possibilities + if ($channel == 'pear.php.net' && $this->getChannel() == 'pecl.php.net') { + if ($package == $this->getPackage()) { + $channel = 'pecl.php.net'; + } + } + if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') { + if ($package == $this->getPackage()) { + $channel = 'pear.php.net'; } } + + return (strtolower($package) == strtolower($this->getPackage()) && + $channel == $this->getChannel() && + version_compare($newdep['min'], $this->getVersion(), '<=') && + version_compare($newdep['max'], $this->getVersion(), '>=')); } - if ($this->_state == PEAR_VALIDATE_INSTALLING) { - return $this->_validatePackageInstall($dep, $required, $depv1); + // use magic to support pecl packages suddenly jumping to the pecl channel + if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') { + if (strtolower($package) == strtolower($this->getPackage())) { + $channel = 'pear.php.net'; + } } - if ($this->_state == PEAR_VALIDATE_DOWNLOADING) { - return $this->_validatePackageDownload($dep, $required, $params, $depv1); + if (isset($param['version'])) { + return (strtolower($package) == strtolower($this->getPackage()) && + $channel == $this->getChannel() && + $param['version'] == $this->getVersion()); } + + return strtolower($package) == strtolower($this->getPackage()) && + $channel == $this->getChannel(); } - function _validatePackageDownload($dep, $required, $params, $depv1 = false) + function isInstalled($dep, $oper = '==') { - $dep['package'] = $dep['name']; - if (isset($dep['uri'])) { - $dep['channel'] = '__uri'; + if (!$dep) { + return false; } - $depname = $this->_registry->parsedPackageNameToString($dep, true); - $found = false; - foreach ($params as $param) { - if ($param->isEqual( - array('package' => $dep['name'], - 'channel' => $dep['channel']))) { - $found = true; - break; - } - - if ($depv1 && $dep['channel'] == 'pear.php.net') { - if ($param->isEqual( - array('package' => $dep['name'], - 'channel' => 'pecl.php.net'))) { - $found = true; - break; - } - } + if ($oper != 'ge' && $oper != 'gt' && $oper != 'has' && $oper != '==') { + return false; } - if (!$found && isset($dep['providesextension'])) { - foreach ($params as $param) { - if ($param->isExtension($dep['providesextension'])) { - $found = true; - break; - } + if (is_object($dep)) { + $package = $dep->getPackage(); + $channel = $dep->getChannel(); + if ($dep->getURI()) { + $dep = array( + 'uri' => $dep->getURI(), + 'version' => $dep->getVersion(), + ); + } else { + $dep = array( + 'version' => $dep->getVersion(), + ); } - } - - if ($found) { - $version = $param->getVersion(); - $installed = false; - $downloaded = true; } else { - if ($this->_registry->packageExists($dep['name'], $dep['channel'])) { - $installed = true; - $downloaded = false; - $version = $this->_registry->packageinfo($dep['name'], 'version', - $dep['channel']); + if (isset($dep['uri'])) { + $channel = '__uri'; + $package = $dep['dep']['name']; } else { - if ($dep['channel'] == 'pecl.php.net' && $this->_registry->packageExists($dep['name'], - 'pear.php.net')) { - $installed = true; - $downloaded = false; - $version = $this->_registry->packageinfo($dep['name'], 'version', - 'pear.php.net'); - } else { - $version = 'not installed or downloaded'; - $installed = false; - $downloaded = false; - } + $channel = $dep['info']->getChannel(); + $package = $dep['info']->getPackage(); } } - $extra = $this->_getExtraString($dep); - if (isset($dep['exclude']) && !is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); + $options = $this->_downloader->getOptions(); + $test = $this->_installRegistry->packageExists($package, $channel); + if (!$test && $channel == 'pecl.php.net') { + // do magic to allow upgrading from old pecl packages to new ones + $test = $this->_installRegistry->packageExists($package, 'pear.php.net'); + $channel = 'pear.php.net'; } - if (!isset($dep['min']) && !isset($dep['max']) && - !isset($dep['recommended']) && !isset($dep['exclude']) - ) { - if ($installed || $downloaded) { - $installed = $installed ? 'installed' : 'downloaded'; - if (isset($dep['conflicts'])) { - $rest = ''; - if ($version) { - $rest = ", $installed version is " . $version; - } - - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s conflicts with package "' . $depname . '"' . $extra . $rest); - } + if ($test) { + if (isset($dep['uri'])) { + if ($this->_installRegistry->packageInfo($package, 'uri', '__uri') == $dep['uri']) { + return true; + } + } - return $this->warning('warning: %s conflicts with package "' . $depname . '"' . $extra . $rest); + if (isset($options['upgrade'])) { + $packageVersion = $this->_installRegistry->packageInfo($package, 'version', $channel); + if (version_compare($packageVersion, $dep['version'], '>=')) { + return true; } - return true; + return false; } - if (isset($dep['conflicts'])) { - return true; + return true; + } + + return false; + } + + /** + * Detect duplicate package names with differing versions + * + * If a user requests to install Date 1.4.6 and Date 1.4.7, + * for instance, this is a logic error. This method + * detects this situation. + * + * @param array $params array of PEAR_Downloader_Package objects + * @param array $errorparams empty array + * @return array array of stupid duplicated packages in PEAR_Downloader_Package obejcts + */ + function detectStupidDuplicates($params, &$errorparams) + { + $existing = array(); + foreach ($params as $i => $param) { + $package = $param->getPackage(); + $channel = $param->getChannel(); + $group = $param->getGroup(); + if (!isset($existing[$channel . '/' . $package])) { + $existing[$channel . '/' . $package] = array(); } - if ($required) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires package "' . $depname . '"' . $extra); + if (!isset($existing[$channel . '/' . $package][$group])) { + $existing[$channel . '/' . $package][$group] = array(); + } + + $existing[$channel . '/' . $package][$group][] = $i; + } + + $indices = array(); + foreach ($existing as $package => $groups) { + foreach ($groups as $group => $dupes) { + if (count($dupes) > 1) { + $indices = $indices + $dupes; } + } + } - return $this->warning('warning: %s requires package "' . $depname . '"' . $extra); + $indices = array_unique($indices); + foreach ($indices as $index) { + $errorparams[] = $params[$index]; + } + + return count($errorparams); + } + + /** + * @param array + * @param bool ignore install groups - for final removal of dupe packages + * @static + */ + function removeDuplicates(&$params, $ignoreGroups = false) + { + $pnames = array(); + foreach ($params as $i => $param) { + if (!$param) { + continue; } - return $this->warning('%s can optionally use package "' . $depname . '"' . $extra); + if ($param->getPackage()) { + $group = $ignoreGroups ? '' : $param->getGroup(); + $pnames[$i] = $param->getChannel() . '/' . + $param->getPackage() . '-' . $param->getVersion() . '#' . $group; + } } - if (!$installed && !$downloaded) { - if (isset($dep['conflicts'])) { - return true; + $pnames = array_unique($pnames); + $unset = array_diff(array_keys($params), array_keys($pnames)); + $testp = array_flip($pnames); + foreach ($params as $i => $param) { + if (!$param) { + $unset[] = $i; + continue; } - if ($required) { - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires package "' . $depname . '"' . $extra); - } + if (!is_a($param, 'PEAR_Downloader_Package')) { + $unset[] = $i; + continue; + } - return $this->warning('warning: %s requires package "' . $depname . '"' . $extra); + $group = $ignoreGroups ? '' : $param->getGroup(); + if (!isset($testp[$param->getChannel() . '/' . $param->getPackage() . '-' . + $param->getVersion() . '#' . $group])) { + $unset[] = $i; } + } - return $this->warning('%s can optionally use package "' . $depname . '"' . $extra); + foreach ($unset as $i) { + unset($params[$i]); } - $fail = false; - if (isset($dep['min']) && version_compare($version, $dep['min'], '<')) { - $fail = true; + $ret = array(); + foreach ($params as $i => $param) { + $ret[] = &$params[$i]; } - if (isset($dep['max']) && version_compare($version, $dep['max'], '>')) { - $fail = true; + $params = array(); + foreach ($ret as $i => $param) { + $params[] = &$ret[$i]; } + } - if ($fail && !isset($dep['conflicts'])) { - $installed = $installed ? 'installed' : 'downloaded'; - $dep['package'] = $dep['name']; - $dep = $this->_registry->parsedPackageNameToString($dep, true); - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s requires package "' . $depname . '"' . - $extra . ", $installed version is " . $version); + function explicitState() + { + return $this->_explicitState; + } + + function setExplicitState($s) + { + $this->_explicitState = $s; + } + + /** + * @static + */ + function mergeDependencies(&$params) + { + $bundles = $newparams = array(); + foreach ($params as $i => $param) { + if (!$param->isBundle()) { + continue; } - return $this->warning('warning: %s requires package "' . $depname . '"' . - $extra . ", $installed version is " . $version); - } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail && - isset($dep['conflicts']) && !isset($dep['exclude'])) { - $installed = $installed ? 'installed' : 'downloaded'; - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s conflicts with package "' . $depname . '"' . $extra . - ", $installed version is " . $version); + $bundles[] = $i; + $pf = &$param->getPackageFile(); + $newdeps = array(); + $contents = $pf->getBundledPackages(); + if (!is_array($contents)) { + $contents = array($contents); } - return $this->warning('warning: %s conflicts with package "' . $depname . '"' . - $extra . ", $installed version is " . $version); - } + foreach ($contents as $file) { + $filecontents = $pf->getFileContents($file); + $dl = &$param->getDownloader(); + $options = $dl->getOptions(); + if (PEAR::isError($dir = $dl->getDownloadDir())) { + return $dir; + } - if (isset($dep['exclude'])) { - $installed = $installed ? 'installed' : 'downloaded'; - foreach ($dep['exclude'] as $exclude) { - if (version_compare($version, $exclude, '==') && !isset($dep['conflicts'])) { - if (!isset($this->_options['nodeps']) && - !isset($this->_options['force']) - ) { - return $this->raiseError('%s is not compatible with ' . - $installed . ' package "' . - $depname . '" version ' . - $exclude); - } + $fp = @fopen($dir . DIRECTORY_SEPARATOR . $file, 'wb'); + if (!$fp) { + continue; + } - return $this->warning('warning: %s is not compatible with ' . - $installed . ' package "' . - $depname . '" version ' . - $exclude); - } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) { - $installed = $installed ? 'installed' : 'downloaded'; - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('%s conflicts with package "' . $depname . '"' . - $extra . ", $installed version is " . $version); + fwrite($fp, $filecontents, strlen($filecontents)); + fclose($fp); + if ($s = $params[$i]->explicitState()) { + $obj->setExplicitState($s); + } + + $obj = &new PEAR_Downloader_Package($params[$i]->getDownloader()); + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + if (PEAR::isError($dir = $dl->getDownloadDir())) { + PEAR::popErrorHandling(); + return $dir; + } + + $e = $obj->_fromFile($a = $dir . DIRECTORY_SEPARATOR . $file); + PEAR::popErrorHandling(); + if (PEAR::isError($e)) { + if (!isset($options['soft'])) { + $dl->log(0, $e->getMessage()); } + continue; + } - return $this->warning('warning: %s conflicts with package "' . $depname . '"' . - $extra . ", $installed version is " . $version); + $j = &$obj; + if (!PEAR_Downloader_Package::willDownload($j, + array_merge($params, $newparams)) && !$param->isInstalled($j)) { + $newparams[] = &$j; } } } - if (isset($dep['recommended'])) { - $installed = $installed ? 'installed' : 'downloaded'; - if (version_compare($version, $dep['recommended'], '==')) { - return true; + foreach ($bundles as $i) { + unset($params[$i]); // remove bundles - only their contents matter for installation + } + + PEAR_Downloader_Package::removeDuplicates($params); // strip any unset indices + if (count($newparams)) { // add in bundled packages for install + foreach ($newparams as $i => $unused) { + $params[] = &$newparams[$i]; } + $newparams = array(); + } - if (!$found && $installed) { - $param = $this->_registry->getPackage($dep['name'], $dep['channel']); + foreach ($params as $i => $param) { + $newdeps = array(); + foreach ($param->_downloadDeps as $dep) { + $merge = array_merge($params, $newparams); + if (!PEAR_Downloader_Package::willDownload($dep, $merge) + && !$param->isInstalled($dep) + ) { + $newdeps[] = $dep; + } else { + //var_dump($dep); + // detect versioning conflicts here + } } - if ($param) { - $found = false; - foreach ($params as $parent) { - if ($parent->isEqual($this->_currentPackage)) { - $found = true; - break; - } + // convert the dependencies into PEAR_Downloader_Package objects for the next time around + $params[$i]->_downloadDeps = array(); + foreach ($newdeps as $dep) { + $obj = &new PEAR_Downloader_Package($params[$i]->getDownloader()); + if ($s = $params[$i]->explicitState()) { + $obj->setExplicitState($s); } - if ($found) { - if ($param->isCompatible($parent)) { - return true; + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $e = $obj->fromDepURL($dep); + PEAR::popErrorHandling(); + if (PEAR::isError($e)) { + if (!isset($options['soft'])) { + $obj->_downloader->log(0, $e->getMessage()); } - } else { // this is for validPackage() calls - $parent = $this->_registry->getPackage($this->_currentPackage['package'], - $this->_currentPackage['channel']); - if ($parent !== null && $param->isCompatible($parent)) { - return true; + continue; + } + + $e = $obj->detectDependencies($params); + if (PEAR::isError($e)) { + if (!isset($options['soft'])) { + $obj->_downloader->log(0, $e->getMessage()); } } - } - if (!isset($this->_options['nodeps']) && !isset($this->_options['force']) && - !isset($this->_options['loose']) - ) { - return $this->raiseError('%s dependency package "' . $depname . - '" ' . $installed . ' version ' . $version . - ' is not the recommended version ' . $dep['recommended'] . - ', but may be compatible, use --force to install'); + $j = &$obj; + $newparams[] = &$j; } + } - return $this->warning('warning: %s dependency package "' . $depname . - '" ' . $installed . ' version ' . $version . - ' is not the recommended version ' . $dep['recommended']); + if (count($newparams)) { + foreach ($newparams as $i => $unused) { + $params[] = &$newparams[$i]; + } + return true; } - return true; + return false; } - function _validatePackageInstall($dep, $required, $depv1 = false) - { - return $this->_validatePackageDownload($dep, $required, array(), $depv1); - } /** - * Verify that uninstalling packages passed in to command line is OK. - * - * @param PEAR_Installer $dl - * @return PEAR_Error|true + * @static */ - function validatePackageUninstall(&$dl) + function willDownload($param, $params) { - if (PEAR::isError($this->_dependencydb)) { - return $this->_dependencydb; + if (!is_array($params)) { + return false; } - $params = array(); - // construct an array of "downloaded" packages to fool the package dependency checker - // into using these to validate uninstalls of circular dependencies - $downloaded = &$dl->getUninstallPackages(); - foreach ($downloaded as $i => $pf) { - if (!class_exists('PEAR_Downloader_Package')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Downloader/Package.php'; + foreach ($params as $obj) { + if ($obj->isEqual($param)) { + return true; } - $dp = &new PEAR_Downloader_Package($dl); - $dp->setPackageFile($downloaded[$i]); - $params[$i] = &$dp; } - // check cache - $memyselfandI = strtolower($this->_currentPackage['channel']) . '/' . - strtolower($this->_currentPackage['package']); - if (isset($dl->___uninstall_package_cache)) { - $badpackages = $dl->___uninstall_package_cache; - if (isset($badpackages[$memyselfandI]['warnings'])) { - foreach ($badpackages[$memyselfandI]['warnings'] as $warning) { - $dl->log(0, $warning[0]); + return false; + } + + /** + * For simpler unit-testing + * @param PEAR_Config + * @param int + * @param string + */ + function &getPackagefileObject(&$c, $d, $t = false) + { + $a = &new PEAR_PackageFile($c, $d, $t); + return $a; + } + + + /** + * This will retrieve from a local file if possible, and parse out + * a group name as well. The original parameter will be modified to reflect this. + * @param string|array can be a parsed package name as well + * @access private + */ + function _fromFile(&$param) + { + $saveparam = $param; + if (is_string($param)) { + if (!@file_exists($param)) { + $test = explode('#', $param); + $group = array_pop($test); + if (@file_exists(implode('#', $test))) { + $this->setGroup($group); + $param = implode('#', $test); + $this->_explicitGroup = true; } } - if (isset($badpackages[$memyselfandI]['errors'])) { - foreach ($badpackages[$memyselfandI]['errors'] as $error) { - if (is_array($error)) { - $dl->log(0, $error[0]); - } else { - $dl->log(0, $error->getMessage()); + if (@is_file($param)) { + $this->_type = 'local'; + $options = $this->_downloader->getOptions(); + if (isset($options['downloadonly'])) { + $pkg = &$this->getPackagefileObject($this->_config, + $this->_downloader->_debug); + } else { + if (PEAR::isError($dir = $this->_downloader->getDownloadDir())) { + return $dir; } + $pkg = &$this->getPackagefileObject($this->_config, + $this->_downloader->_debug, $dir); } - - if (isset($this->_options['nodeps']) || isset($this->_options['force'])) { - return $this->warning( - 'warning: %s should not be uninstalled, other installed packages depend ' . - 'on this package'); + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $pf = &$pkg->fromAnyFile($param, PEAR_VALIDATE_INSTALLING); + PEAR::popErrorHandling(); + if (PEAR::isError($pf)) { + $this->_valid = false; + $param = $saveparam; + return $pf; } - - return $this->raiseError( - '%s cannot be uninstalled, other installed packages depend on this package'); + $this->_packagefile = &$pf; + if (!$this->getGroup()) { + $this->setGroup('default'); // install the default dependency group + } + return $this->_valid = true; } - - return true; } + $param = $saveparam; + return $this->_valid = false; + } - // first, list the immediate parents of each package to be uninstalled - $perpackagelist = array(); - $allparents = array(); - foreach ($params as $i => $param) { - $a = array( - 'channel' => strtolower($param->getChannel()), - 'package' => strtolower($param->getPackage()) - ); + function _fromUrl($param, $saveparam = '') + { + if (!is_array($param) && (preg_match('#^(http|https|ftp)://#', $param))) { + $options = $this->_downloader->getOptions(); + $this->_type = 'url'; + $callback = $this->_downloader->ui ? + array(&$this->_downloader, '_downloadCallback') : null; + $this->_downloader->pushErrorHandling(PEAR_ERROR_RETURN); + if (PEAR::isError($dir = $this->_downloader->getDownloadDir())) { + $this->_downloader->popErrorHandling(); + return $dir; + } - $deps = $this->_dependencydb->getDependentPackages($a); - if ($deps) { - foreach ($deps as $d) { - $pardeps = $this->_dependencydb->getDependencies($d); - foreach ($pardeps as $dep) { - if (strtolower($dep['dep']['channel']) == $a['channel'] && - strtolower($dep['dep']['name']) == $a['package']) { - if (!isset($perpackagelist[$a['channel'] . '/' . $a['package']])) { - $perpackagelist[$a['channel'] . '/' . $a['package']] = array(); - } - $perpackagelist[$a['channel'] . '/' . $a['package']][] - = array($d['channel'] . '/' . $d['package'], $dep); - if (!isset($allparents[$d['channel'] . '/' . $d['package']])) { - $allparents[$d['channel'] . '/' . $d['package']] = array(); - } - if (!isset($allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']])) { - $allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']] = array(); - } - $allparents[$d['channel'] . '/' . $d['package']] - [$a['channel'] . '/' . $a['package']][] - = array($d, $dep); - } - } + $this->_downloader->log(3, 'Downloading "' . $param . '"'); + $file = $this->_downloader->downloadHttp($param, $this->_downloader->ui, + $dir, $callback, null, false, $this->getChannel()); + $this->_downloader->popErrorHandling(); + if (PEAR::isError($file)) { + if (!empty($saveparam)) { + $saveparam = ", cannot download \"$saveparam\""; } + $err = PEAR::raiseError('Could not download from "' . $param . + '"' . $saveparam . ' (' . $file->getMessage() . ')'); + return $err; } - } - // next, remove any packages from the parents list that are not installed - $remove = array(); - foreach ($allparents as $parent => $d1) { - foreach ($d1 as $d) { - if ($this->_registry->packageExists($d[0][0]['package'], $d[0][0]['channel'])) { - continue; + if ($this->_rawpackagefile) { + require_once 'phar://install-pear-nozlib.phar/' . 'Archive/Tar.php'; + $tar = &new Archive_Tar($file); + $packagexml = $tar->extractInString('package2.xml'); + if (!$packagexml) { + $packagexml = $tar->extractInString('package.xml'); } - $remove[$parent] = true; - } - } - // next remove any packages from the parents list that are not passed in for - // uninstallation - foreach ($allparents as $parent => $d1) { - foreach ($d1 as $d) { - foreach ($params as $param) { - if (strtolower($param->getChannel()) == $d[0][0]['channel'] && - strtolower($param->getPackage()) == $d[0][0]['package']) { - // found it - continue 3; + if (str_replace(array("\n", "\r"), array('',''), $packagexml) != + str_replace(array("\n", "\r"), array('',''), $this->_rawpackagefile)) { + if ($this->getChannel() != 'pear.php.net') { + return PEAR::raiseError('CRITICAL ERROR: package.xml downloaded does ' . + 'not match value returned from xml-rpc'); } + + // be more lax for the existing PEAR packages that have not-ok + // characters in their package.xml + $this->_downloader->log(0, 'CRITICAL WARNING: The "' . + $this->getPackage() . '" package has invalid characters in its ' . + 'package.xml. The next version of PEAR may not be able to install ' . + 'this package for security reasons. Please open a bug report at ' . + 'http://pear.php.net/package/' . $this->getPackage() . '/bugs'); } - $remove[$parent] = true; } - } - // remove all packages whose dependencies fail - // save which ones failed for error reporting - $badchildren = array(); - do { - $fail = false; - foreach ($remove as $package => $unused) { - if (!isset($allparents[$package])) { - continue; + // whew, download worked! + if (isset($options['downloadonly'])) { + $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->debug); + } else { + $dir = $this->_downloader->getDownloadDir(); + if (PEAR::isError($dir)) { + return $dir; } + $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->debug, $dir); + } - foreach ($allparents[$package] as $kid => $d1) { - foreach ($d1 as $depinfo) { - if ($depinfo[1]['type'] != 'optional') { - if (isset($badchildren[$kid])) { - continue; - } - $badchildren[$kid] = true; - $remove[$kid] = true; - $fail = true; - continue 2; + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $pf = &$pkg->fromAnyFile($file, PEAR_VALIDATE_INSTALLING); + PEAR::popErrorHandling(); + if (PEAR::isError($pf)) { + if (is_array($pf->getUserInfo())) { + foreach ($pf->getUserInfo() as $err) { + if (is_array($err)) { + $err = $err['message']; + } + + if (!isset($options['soft'])) { + $this->_downloader->log(0, "Validation Error: $err"); } } } - if ($fail) { - // start over, we removed some children - continue 2; - } - } - } while ($fail); - // next, construct the list of packages that can't be uninstalled - $badpackages = array(); - $save = $this->_currentPackage; - foreach ($perpackagelist as $package => $packagedeps) { - foreach ($packagedeps as $parent) { - if (!isset($remove[$parent[0]])) { - continue; + if (!isset($options['soft'])) { + $this->_downloader->log(0, $pf->getMessage()); } - $packagename = $this->_registry->parsePackageName($parent[0]); - $packagename['channel'] = $this->_registry->channelAlias($packagename['channel']); - $pa = $this->_registry->getPackage($packagename['package'], $packagename['channel']); - $packagename['package'] = $pa->getPackage(); - $this->_currentPackage = $packagename; - // parent is not present in uninstall list, make sure we can actually - // uninstall it (parent dep is optional) - $parentname['channel'] = $this->_registry->channelAlias($parent[1]['dep']['channel']); - $pa = $this->_registry->getPackage($parent[1]['dep']['name'], $parent[1]['dep']['channel']); - $parentname['package'] = $pa->getPackage(); - $parent[1]['dep']['package'] = $parentname['package']; - $parent[1]['dep']['channel'] = $parentname['channel']; - if ($parent[1]['type'] == 'optional') { - $test = $this->_validatePackageUninstall($parent[1]['dep'], false, $dl); - if ($test !== true) { - $badpackages[$package]['warnings'][] = $test; - } - } else { - $test = $this->_validatePackageUninstall($parent[1]['dep'], true, $dl); - if ($test !== true) { - $badpackages[$package]['errors'][] = $test; - } - } + ///FIXME need to pass back some error code that we can use to match with to cancel all further operations + /// At least stop all deps of this package from being installed + $out = $saveparam ? $saveparam : $param; + $err = PEAR::raiseError('Download of "' . $out . '" succeeded, but it is not a valid package archive'); + $this->_valid = false; + return $err; } + + $this->_packagefile = &$pf; + $this->setGroup('default'); // install the default dependency group + return $this->_valid = true; } - $this->_currentPackage = $save; - $dl->___uninstall_package_cache = $badpackages; - if (isset($badpackages[$memyselfandI])) { - if (isset($badpackages[$memyselfandI]['warnings'])) { - foreach ($badpackages[$memyselfandI]['warnings'] as $warning) { - $dl->log(0, $warning[0]); - } + return $this->_valid = false; + } + + /** + * + * @param string|array pass in an array of format + * array( + * 'package' => 'pname', + * ['channel' => 'channame',] + * ['version' => 'version',] + * ['state' => 'state',]) + * or a string of format [channame/]pname[-version|-state] + */ + function _fromString($param) + { + $options = $this->_downloader->getOptions(); + $channel = $this->_config->get('default_channel'); + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $pname = $this->_registry->parsePackageName($param, $channel); + PEAR::popErrorHandling(); + if (PEAR::isError($pname)) { + if ($pname->getCode() == 'invalid') { + $this->_valid = false; + return false; } - if (isset($badpackages[$memyselfandI]['errors'])) { - foreach ($badpackages[$memyselfandI]['errors'] as $error) { - if (is_array($error)) { - $dl->log(0, $error[0]); + if ($pname->getCode() == 'channel') { + $parsed = $pname->getUserInfo(); + if ($this->_downloader->discover($parsed['channel'])) { + if ($this->_config->get('auto_discover')) { + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $pname = $this->_registry->parsePackageName($param, $channel); + PEAR::popErrorHandling(); } else { - $dl->log(0, $error->getMessage()); - } - } - - if (isset($this->_options['nodeps']) || isset($this->_options['force'])) { - return $this->warning( - 'warning: %s should not be uninstalled, other installed packages depend ' . - 'on this package'); + if (!isset($options['soft'])) { + $this->_downloader->log(0, 'Channel "' . $parsed['channel'] . + '" is not initialized, use ' . + '"pear channel-discover ' . $parsed['channel'] . '" to initialize' . + 'or pear config-set auto_discover 1'); + } + } } - return $this->raiseError( - '%s cannot be uninstalled, other installed packages depend on this package'); - } - } + if (PEAR::isError($pname)) { + if (!isset($options['soft'])) { + $this->_downloader->log(0, $pname->getMessage()); + } - return true; - } + if (is_array($param)) { + $param = $this->_registry->parsedPackageNameToString($param); + } - function _validatePackageUninstall($dep, $required, $dl) - { - $depname = $this->_registry->parsedPackageNameToString($dep, true); - $version = $this->_registry->packageinfo($dep['package'], 'version', $dep['channel']); - if (!$version) { - return true; - } + $err = PEAR::raiseError('invalid package name/package file "' . $param . '"'); + $this->_valid = false; + return $err; + } + } else { + if (!isset($options['soft'])) { + $this->_downloader->log(0, $pname->getMessage()); + } - $extra = $this->_getExtraString($dep); - if (isset($dep['exclude']) && !is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); + $err = PEAR::raiseError('invalid package name/package file "' . $param . '"'); + $this->_valid = false; + return $err; + } } - if (isset($dep['conflicts'])) { - return true; // uninstall OK - these packages conflict (probably installed with --force) + if (!isset($this->_type)) { + $this->_type = 'rest'; } - if (!isset($dep['min']) && !isset($dep['max'])) { - if (!$required) { - return $this->warning('"' . $depname . '" can be optionally used by ' . - 'installed package %s' . $extra); - } + $this->_parsedname = $pname; + $this->_explicitState = isset($pname['state']) ? $pname['state'] : false; + $this->_explicitGroup = isset($pname['group']) ? true : false; - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError('"' . $depname . '" is required by ' . - 'installed package %s' . $extra); + $info = $this->_downloader->_getPackageDownloadUrl($pname); + if (PEAR::isError($info)) { + if ($info->getCode() != -976 && $pname['channel'] == 'pear.php.net') { + // try pecl + $pname['channel'] = 'pecl.php.net'; + if ($test = $this->_downloader->_getPackageDownloadUrl($pname)) { + if (!PEAR::isError($test)) { + $info = PEAR::raiseError($info->getMessage() . ' - package ' . + $this->_registry->parsedPackageNameToString($pname, true) . + ' can be installed with "pecl install ' . $pname['package'] . + '"'); + } else { + $pname['channel'] = 'pear.php.net'; + } + } else { + $pname['channel'] = 'pear.php.net'; + } } - return $this->warning('warning: "' . $depname . '" is required by ' . - 'installed package %s' . $extra); - } - - $fail = false; - if (isset($dep['min']) && version_compare($version, $dep['min'], '>=')) { - $fail = true; - } - - if (isset($dep['max']) && version_compare($version, $dep['max'], '<=')) { - $fail = true; + return $info; } - // we re-use this variable, preserve the original value - $saverequired = $required; - if (!$required) { - return $this->warning($depname . $extra . ' can be optionally used by installed package' . - ' "%s"'); + $this->_rawpackagefile = $info['raw']; + $ret = $this->_analyzeDownloadURL($info, $param, $pname); + if (PEAR::isError($ret)) { + return $ret; } - if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) { - return $this->raiseError($depname . $extra . ' is required by installed package' . - ' "%s"'); + if ($ret) { + $this->_downloadURL = $ret; + return $this->_valid = (bool) $ret; } - - return $this->raiseError('warning: ' . $depname . $extra . - ' is required by installed package "%s"'); } /** - * validate a downloaded package against installed packages - * - * As of PEAR 1.4.3, this will only validate - * - * @param array|PEAR_Downloader_Package|PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * $pkg package identifier (either - * array('package' => blah, 'channel' => blah) or an array with - * index 'info' referencing an object) - * @param PEAR_Downloader $dl - * @param array $params full list of packages to install - * @return true|PEAR_Error + * @param array output of package.getDownloadURL + * @param string|array|object information for detecting packages to be downloaded, and + * for errors + * @param array name information of the package + * @param array|null packages to be downloaded + * @param bool is this an optional dependency? + * @param bool is this any kind of dependency? + * @access private */ - function validatePackage($pkg, &$dl, $params = array()) + function _analyzeDownloadURL($info, $param, $pname, $params = null, $optional = false, + $isdependency = false) { - if (is_array($pkg) && isset($pkg['info'])) { - $deps = $this->_dependencydb->getDependentPackageDependencies($pkg['info']); - } else { - $deps = $this->_dependencydb->getDependentPackageDependencies($pkg); + if (!is_string($param) && PEAR_Downloader_Package::willDownload($param, $params)) { + return false; } - $fail = false; - if ($deps) { - if (!class_exists('PEAR_Downloader_Package')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Downloader/Package.php'; - } + if ($info === false) { + $saveparam = !is_string($param) ? ", cannot download \"$param\"" : ''; - $dp = &new PEAR_Downloader_Package($dl); - if (is_object($pkg)) { - $dp->setPackageFile($pkg); + // no releases exist + return PEAR::raiseError('No releases for package "' . + $this->_registry->parsedPackageNameToString($pname, true) . '" exist' . $saveparam); + } + + if (strtolower($info['info']->getChannel()) != strtolower($pname['channel'])) { + $err = false; + if ($pname['channel'] == 'pecl.php.net') { + if ($info['info']->getChannel() != 'pear.php.net') { + $err = true; + } + } elseif ($info['info']->getChannel() == 'pecl.php.net') { + if ($pname['channel'] != 'pear.php.net') { + $err = true; + } } else { - $dp->setDownloadURL($pkg); + $err = true; } - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - foreach ($deps as $channel => $info) { - foreach ($info as $package => $ds) { - foreach ($params as $packd) { - if (strtolower($packd->getPackage()) == strtolower($package) && - $packd->getChannel() == $channel) { - $dl->log(3, 'skipping installed package check of "' . - $this->_registry->parsedPackageNameToString( - array('channel' => $channel, 'package' => $package), - true) . - '", version "' . $packd->getVersion() . '" will be ' . - 'downloaded and installed'); - continue 2; // jump to next package - } - } + if ($err) { + return PEAR::raiseError('SECURITY ERROR: package in channel "' . $pname['channel'] . + '" retrieved another channel\'s name for download! ("' . + $info['info']->getChannel() . '")'); + } + } - foreach ($ds as $d) { - $checker = &new PEAR_Dependency2($this->_config, $this->_options, - array('channel' => $channel, 'package' => $package), $this->_state); - $dep = $d['dep']; - $required = $d['type'] == 'required'; - $ret = $checker->_validatePackageDownload($dep, $required, array(&$dp)); - if (is_array($ret)) { - $dl->log(0, $ret[0]); - } elseif (PEAR::isError($ret)) { - $dl->log(0, $ret->getMessage()); - $fail = true; - } - } + $preferred_state = $this->_config->get('preferred_state'); + if (!isset($info['url'])) { + $package_version = $this->_registry->packageInfo($info['info']->getPackage(), + 'version', $info['info']->getChannel()); + if ($this->isInstalled($info)) { + if ($isdependency && version_compare($info['version'], $package_version, '<=')) { + // ignore bogus errors of "failed to download dependency" + // if it is already installed and the one that would be + // downloaded is older or the same version (Bug #7219) + return false; } } - PEAR::popErrorHandling(); - } - if ($fail) { - return $this->raiseError( - '%s cannot be installed, conflicts with installed packages'); - } + if ($info['version'] === $package_version) { + if (!isset($options['soft'])) { + $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] . + '/' . $pname['package'] . '-' . $package_version. ', additionally the suggested version' . + ' (' . $package_version . ') is the same as the locally installed one.'); + } - return true; - } + return false; + } - /** - * validate a package.xml 1.0 dependency - */ - function validateDependency1($dep, $params = array()) - { - if (!isset($dep['optional'])) { - $dep['optional'] = 'no'; - } + if (version_compare($info['version'], $package_version, '<=')) { + if (!isset($options['soft'])) { + $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] . + '/' . $pname['package'] . '-' . $package_version . ', additionally the suggested version' . + ' (' . $info['version'] . ') is a lower version than the locally installed one (' . $package_version . ').'); + } - list($newdep, $type) = $this->normalizeDep($dep); - if (!$newdep) { - return $this->raiseError("Invalid Dependency"); - } + return false; + } - if (method_exists($this, "validate{$type}Dependency")) { - return $this->{"validate{$type}Dependency"}($newdep, $dep['optional'] == 'no', - $params, true); - } - } + $instead = ', will instead download version ' . $info['version'] . + ', stability "' . $info['info']->getState() . '"'; + // releases exist, but we failed to get any + if (isset($this->_downloader->_options['force'])) { + if (isset($pname['version'])) { + $vs = ', version "' . $pname['version'] . '"'; + } elseif (isset($pname['state'])) { + $vs = ', stability "' . $pname['state'] . '"'; + } elseif ($param == 'dependency') { + if (!class_exists('PEAR_Common')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Common.php'; + } - /** - * Convert a 1.0 dep into a 2.0 dep - */ - function normalizeDep($dep) - { - $types = array( - 'pkg' => 'Package', - 'ext' => 'Extension', - 'os' => 'Os', - 'php' => 'Php' - ); + if (!in_array($info['info']->getState(), + PEAR_Common::betterStates($preferred_state, true))) { + if ($optional) { + // don't spit out confusing error message + return $this->_downloader->_getPackageDownloadUrl( + array('package' => $pname['package'], + 'channel' => $pname['channel'], + 'version' => $info['version'])); + } + $vs = ' within preferred state "' . $preferred_state . + '"'; + } else { + if (!class_exists('PEAR_Dependency2')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Dependency2.php'; + } - if (!isset($types[$dep['type']])) { - return array(false, false); - } + if ($optional) { + // don't spit out confusing error message + return $this->_downloader->_getPackageDownloadUrl( + array('package' => $pname['package'], + 'channel' => $pname['channel'], + 'version' => $info['version'])); + } + $vs = PEAR_Dependency2::_getExtraString($pname); + $instead = ''; + } + } else { + $vs = ' within preferred state "' . $preferred_state . '"'; + } - $type = $types[$dep['type']]; + if (!isset($options['soft'])) { + $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] . + '/' . $pname['package'] . $vs . $instead); + } - $newdep = array(); - switch ($type) { - case 'Package' : - $newdep['channel'] = 'pear.php.net'; - case 'Extension' : - case 'Os' : - $newdep['name'] = $dep['name']; - break; - } + // download the latest release + return $this->_downloader->_getPackageDownloadUrl( + array('package' => $pname['package'], + 'channel' => $pname['channel'], + 'version' => $info['version'])); + } else { + if (isset($info['php']) && $info['php']) { + $err = PEAR::raiseError('Failed to download ' . + $this->_registry->parsedPackageNameToString( + array('channel' => $pname['channel'], + 'package' => $pname['package']), + true) . + ', latest release is version ' . $info['php']['v'] . + ', but it requires PHP version "' . + $info['php']['m'] . '", use "' . + $this->_registry->parsedPackageNameToString( + array('channel' => $pname['channel'], 'package' => $pname['package'], + 'version' => $info['php']['v'])) . '" to install', + PEAR_DOWNLOADER_PACKAGE_PHPVERSION); + return $err; + } - $dep['rel'] = PEAR_Dependency2::signOperator($dep['rel']); - switch ($dep['rel']) { - case 'has' : - return array($newdep, $type); - break; - case 'not' : - $newdep['conflicts'] = true; - break; - case '>=' : - case '>' : - $newdep['min'] = $dep['version']; - if ($dep['rel'] == '>') { - $newdep['exclude'] = $dep['version']; + // construct helpful error message + if (isset($pname['version'])) { + $vs = ', version "' . $pname['version'] . '"'; + } elseif (isset($pname['state'])) { + $vs = ', stability "' . $pname['state'] . '"'; + } elseif ($param == 'dependency') { + if (!class_exists('PEAR_Common')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Common.php'; + } + + if (!in_array($info['info']->getState(), + PEAR_Common::betterStates($preferred_state, true))) { + if ($optional) { + // don't spit out confusing error message, and don't die on + // optional dep failure! + return $this->_downloader->_getPackageDownloadUrl( + array('package' => $pname['package'], + 'channel' => $pname['channel'], + 'version' => $info['version'])); + } + $vs = ' within preferred state "' . $preferred_state . '"'; + } else { + if (!class_exists('PEAR_Dependency2')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Dependency2.php'; + } + + if ($optional) { + // don't spit out confusing error message, and don't die on + // optional dep failure! + return $this->_downloader->_getPackageDownloadUrl( + array('package' => $pname['package'], + 'channel' => $pname['channel'], + 'version' => $info['version'])); + } + $vs = PEAR_Dependency2::_getExtraString($pname); + } + } else { + $vs = ' within preferred state "' . $this->_downloader->config->get('preferred_state') . '"'; } - break; - case '<=' : - case '<' : - $newdep['max'] = $dep['version']; - if ($dep['rel'] == '<') { - $newdep['exclude'] = $dep['version']; + + $options = $this->_downloader->getOptions(); + // this is only set by the "download-all" command + if (isset($options['ignorepreferred_state'])) { + $err = PEAR::raiseError( + 'Failed to download ' . $this->_registry->parsedPackageNameToString( + array('channel' => $pname['channel'], 'package' => $pname['package']), + true) + . $vs . + ', latest release is version ' . $info['version'] . + ', stability "' . $info['info']->getState() . '", use "' . + $this->_registry->parsedPackageNameToString( + array('channel' => $pname['channel'], 'package' => $pname['package'], + 'version' => $info['version'])) . '" to install', + PEAR_DOWNLOADER_PACKAGE_STATE); + return $err; } - break; - case 'ne' : - case '!=' : - $newdep['min'] = '0'; - $newdep['max'] = '100000'; - $newdep['exclude'] = $dep['version']; - break; - case '==' : - $newdep['min'] = $dep['version']; - $newdep['max'] = $dep['version']; - break; - } - if ($type == 'Php') { - if (!isset($newdep['min'])) { - $newdep['min'] = '4.4.0'; - } - if (!isset($newdep['max'])) { - $newdep['max'] = '6.0.0'; + // Checks if the user has a package installed already and checks the release against + // the state against the installed package, this allows upgrades for packages + // with lower stability than the preferred_state + $stability = $this->_registry->packageInfo($pname['package'], 'stability', $pname['channel']); + if (!$this->isInstalled($info) + || !in_array($info['info']->getState(), PEAR_Common::betterStates($stability['release'], true)) + ) { + $err = PEAR::raiseError( + 'Failed to download ' . $this->_registry->parsedPackageNameToString( + array('channel' => $pname['channel'], 'package' => $pname['package']), + true) + . $vs . + ', latest release is version ' . $info['version'] . + ', stability "' . $info['info']->getState() . '", use "' . + $this->_registry->parsedPackageNameToString( + array('channel' => $pname['channel'], 'package' => $pname['package'], + 'version' => $info['version'])) . '" to install'); + return $err; + } } } - return array($newdep, $type); - } - - /** - * Converts text comparing operators to them sign equivalents - * - * Example: 'ge' to '>=' - * - * @access public - * @param string Operator - * @return string Sign equivalent - */ - function signOperator($operator) - { - switch($operator) { - case 'lt': return '<'; - case 'le': return '<='; - case 'gt': return '>'; - case 'ge': return '>='; - case 'eq': return '=='; - case 'ne': return '!='; - default: - return $operator; - } - } - function raiseError($msg) - { - if (isset($this->_options['ignore-errors'])) { - return $this->warning($msg); + if (isset($info['deprecated']) && $info['deprecated']) { + $this->_downloader->log(0, + 'WARNING: "' . + $this->_registry->parsedPackageNameToString( + array('channel' => $info['info']->getChannel(), + 'package' => $info['info']->getPackage()), true) . + '" is deprecated in favor of "' . + $this->_registry->parsedPackageNameToString($info['deprecated'], true) . + '"'); } - return PEAR::raiseError(sprintf($msg, $this->_registry->parsedPackageNameToString( - $this->_currentPackage, true))); - } - - function warning($msg) - { - return array(sprintf($msg, $this->_registry->parsedPackageNameToString( - $this->_currentPackage, true))); + return $info; } } + * Since version PEAR1.3.2, ErrorStack no longer instantiates an exception class. This can + * still be done quite handily in an error callback or by manipulating the returned array + * @category Debugging + * @package PEAR_ErrorStack * @author Greg Beaver - * @copyright 1997-2009 The Authors + * @copyright 2004-2008 Greg Beaver * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: DependencyDB.php,v 1.44 2009/03/21 15:15:26 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 + * @version CVS: $Id: ErrorStack.php 276383 2009-02-24 23:39:37Z dufuz $ + * @link http://pear.php.net/package/PEAR_ErrorStack + */ + +/** + * Singleton storage + * + * Format: + *
+ * array(
+ *  'package1' => PEAR_ErrorStack object,
+ *  'package2' => PEAR_ErrorStack object,
+ *  ...
+ * )
+ * 
+ * @access private + * @global array $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] + */ +$GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] = array(); + +/** + * Global error callback (default) + * + * This is only used if set to non-false. * is the default callback for + * all packages, whereas specific packages may set a default callback + * for all instances, regardless of whether they are a singleton or not. + * + * To exclude non-singletons, only set the local callback for the singleton + * @see PEAR_ErrorStack::setDefaultCallback() + * @access private + * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] + */ +$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] = array( + '*' => false, +); + +/** + * Global Log object (default) + * + * This is only used if set to non-false. Use to set a default log object for + * all stacks, regardless of instantiation order or location + * @see PEAR_ErrorStack::setDefaultLogger() + * @access private + * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] */ +$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = false; /** - * Needed for error handling + * Global Overriding Callback + * + * This callback will override any error callbacks that specific loggers have set. + * Use with EXTREME caution + * @see PEAR_ErrorStack::staticPushCallback() + * @access private + * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] */ -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR.php'; -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Config.php'; +$GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array(); -$GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'] = array(); +/**#@+ + * One of four possible return values from the error Callback + * @see PEAR_ErrorStack::_errorCallback() + */ /** - * Track dependency relationships between installed packages - * @category pear - * @package PEAR - * @author Greg Beaver - * @author Tomas V.V.Cox - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 + * If this is returned, then the error will be both pushed onto the stack + * and logged. */ -class PEAR_DependencyDB -{ - // {{{ properties +define('PEAR_ERRORSTACK_PUSHANDLOG', 1); +/** + * If this is returned, then the error will only be pushed onto the stack, + * and not logged. + */ +define('PEAR_ERRORSTACK_PUSH', 2); +/** + * If this is returned, then the error will only be logged, but not pushed + * onto the error stack. + */ +define('PEAR_ERRORSTACK_LOG', 3); +/** + * If this is returned, then the error is completely ignored. + */ +define('PEAR_ERRORSTACK_IGNORE', 4); +/** + * If this is returned, then the error is logged and die() is called. + */ +define('PEAR_ERRORSTACK_DIE', 5); +/**#@-*/ - /** - * This is initialized by {@link setConfig()} - * @var PEAR_Config +/** + * Error code for an attempt to instantiate a non-class as a PEAR_ErrorStack in + * the singleton method. + */ +define('PEAR_ERRORSTACK_ERR_NONCLASS', 1); + +/** + * Error code for an attempt to pass an object into {@link PEAR_ErrorStack::getMessage()} + * that has no __toString() method + */ +define('PEAR_ERRORSTACK_ERR_OBJTOSTRING', 2); +/** + * Error Stack Implementation + * + * Usage: + * + * // global error stack + * $global_stack = &PEAR_ErrorStack::singleton('MyPackage'); + * // local error stack + * $local_stack = new PEAR_ErrorStack('MyPackage'); + * + * @author Greg Beaver + * @version 1.9.0 + * @package PEAR_ErrorStack + * @category Debugging + * @copyright 2004-2008 Greg Beaver + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: ErrorStack.php 276383 2009-02-24 23:39:37Z dufuz $ + * @link http://pear.php.net/package/PEAR_ErrorStack + */ +class PEAR_ErrorStack { + /** + * Errors are stored in the order that they are pushed on the stack. + * @since 0.4alpha Errors are no longer organized by error level. + * This renders pop() nearly unusable, and levels could be more easily + * handled in a callback anyway + * @var array * @access private */ - var $_config; + var $_errors = array(); + /** - * This is initialized by {@link setConfig()} - * @var PEAR_Registry + * Storage of errors by level. + * + * Allows easy retrieval and deletion of only errors from a particular level + * @since PEAR 1.4.0dev + * @var array * @access private */ - var $_registry; + var $_errorsByLevel = array(); + /** - * Filename of the dependency DB (usually .depdb) + * Package name this error stack represents * @var string - * @access private + * @access protected */ - var $_depdb = false; + var $_package; + /** - * File name of the lockfile (usually .depdblock) - * @var string + * Determines whether a PEAR_Error is thrown upon every error addition + * @var boolean * @access private */ - var $_lockfile = false; + var $_compat = false; + /** - * Open file resource for locking the lockfile - * @var resource|false + * If set to a valid callback, this will be used to generate the error + * message from the error code, otherwise the message passed in will be + * used + * @var false|string|array * @access private */ - var $_lockFp = false; + var $_msgCallback = false; + /** - * API version of this class, used to validate a file on-disk - * @var string - * @access private + * If set to a valid callback, this will be used to generate the error + * context for an error. For PHP-related errors, this will be a file + * and line number as retrieved from debug_backtrace(), but can be + * customized for other purposes. The error might actually be in a separate + * configuration file, or in a database query. + * @var false|string|array + * @access protected */ - var $_version = '1.0'; + var $_contextCallback = false; + /** - * Cached dependency database file - * @var array|null - * @access private + * If set to a valid callback, this will be called every time an error + * is pushed onto the stack. The return value will be used to determine + * whether to allow an error to be pushed or logged. + * + * The return value must be one an PEAR_ERRORSTACK_* constant + * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG + * @var false|string|array + * @access protected */ - var $_cache; - - // }}} - // {{{ & singleton() - + var $_errorCallback = array(); + /** - * Get a raw dependency database. Calls setConfig() and assertDepsDB() - * @param PEAR_Config - * @param string|false full path to the dependency database, or false to use default - * @return PEAR_DependencyDB|PEAR_Error + * PEAR::Log object for logging errors + * @var false|Log + * @access protected + */ + var $_logger = false; + + /** + * Error messages - designed to be overridden + * @var array + * @abstract + */ + var $_errorMsgs = array(); + + /** + * Set up a new error stack + * + * @param string $package name of the package this error stack represents + * @param callback $msgCallback callback used for error message generation + * @param callback $contextCallback callback used for context generation, + * defaults to {@link getFileLine()} + * @param boolean $throwPEAR_Error + */ + function PEAR_ErrorStack($package, $msgCallback = false, $contextCallback = false, + $throwPEAR_Error = false) + { + $this->_package = $package; + $this->setMessageCallback($msgCallback); + $this->setContextCallback($contextCallback); + $this->_compat = $throwPEAR_Error; + } + + /** + * Return a single error stack for this package. + * + * Note that all parameters are ignored if the stack for package $package + * has already been instantiated + * @param string $package name of the package this error stack represents + * @param callback $msgCallback callback used for error message generation + * @param callback $contextCallback callback used for context generation, + * defaults to {@link getFileLine()} + * @param boolean $throwPEAR_Error + * @param string $stackClass class to instantiate * @static + * @return PEAR_ErrorStack */ - function &singleton(&$config, $depdb = false) + function &singleton($package, $msgCallback = false, $contextCallback = false, + $throwPEAR_Error = false, $stackClass = 'PEAR_ErrorStack') { - $phpdir = $config->get('php_dir', null, 'pear.php.net'); - if (!isset($GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir])) { - $a = new PEAR_DependencyDB; - $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir] = &$a; - $a->setConfig($config, $depdb); - $e = $a->assertDepsDB(); - if (PEAR::isError($e)) { - return $e; + if (isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { + return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]; + } + if (!class_exists($stackClass)) { + if (function_exists('debug_backtrace')) { + $trace = debug_backtrace(); } + PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_NONCLASS, + 'exception', array('stackclass' => $stackClass), + 'stack class "%stackclass%" is not a valid class name (should be like PEAR_ErrorStack)', + false, $trace); } + $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package] = + new $stackClass($package, $msgCallback, $contextCallback, $throwPEAR_Error); - return $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir]; + return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]; } /** - * Set up the registry/location of dependency DB - * @param PEAR_Config|false - * @param string|false full path to the dependency database, or false to use default + * Internal error handler for PEAR_ErrorStack class + * + * Dies if the error is an exception (and would have died anyway) + * @access private */ - function setConfig(&$config, $depdb = false) + function _handleError($err) { - if (!$config) { - $this->_config = &PEAR_Config::singleton(); - } else { - $this->_config = &$config; - } - - $this->_registry = &$this->_config->getRegistry(); - if (!$depdb) { - $this->_depdb = $this->_config->get('php_dir', null, 'pear.php.net') . - DIRECTORY_SEPARATOR . '.depdb'; - } else { - $this->_depdb = $depdb; + if ($err['level'] == 'exception') { + $message = $err['message']; + if (isset($_SERVER['REQUEST_URI'])) { + echo '
'; + } else { + echo "\n"; + } + var_dump($err['context']); + die($message); } - - $this->_lockfile = dirname($this->_depdb) . DIRECTORY_SEPARATOR . '.depdblock'; } - // }}} - - function hasWriteAccess() + + /** + * Set up a PEAR::Log object for all error stacks that don't have one + * @param Log $log + * @static + */ + function setDefaultLogger(&$log) { - if (!file_exists($this->_depdb)) { - $dir = $this->_depdb; - while ($dir && $dir != '.') { - $dir = dirname($dir); // cd .. - if ($dir != '.' && file_exists($dir)) { - if (is_writeable($dir)) { - return true; - } - - return false; - } - } - - return false; + if (is_object($log) && method_exists($log, 'log') ) { + $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log; + } elseif (is_callable($log)) { + $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log; + } + } + + /** + * Set up a PEAR::Log object for this error stack + * @param Log $log + */ + function setLogger(&$log) + { + if (is_object($log) && method_exists($log, 'log') ) { + $this->_logger = &$log; + } elseif (is_callable($log)) { + $this->_logger = &$log; } - - return is_writeable($this->_depdb); } - - // {{{ assertDepsDB() - + /** - * Create the dependency database, if it doesn't exist. Error if the database is - * newer than the code reading it. - * @return void|PEAR_Error + * Set an error code => error message mapping callback + * + * This method sets the callback that can be used to generate error + * messages for any instance + * @param array|string Callback function/method */ - function assertDepsDB() + function setMessageCallback($msgCallback) { - if (!is_file($this->_depdb)) { - $this->rebuildDB(); + if (!$msgCallback) { + $this->_msgCallback = array(&$this, 'getErrorMessage'); } else { - $depdb = $this->_getDepDB(); - // Datatype format has been changed, rebuild the Deps DB - if ($depdb['_version'] < $this->_version) { - $this->rebuildDB(); - } - - if ($depdb['_version']{0} > $this->_version{0}) { - return PEAR::raiseError('Dependency database is version ' . - $depdb['_version'] . ', and we are version ' . - $this->_version . ', cannot continue'); + if (is_callable($msgCallback)) { + $this->_msgCallback = $msgCallback; } } } - + /** - * Get a list of installed packages that depend on this package - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array - * @return array|false + * Get an error code => error message mapping callback + * + * This method returns the current callback that can be used to generate error + * messages + * @return array|string|false Callback function/method or false if none */ - function getDependentPackages(&$pkg) + function getMessageCallback() { - $data = $this->_getDepDB(); - if (is_object($pkg)) { - $channel = strtolower($pkg->getChannel()); - $package = strtolower($pkg->getPackage()); - } else { - $channel = strtolower($pkg['channel']); - $package = strtolower($pkg['package']); - } - - if (isset($data['packages'][$channel][$package])) { - return $data['packages'][$channel][$package]; - } - - return false; + return $this->_msgCallback; } - + /** - * Get a list of the actual dependencies of installed packages that depend on - * a package. - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array - * @return array|false + * Sets a default callback to be used by all error stacks + * + * This method sets the callback that can be used to generate error + * messages for a singleton + * @param array|string Callback function/method + * @param string Package name, or false for all packages + * @static */ - function getDependentPackageDependencies(&$pkg) + function setDefaultCallback($callback = false, $package = false) { - $data = $this->_getDepDB(); - if (is_object($pkg)) { - $channel = strtolower($pkg->getChannel()); - $package = strtolower($pkg->getPackage()); - } else { - $channel = strtolower($pkg['channel']); - $package = strtolower($pkg['package']); + if (!is_callable($callback)) { + $callback = false; } - - $depend = $this->getDependentPackages($pkg); - if (!$depend) { - return false; + $package = $package ? $package : '*'; + $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$package] = $callback; + } + + /** + * Set a callback that generates context information (location of error) for an error stack + * + * This method sets the callback that can be used to generate context + * information for an error. Passing in NULL will disable context generation + * and remove the expensive call to debug_backtrace() + * @param array|string|null Callback function/method + */ + function setContextCallback($contextCallback) + { + if ($contextCallback === null) { + return $this->_contextCallback = false; } - - $dependencies = array(); - foreach ($depend as $info) { - $temp = $this->getDependencies($info); - foreach ($temp as $dep) { - if (isset($dep['dep'], $dep['dep']['channel'], $dep['dep']['name']) && - strtolower($dep['dep']['channel']) == $channel && - strtolower($dep['dep']['name']) == $package - ) { - if (!isset($dependencies[$info['channel']])) { - $dependencies[$info['channel']] = array(); - } - - if (!isset($dependencies[$info['channel']][$info['package']])) { - $dependencies[$info['channel']][$info['package']] = array(); - } - $dependencies[$info['channel']][$info['package']][] = $dep; - } + if (!$contextCallback) { + $this->_contextCallback = array(&$this, 'getFileLine'); + } else { + if (is_callable($contextCallback)) { + $this->_contextCallback = $contextCallback; } } - - return $dependencies; } - + /** - * Get a list of dependencies of this installed package - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array - * @return array|false + * Set an error Callback + * If set to a valid callback, this will be called every time an error + * is pushed onto the stack. The return value will be used to determine + * whether to allow an error to be pushed or logged. + * + * The return value must be one of the ERRORSTACK_* constants. + * + * This functionality can be used to emulate PEAR's pushErrorHandling, and + * the PEAR_ERROR_CALLBACK mode, without affecting the integrity of + * the error stack or logging + * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG + * @see popCallback() + * @param string|array $cb */ - function getDependencies(&$pkg) + function pushCallback($cb) { - if (is_object($pkg)) { - $channel = strtolower($pkg->getChannel()); - $package = strtolower($pkg->getPackage()); - } else { - $channel = strtolower($pkg['channel']); - $package = strtolower($pkg['package']); - } - - $data = $this->_getDepDB(); - if (isset($data['dependencies'][$channel][$package])) { - return $data['dependencies'][$channel][$package]; + array_push($this->_errorCallback, $cb); + } + + /** + * Remove a callback from the error callback stack + * @see pushCallback() + * @return array|string|false + */ + function popCallback() + { + if (!count($this->_errorCallback)) { + return false; } - - return false; + return array_pop($this->_errorCallback); } - + /** - * Determine whether $parent depends on $child, near or deep - * @param array|PEAR_PackageFile_v2|PEAR_PackageFile_v2 - * @param array|PEAR_PackageFile_v2|PEAR_PackageFile_v2 + * Set a temporary overriding error callback for every package error stack + * + * Use this to temporarily disable all existing callbacks (can be used + * to emulate the @ operator, for instance) + * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG + * @see staticPopCallback(), pushCallback() + * @param string|array $cb + * @static */ - function dependsOn($parent, $child) + function staticPushCallback($cb) { - $c = array(); - $this->_getDepDB(); - return $this->_dependsOn($parent, $child, $c); + array_push($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'], $cb); } - - function _dependsOn($parent, $child, &$checked) + + /** + * Remove a temporary overriding error callback + * @see staticPushCallback() + * @return array|string|false + * @static + */ + function staticPopCallback() { - if (is_object($parent)) { - $channel = strtolower($parent->getChannel()); - $package = strtolower($parent->getPackage()); - } else { - $channel = strtolower($parent['channel']); - $package = strtolower($parent['package']); - } - - if (is_object($child)) { - $depchannel = strtolower($child->getChannel()); - $deppackage = strtolower($child->getPackage()); - } else { - $depchannel = strtolower($child['channel']); - $deppackage = strtolower($child['package']); + $ret = array_pop($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK']); + if (!is_array($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'])) { + $GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array(); } - - if (isset($checked[$channel][$package][$depchannel][$deppackage])) { - return false; // avoid endless recursion + return $ret; + } + + /** + * Add an error to the stack + * + * If the message generator exists, it is called with 2 parameters. + * - the current Error Stack object + * - an array that is in the same format as an error. Available indices + * are 'code', 'package', 'time', 'params', 'level', and 'context' + * + * Next, if the error should contain context information, this is + * handled by the context grabbing method. + * Finally, the error is pushed onto the proper error stack + * @param int $code Package-specific error code + * @param string $level Error level. This is NOT spell-checked + * @param array $params associative array of error parameters + * @param string $msg Error message, or a portion of it if the message + * is to be generated + * @param array $repackage If this error re-packages an error pushed by + * another package, place the array returned from + * {@link pop()} in this parameter + * @param array $backtrace Protected parameter: use this to pass in the + * {@link debug_backtrace()} that should be used + * to find error context + * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also + * thrown. If a PEAR_Error is returned, the userinfo + * property is set to the following array: + * + * + * array( + * 'code' => $code, + * 'params' => $params, + * 'package' => $this->_package, + * 'level' => $level, + * 'time' => time(), + * 'context' => $context, + * 'message' => $msg, + * //['repackage' => $err] repackaged error array/Exception class + * ); + * + * + * Normally, the previous array is returned. + */ + function push($code, $level = 'error', $params = array(), $msg = false, + $repackage = false, $backtrace = false) + { + $context = false; + // grab error context + if ($this->_contextCallback) { + if (!$backtrace) { + $backtrace = debug_backtrace(); + } + $context = call_user_func($this->_contextCallback, $code, $params, $backtrace); } - - $checked[$channel][$package][$depchannel][$deppackage] = true; - if (!isset($this->_cache['dependencies'][$channel][$package])) { - return false; + + // save error + $time = explode(' ', microtime()); + $time = $time[1] + $time[0]; + $err = array( + 'code' => $code, + 'params' => $params, + 'package' => $this->_package, + 'level' => $level, + 'time' => $time, + 'context' => $context, + 'message' => $msg, + ); + + if ($repackage) { + $err['repackage'] = $repackage; + } + + // set up the error message, if necessary + if ($this->_msgCallback) { + $msg = call_user_func_array($this->_msgCallback, + array(&$this, $err)); + $err['message'] = $msg; + } + $push = $log = true; + $die = false; + // try the overriding callback first + $callback = $this->staticPopCallback(); + if ($callback) { + $this->staticPushCallback($callback); } - - foreach ($this->_cache['dependencies'][$channel][$package] as $info) { - if (isset($info['dep']['uri'])) { - if (is_object($child)) { - if ($info['dep']['uri'] == $child->getURI()) { - return true; - } - } elseif (isset($child['uri'])) { - if ($info['dep']['uri'] == $child['uri']) { - return true; - } - } - return false; - } - - if (strtolower($info['dep']['channel']) == $depchannel && - strtolower($info['dep']['name']) == $deppackage) { - return true; + if (!is_callable($callback)) { + // try the local callback next + $callback = $this->popCallback(); + if (is_callable($callback)) { + $this->pushCallback($callback); + } else { + // try the default callback + $callback = isset($GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package]) ? + $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package] : + $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']['*']; + } + } + if (is_callable($callback)) { + switch(call_user_func($callback, $err)){ + case PEAR_ERRORSTACK_IGNORE: + return $err; + break; + case PEAR_ERRORSTACK_PUSH: + $log = false; + break; + case PEAR_ERRORSTACK_LOG: + $push = false; + break; + case PEAR_ERRORSTACK_DIE: + $die = true; + break; + // anything else returned has the same effect as pushandlog + } + } + if ($push) { + array_unshift($this->_errors, $err); + if (!isset($this->_errorsByLevel[$err['level']])) { + $this->_errorsByLevel[$err['level']] = array(); + } + $this->_errorsByLevel[$err['level']][] = &$this->_errors[0]; + } + if ($log) { + if ($this->_logger || $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']) { + $this->_log($err); } } - - foreach ($this->_cache['dependencies'][$channel][$package] as $info) { - if (isset($info['dep']['uri'])) { - if ($this->_dependsOn(array( - 'uri' => $info['dep']['uri'], - 'package' => $info['dep']['name']), $child, $checked)) { - return true; - } - } else { - if ($this->_dependsOn(array( - 'channel' => $info['dep']['channel'], - 'package' => $info['dep']['name']), $child, $checked)) { - return true; - } - } + if ($die) { + die(); } - - return false; + if ($this->_compat && $push) { + return $this->raiseError($msg, $code, null, null, $err); + } + return $err; } - + /** - * Register dependencies of a package that is being installed or upgraded - * @param PEAR_PackageFile_v2|PEAR_PackageFile_v2 + * Static version of {@link push()} + * + * @param string $package Package name this error belongs to + * @param int $code Package-specific error code + * @param string $level Error level. This is NOT spell-checked + * @param array $params associative array of error parameters + * @param string $msg Error message, or a portion of it if the message + * is to be generated + * @param array $repackage If this error re-packages an error pushed by + * another package, place the array returned from + * {@link pop()} in this parameter + * @param array $backtrace Protected parameter: use this to pass in the + * {@link debug_backtrace()} that should be used + * to find error context + * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also + * thrown. see docs for {@link push()} + * @static */ - function installPackage(&$package) + function staticPush($package, $code, $level = 'error', $params = array(), + $msg = false, $repackage = false, $backtrace = false) { - $data = $this->_getDepDB(); - unset($this->_cache); - $this->_setPackageDeps($data, $package); - $this->_writeDepDB($data); + $s = &PEAR_ErrorStack::singleton($package); + if ($s->_contextCallback) { + if (!$backtrace) { + if (function_exists('debug_backtrace')) { + $backtrace = debug_backtrace(); + } + } + } + return $s->push($code, $level, $params, $msg, $repackage, $backtrace); } - + /** - * Remove dependencies of a package that is being uninstalled, or upgraded. - * - * Upgraded packages first uninstall, then install - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array If an array, then it must have - * indices 'channel' and 'package' + * Log an error using PEAR::Log + * @param array $err Error array + * @param array $levels Error level => Log constant map + * @access protected */ - function uninstallPackage(&$pkg) + function _log($err) { - $data = $this->_getDepDB(); - unset($this->_cache); - if (is_object($pkg)) { - $channel = strtolower($pkg->getChannel()); - $package = strtolower($pkg->getPackage()); + if ($this->_logger) { + $logger = &$this->_logger; } else { - $channel = strtolower($pkg['channel']); - $package = strtolower($pkg['package']); + $logger = &$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']; } - - if (!isset($data['dependencies'][$channel][$package])) { - return true; + if (is_a($logger, 'Log')) { + $levels = array( + 'exception' => PEAR_LOG_CRIT, + 'alert' => PEAR_LOG_ALERT, + 'critical' => PEAR_LOG_CRIT, + 'error' => PEAR_LOG_ERR, + 'warning' => PEAR_LOG_WARNING, + 'notice' => PEAR_LOG_NOTICE, + 'info' => PEAR_LOG_INFO, + 'debug' => PEAR_LOG_DEBUG); + if (isset($levels[$err['level']])) { + $level = $levels[$err['level']]; + } else { + $level = PEAR_LOG_INFO; + } + $logger->log($err['message'], $level, $err); + } else { // support non-standard logs + call_user_func($logger, $err); } + } - foreach ($data['dependencies'][$channel][$package] as $dep) { - $found = false; - $depchannel = isset($dep['dep']['uri']) ? '__uri' : strtolower($dep['dep']['channel']); - $depname = strtolower($dep['dep']['name']); - if (isset($data['packages'][$depchannel][$depname])) { - foreach ($data['packages'][$depchannel][$depname] as $i => $info) { - if ($info['channel'] == $channel && $info['package'] == $package) { - $found = true; - break; - } - } - } - - if ($found) { - unset($data['packages'][$depchannel][$depname][$i]); - if (!count($data['packages'][$depchannel][$depname])) { - unset($data['packages'][$depchannel][$depname]); - if (!count($data['packages'][$depchannel])) { - unset($data['packages'][$depchannel]); - } - } else { - $data['packages'][$depchannel][$depname] = - array_values($data['packages'][$depchannel][$depname]); - } + + /** + * Pop an error off of the error stack + * + * @return false|array + * @since 0.4alpha it is no longer possible to specify a specific error + * level to return - the last error pushed will be returned, instead + */ + function pop() + { + $err = @array_shift($this->_errors); + if (!is_null($err)) { + @array_pop($this->_errorsByLevel[$err['level']]); + if (!count($this->_errorsByLevel[$err['level']])) { + unset($this->_errorsByLevel[$err['level']]); } } - - unset($data['dependencies'][$channel][$package]); - if (!count($data['dependencies'][$channel])) { - unset($data['dependencies'][$channel]); - } - - if (!count($data['dependencies'])) { - unset($data['dependencies']); - } - - if (!count($data['packages'])) { - unset($data['packages']); - } - - $this->_writeDepDB($data); + return $err; } /** - * Rebuild the dependency DB by reading registry entries. - * @return true|PEAR_Error + * Pop an error off of the error stack, static method + * + * @param string package name + * @return boolean + * @since PEAR1.5.0a1 */ - function rebuildDB() + function staticPop($package) { - $depdb = array('_version' => $this->_version); - if (!$this->hasWriteAccess()) { - // allow startup for read-only with older Registry - return $depdb; + if ($package) { + if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { + return false; + } + return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->pop(); } + } - $packages = $this->_registry->listAllPackages(); - if (PEAR::isError($packages)) { - return $packages; + /** + * Determine whether there are any errors on the stack + * @param string|array Level name. Use to determine if any errors + * of level (string), or levels (array) have been pushed + * @return boolean + */ + function hasErrors($level = false) + { + if ($level) { + return isset($this->_errorsByLevel[$level]); } - - foreach ($packages as $channel => $ps) { - foreach ($ps as $package) { - $package = $this->_registry->getPackage($package, $channel); - if (PEAR::isError($package)) { - return $package; + return count($this->_errors); + } + + /** + * Retrieve all errors since last purge + * + * @param boolean set in order to empty the error stack + * @param string level name, to return only errors of a particular severity + * @return array + */ + function getErrors($purge = false, $level = false) + { + if (!$purge) { + if ($level) { + if (!isset($this->_errorsByLevel[$level])) { + return array(); + } else { + return $this->_errorsByLevel[$level]; } - $this->_setPackageDeps($depdb, $package); + } else { + return $this->_errors; } } - - $error = $this->_writeDepDB($depdb); - if (PEAR::isError($error)) { - return $error; + if ($level) { + $ret = $this->_errorsByLevel[$level]; + foreach ($this->_errorsByLevel[$level] as $i => $unused) { + // entries are references to the $_errors array + $this->_errorsByLevel[$level][$i] = false; + } + // array_filter removes all entries === false + $this->_errors = array_filter($this->_errors); + unset($this->_errorsByLevel[$level]); + return $ret; } - - $this->_cache = $depdb; - return true; + $ret = $this->_errors; + $this->_errors = array(); + $this->_errorsByLevel = array(); + return $ret; } - + /** - * Register usage of the dependency DB to prevent race conditions - * @param int one of the LOCK_* constants - * @return true|PEAR_Error - * @access private + * Determine whether there are any errors on a single error stack, or on any error stack + * + * The optional parameter can be used to test the existence of any errors without the need of + * singleton instantiation + * @param string|false Package name to check for errors + * @param string Level name to check for a particular severity + * @return boolean + * @static */ - function _lock($mode = LOCK_EX) + function staticHasErrors($package = false, $level = false) { - if (stristr(php_uname(), 'Windows 9')) { - return true; - } - - if ($mode != LOCK_UN && is_resource($this->_lockFp)) { - // XXX does not check type of lock (LOCK_SH/LOCK_EX) - return true; - } - - $open_mode = 'w'; - // XXX People reported problems with LOCK_SH and 'w' - if ($mode === LOCK_SH) { - if (!file_exists($this->_lockfile)) { - touch($this->_lockfile); - } elseif (!is_file($this->_lockfile)) { - return PEAR::raiseError('could not create Dependency lock file, ' . - 'it exists and is not a regular file'); + if ($package) { + if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { + return false; } - $open_mode = 'r'; + return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->hasErrors($level); } - - if (!is_resource($this->_lockFp)) { - $this->_lockFp = @fopen($this->_lockfile, $open_mode); - } - - if (!is_resource($this->_lockFp)) { - return PEAR::raiseError("could not create Dependency lock file" . - (isset($php_errormsg) ? ": " . $php_errormsg : "")); - } - - if (!(int)flock($this->_lockFp, $mode)) { - switch ($mode) { - case LOCK_SH: $str = 'shared'; break; - case LOCK_EX: $str = 'exclusive'; break; - case LOCK_UN: $str = 'unlock'; break; - default: $str = 'unknown'; break; + foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) { + if ($obj->hasErrors($level)) { + return true; } - - return PEAR::raiseError("could not acquire $str lock ($this->_lockfile)"); } - - return true; + return false; } - + /** - * Release usage of dependency DB - * @return true|PEAR_Error - * @access private + * Get a list of all errors since last purge, organized by package + * @since PEAR 1.4.0dev BC break! $level is now in the place $merge used to be + * @param boolean $purge Set to purge the error stack of existing errors + * @param string $level Set to a level name in order to retrieve only errors of a particular level + * @param boolean $merge Set to return a flat array, not organized by package + * @param array $sortfunc Function used to sort a merged array - default + * sorts by time, and should be good for most cases + * @static + * @return array */ - function _unlock() + function staticGetErrors($purge = false, $level = false, $merge = false, + $sortfunc = array('PEAR_ErrorStack', '_sortErrors')) { - $ret = $this->_lock(LOCK_UN); - if (is_resource($this->_lockFp)) { - fclose($this->_lockFp); + $ret = array(); + if (!is_callable($sortfunc)) { + $sortfunc = array('PEAR_ErrorStack', '_sortErrors'); + } + foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) { + $test = $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->getErrors($purge, $level); + if ($test) { + if ($merge) { + $ret = array_merge($ret, $test); + } else { + $ret[$package] = $test; + } + } + } + if ($merge) { + usort($ret, $sortfunc); } - $this->_lockFp = null; return $ret; } - + /** - * Load the dependency database from disk, or return the cache - * @return array|PEAR_Error + * Error sorting function, sorts by time + * @access private */ - function _getDepDB() + function _sortErrors($a, $b) { - if (!$this->hasWriteAccess()) { - return array('_version' => $this->_version); - } - - if (isset($this->_cache)) { - return $this->_cache; + if ($a['time'] == $b['time']) { + return 0; } - - if (!$fp = fopen($this->_depdb, 'r')) { - $err = PEAR::raiseError("Could not open dependencies file `".$this->_depdb."'"); - return $err; + if ($a['time'] < $b['time']) { + return 1; } - - $rt = get_magic_quotes_runtime(); - set_magic_quotes_runtime(0); - clearstatcache(); - fclose($fp); - $data = unserialize(file_get_contents($this->_depdb)); - set_magic_quotes_runtime($rt); - $this->_cache = $data; - return $data; + return -1; } /** - * Write out the dependency database to disk - * @param array the database - * @return true|PEAR_Error - * @access private + * Standard file/line number/function/class context callback + * + * This function uses a backtrace generated from {@link debug_backtrace()} + * and so will not work at all in PHP < 4.3.0. The frame should + * reference the frame that contains the source of the error. + * @return array|false either array('file' => file, 'line' => line, + * 'function' => function name, 'class' => class name) or + * if this doesn't work, then false + * @param unused + * @param integer backtrace frame. + * @param array Results of debug_backtrace() + * @static */ - function _writeDepDB(&$deps) + function getFileLine($code, $params, $backtrace = null) { - if (PEAR::isError($e = $this->_lock(LOCK_EX))) { - return $e; + if ($backtrace === null) { + return false; } - - if (!$fp = fopen($this->_depdb, 'wb')) { - $this->_unlock(); - return PEAR::raiseError("Could not open dependencies file `".$this->_depdb."' for writing"); + $frame = 0; + $functionframe = 1; + if (!isset($backtrace[1])) { + $functionframe = 0; + } else { + while (isset($backtrace[$functionframe]['function']) && + $backtrace[$functionframe]['function'] == 'eval' && + isset($backtrace[$functionframe + 1])) { + $functionframe++; + } + } + if (isset($backtrace[$frame])) { + if (!isset($backtrace[$frame]['file'])) { + $frame++; + } + $funcbacktrace = $backtrace[$functionframe]; + $filebacktrace = $backtrace[$frame]; + $ret = array('file' => $filebacktrace['file'], + 'line' => $filebacktrace['line']); + // rearrange for eval'd code or create function errors + if (strpos($filebacktrace['file'], '(') && + preg_match(';^(.*?)\((\d+)\) : (.*?)\\z;', $filebacktrace['file'], + $matches)) { + $ret['file'] = $matches[1]; + $ret['line'] = $matches[2] + 0; + } + if (isset($funcbacktrace['function']) && isset($backtrace[1])) { + if ($funcbacktrace['function'] != 'eval') { + if ($funcbacktrace['function'] == '__lambda_func') { + $ret['function'] = 'create_function() code'; + } else { + $ret['function'] = $funcbacktrace['function']; + } + } + } + if (isset($funcbacktrace['class']) && isset($backtrace[1])) { + $ret['class'] = $funcbacktrace['class']; + } + return $ret; } - - $rt = get_magic_quotes_runtime(); - set_magic_quotes_runtime(0); - fwrite($fp, serialize($deps)); - set_magic_quotes_runtime($rt); - fclose($fp); - $this->_unlock(); - $this->_cache = $deps; - return true; + return false; } - + /** - * Register all dependencies from a package in the dependencies database, in essence - * "installing" the package's dependency information - * @param array the database - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @access private + * Standard error message generation callback + * + * This method may also be called by a custom error message generator + * to fill in template values from the params array, simply + * set the third parameter to the error message template string to use + * + * The special variable %__msg% is reserved: use it only to specify + * where a message passed in by the user should be placed in the template, + * like so: + * + * Error message: %msg% - internal error + * + * If the message passed like so: + * + * + * $stack->push(ERROR_CODE, 'error', array(), 'server error 500'); + * + * + * The returned error message will be "Error message: server error 500 - + * internal error" + * @param PEAR_ErrorStack + * @param array + * @param string|false Pre-generated error message template + * @static + * @return string */ - function _setPackageDeps(&$data, &$pkg) + function getErrorMessage(&$stack, $err, $template = false) { - $pkg->setConfig($this->_config); - if ($pkg->getPackagexmlVersion() == '1.0') { - $gen = &$pkg->getDefaultGenerator(); - $deps = $gen->dependenciesToV2(); + if ($template) { + $mainmsg = $template; } else { - $deps = $pkg->getDeps(true); - } - - if (!$deps) { - return; + $mainmsg = $stack->getErrorMessageTemplate($err['code']); } - - if (!is_array($data)) { - $data = array(); + $mainmsg = str_replace('%__msg%', $err['message'], $mainmsg); + if (is_array($err['params']) && count($err['params'])) { + foreach ($err['params'] as $name => $val) { + if (is_array($val)) { + // @ is needed in case $val is a multi-dimensional array + $val = @implode(', ', $val); + } + if (is_object($val)) { + if (method_exists($val, '__toString')) { + $val = $val->__toString(); + } else { + PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_OBJTOSTRING, + 'warning', array('obj' => get_class($val)), + 'object %obj% passed into getErrorMessage, but has no __toString() method'); + $val = 'Object'; + } + } + $mainmsg = str_replace('%' . $name . '%', $val, $mainmsg); + } } - - if (!isset($data['dependencies'])) { - $data['dependencies'] = array(); + return $mainmsg; + } + + /** + * Standard Error Message Template generator from code + * @return string + */ + function getErrorMessageTemplate($code) + { + if (!isset($this->_errorMsgs[$code])) { + return '%__msg%'; } + return $this->_errorMsgs[$code]; + } + + /** + * Set the Error Message Template array + * + * The array format must be: + *
+     * array(error code => 'message template',...)
+     * 
+ * + * Error message parameters passed into {@link push()} will be used as input + * for the error message. If the template is 'message %foo% was %bar%', and the + * parameters are array('foo' => 'one', 'bar' => 'six'), the error message returned will + * be 'message one was six' + * @return string + */ + function setErrorMessageTemplate($template) + { + $this->_errorMsgs = $template; + } + + + /** + * emulate PEAR::raiseError() + * + * @return PEAR_Error + */ + function raiseError() + { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR.php'; + $args = func_get_args(); + return call_user_func_array(array('PEAR', 'raiseError'), $args); + } +} +$stack = &PEAR_ErrorStack::singleton('PEAR_ErrorStack'); +$stack->pushCallback(array('PEAR_ErrorStack', '_handleError')); +?> + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Frontend.php 276383 2009-02-24 23:39:37Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ - $channel = strtolower($pkg->getChannel()); - $package = strtolower($pkg->getPackage()); +/** + * Include error handling + */ +//require_once 'PEAR.php'; - if (!isset($data['dependencies'][$channel])) { - $data['dependencies'][$channel] = array(); - } +/** + * Which user interface class is being used. + * @var string class name + */ +$GLOBALS['_PEAR_FRONTEND_CLASS'] = 'PEAR_Frontend_CLI'; - $data['dependencies'][$channel][$package] = array(); - if (isset($deps['required']['package'])) { - if (!isset($deps['required']['package'][0])) { - $deps['required']['package'] = array($deps['required']['package']); - } +/** + * Instance of $_PEAR_Command_uiclass. + * @var object + */ +$GLOBALS['_PEAR_FRONTEND_SINGLETON'] = null; - foreach ($deps['required']['package'] as $dep) { - $this->_registerDep($data, $pkg, $dep, 'required'); +/** + * Singleton-based frontend for PEAR user input/output + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Frontend extends PEAR +{ + /** + * Retrieve the frontend object + * @return PEAR_Frontend_CLI|PEAR_Frontend_Web|PEAR_Frontend_Gtk + * @static + */ + function &singleton($type = null) + { + if ($type === null) { + if (!isset($GLOBALS['_PEAR_FRONTEND_SINGLETON'])) { + $a = false; + return $a; } + return $GLOBALS['_PEAR_FRONTEND_SINGLETON']; } - if (isset($deps['optional']['package'])) { - if (!isset($deps['optional']['package'][0])) { - $deps['optional']['package'] = array($deps['optional']['package']); - } + $a = PEAR_Frontend::setFrontendClass($type); + return $a; + } - foreach ($deps['optional']['package'] as $dep) { - $this->_registerDep($data, $pkg, $dep, 'optional'); - } + /** + * Set the frontend class that will be used by calls to {@link singleton()} + * + * Frontends are expected to conform to the PEAR naming standard of + * _ => DIRECTORY_SEPARATOR (PEAR_Frontend_CLI is in PEAR/Frontend/CLI.php) + * @param string $uiclass full class name + * @return PEAR_Frontend + * @static + */ + function &setFrontendClass($uiclass) + { + if (is_object($GLOBALS['_PEAR_FRONTEND_SINGLETON']) && + is_a($GLOBALS['_PEAR_FRONTEND_SINGLETON'], $uiclass)) { + return $GLOBALS['_PEAR_FRONTEND_SINGLETON']; } - if (isset($deps['required']['subpackage'])) { - if (!isset($deps['required']['subpackage'][0])) { - $deps['required']['subpackage'] = array($deps['required']['subpackage']); - } - - foreach ($deps['required']['subpackage'] as $dep) { - $this->_registerDep($data, $pkg, $dep, 'required'); + if (!class_exists($uiclass)) { + $file = 'phar://install-pear-nozlib.phar/' . str_replace('_', '/', $uiclass) . '.php'; + if (PEAR_Frontend::isIncludeable($file)) { + include_once $file; } } - if (isset($deps['optional']['subpackage'])) { - if (!isset($deps['optional']['subpackage'][0])) { - $deps['optional']['subpackage'] = array($deps['optional']['subpackage']); + if (class_exists($uiclass)) { + $obj = &new $uiclass; + // quick test to see if this class implements a few of the most + // important frontend methods + if (is_a($obj, 'PEAR_Frontend')) { + $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = &$obj; + $GLOBALS['_PEAR_FRONTEND_CLASS'] = $uiclass; + return $obj; } - foreach ($deps['optional']['subpackage'] as $dep) { - $this->_registerDep($data, $pkg, $dep, 'optional'); - } + $err = PEAR::raiseError("not a frontend class: $uiclass"); + return $err; } - if (isset($deps['group'])) { - if (!isset($deps['group'][0])) { - $deps['group'] = array($deps['group']); - } - - foreach ($deps['group'] as $group) { - if (isset($group['package'])) { - if (!isset($group['package'][0])) { - $group['package'] = array($group['package']); - } - - foreach ($group['package'] as $dep) { - $this->_registerDep($data, $pkg, $dep, 'optional', - $group['attribs']['name']); - } - } - - if (isset($group['subpackage'])) { - if (!isset($group['subpackage'][0])) { - $group['subpackage'] = array($group['subpackage']); - } + $err = PEAR::raiseError("no such class: $uiclass"); + return $err; + } - foreach ($group['subpackage'] as $dep) { - $this->_registerDep($data, $pkg, $dep, 'optional', - $group['attribs']['name']); - } - } - } + /** + * Set the frontend class that will be used by calls to {@link singleton()} + * + * Frontends are expected to be a descendant of PEAR_Frontend + * @param PEAR_Frontend + * @return PEAR_Frontend + * @static + */ + function &setFrontendObject($uiobject) + { + if (is_object($GLOBALS['_PEAR_FRONTEND_SINGLETON']) && + is_a($GLOBALS['_PEAR_FRONTEND_SINGLETON'], get_class($uiobject))) { + return $GLOBALS['_PEAR_FRONTEND_SINGLETON']; } - if ($data['dependencies'][$channel][$package] == array()) { - unset($data['dependencies'][$channel][$package]); - if (!count($data['dependencies'][$channel])) { - unset($data['dependencies'][$channel]); - } + if (!is_a($uiobject, 'PEAR_Frontend')) { + $err = PEAR::raiseError('not a valid frontend class: (' . + get_class($uiobject) . ')'); + return $err; } + + $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = &$uiobject; + $GLOBALS['_PEAR_FRONTEND_CLASS'] = get_class($uiobject); + return $uiobject; } /** - * @param array the database - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @param array the specific dependency - * @param required|optional whether this is a required or an optional dep - * @param string|false dependency group this dependency is from, or false for ordinary dep + * @param string $path relative or absolute include path + * @return boolean + * @static */ - function _registerDep(&$data, &$pkg, $dep, $type, $group = false) + function isIncludeable($path) { - $info = array( - 'dep' => $dep, - 'type' => $type, - 'group' => $group - ); - - $dep = array_map('strtolower', $dep); - $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri'; - if (!isset($data['dependencies'])) { - $data['dependencies'] = array(); + if (file_exists($path) && is_readable($path)) { + return true; } - $channel = strtolower($pkg->getChannel()); - $package = strtolower($pkg->getPackage()); - - if (!isset($data['dependencies'][$channel])) { - $data['dependencies'][$channel] = array(); + $fp = @fopen($path, 'r', true); + if ($fp) { + fclose($fp); + return true; } - if (!isset($data['dependencies'][$channel][$package])) { - $data['dependencies'][$channel][$package] = array(); - } + return false; + } - $data['dependencies'][$channel][$package][] = $info; - if (isset($data['packages'][$depchannel][$dep['name']])) { - $found = false; - foreach ($data['packages'][$depchannel][$dep['name']] as $i => $p) { - if ($p['channel'] == $channel && $p['package'] == $package) { - $found = true; - break; - } - } + /** + * @param PEAR_Config + */ + function setConfig(&$config) + { + } - if (!$found) { - $data['packages'][$depchannel][$dep['name']][] = array( - 'channel' => $channel, - 'package' => $package - ); - } - } else { - if (!isset($data['packages'])) { - $data['packages'] = array(); - } + /** + * This can be overridden to allow session-based temporary file management + * + * By default, all files are deleted at the end of a session. The web installer + * needs to be able to sustain a list over many sessions in order to support + * user interaction with install scripts + */ + function addTempFile($file) + { + $GLOBALS['_PEAR_Common_tempfiles'][] = $file; + } - if (!isset($data['packages'][$depchannel])) { - $data['packages'][$depchannel] = array(); - } + /** + * Log an action + * + * @param string $msg the message to log + * @param boolean $append_crlf + * @return boolean true + * @abstract + */ + function log($msg, $append_crlf = true) + { + } - if (!isset($data['packages'][$depchannel][$dep['name']])) { - $data['packages'][$depchannel][$dep['name']] = array(); - } + /** + * Run a post-installation script + * + * @param array $scripts array of post-install scripts + * @abstract + */ + function runPostinstallScripts(&$scripts) + { + } - $data['packages'][$depchannel][$dep['name']][] = array( - 'channel' => $channel, - 'package' => $package - ); - } + /** + * Display human-friendly output formatted depending on the + * $command parameter. + * + * This should be able to handle basic output data with no command + * @param mixed $data data structure containing the information to display + * @param string $command command from which this method was called + * @abstract + */ + function outputData($data, $command = '_default') + { + } + + /** + * Display a modal form dialog and return the given input + * + * A frontend that requires multiple requests to retrieve and process + * data must take these needs into account, and implement the request + * handling code. + * @param string $command command from which this method was called + * @param array $prompts associative array. keys are the input field names + * and values are the description + * @param array $types array of input field types (text, password, + * etc.) keys have to be the same like in $prompts + * @param array $defaults array of default values. again keys have + * to be the same like in $prompts. Do not depend + * on a default value being set. + * @return array input sent by the user + * @abstract + */ + function userDialog($command, $prompts, $types = array(), $defaults = array()) + { } } * @author Stig Bakken - * @author Tomas V. V. Cox - * @author Martin Jansen + * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Downloader.php,v 1.159 2009/03/08 04:01:08 dufuz Exp $ + * @version CVS: $Id: CLI.php 278236 2009-04-04 00:09:14Z dufuz $ * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.3.0 + * @since File available since Release 0.1 */ - /** - * Needed for constants, extending + * base class */ -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Common.php'; - -define('PEAR_INSTALLER_OK', 1); -define('PEAR_INSTALLER_FAILED', 0); -define('PEAR_INSTALLER_SKIPPED', -1); -define('PEAR_INSTALLER_ERROR_NO_PREF_STATE', 2); +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Frontend.php'; /** - * Administration class used to download anything from the internet (PEAR Packages, - * static URLs, xml files) - * + * Command-line Frontend for the PEAR Installer * @category pear * @package PEAR - * @author Greg Beaver * @author Stig Bakken - * @author Tomas V. V. Cox - * @author Martin Jansen + * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.3.0 + * @since Class available since Release 0.1 */ -class PEAR_Downloader extends PEAR_Common +class PEAR_Frontend_CLI extends PEAR_Frontend { /** - * @var PEAR_Registry - * @access private + * What type of user interface this frontend is for. + * @var string + * @access public */ - var $_registry; + var $type = 'CLI'; + var $lp = ''; // line prefix - /** - * Preferred Installation State (snapshot, devel, alpha, beta, stable) - * @var string|null - * @access private - */ - var $_preferredState; + var $params = array(); + var $term = array( + 'bold' => '', + 'normal' => '', + ); - /** - * Options from command-line passed to Install. - * - * Recognized options:
- * - onlyreqdeps : install all required dependencies as well - * - alldeps : install all dependencies, including optional - * - installroot : base relative path to install files in - * - force : force a download even if warnings would prevent it - * - nocompress : download uncompressed tarballs - * @see PEAR_Command_Install - * @access private - * @var array - */ - var $_options; + function PEAR_Frontend_CLI() + { + parent::PEAR(); + $term = getenv('TERM'); //(cox) $_ENV is empty for me in 4.1.1 + if (function_exists('posix_isatty') && !posix_isatty(1)) { + // output is being redirected to a file or through a pipe + } elseif ($term) { + if (preg_match('/^(xterm|vt220|linux)/', $term)) { + $this->term['bold'] = sprintf("%c%c%c%c", 27, 91, 49, 109); + $this->term['normal'] = sprintf("%c%c%c", 27, 91, 109); + } elseif (preg_match('/^vt100/', $term)) { + $this->term['bold'] = sprintf("%c%c%c%c%c%c", 27, 91, 49, 109, 0, 0); + $this->term['normal'] = sprintf("%c%c%c%c%c", 27, 91, 109, 0, 0); + } + } elseif (OS_WINDOWS) { + // XXX add ANSI codes here + } + } /** - * Downloaded Packages after a call to download(). - * - * Format of each entry: - * - * - * array('pkg' => 'package_name', 'file' => '/path/to/local/file', - * 'info' => array() // parsed package.xml - * ); - * - * @access private - * @var array + * @param object PEAR_Error object */ - var $_downloadedPackages = array(); + function displayError($e) + { + return $this->_displayLine($e->getMessage()); + } /** - * Packages slated for download. - * - * This is used to prevent downloading a package more than once should it be a dependency - * for two packages to be installed. - * Format of each entry: - * - *
-     * array('package_name1' => parsed package.xml, 'package_name2' => parsed package.xml,
-     * );
-     * 
- * @access private - * @var array + * @param object PEAR_Error object */ - var $_toDownload = array(); + function displayFatalError($eobj) + { + $this->displayError($eobj); + if (class_exists('PEAR_Config')) { + $config = &PEAR_Config::singleton(); + if ($config->get('verbose') > 5) { + if (function_exists('debug_print_backtrace')) { + debug_print_backtrace(); + exit(1); + } - /** - * Array of every package installed, with names lower-cased. - * - * Format: - * - * array('package1' => 0, 'package2' => 1, ); - * - * @var array - */ - var $_installed = array(); + $raised = false; + foreach (debug_backtrace() as $i => $frame) { + if (!$raised) { + if (isset($frame['class']) + && strtolower($frame['class']) == 'pear' + && strtolower($frame['function']) == 'raiseerror' + ) { + $raised = true; + } else { + continue; + } + } - /** - * @var array - * @access private - */ - var $_errorStack = array(); + $frame['class'] = !isset($frame['class']) ? '' : $frame['class']; + $frame['type'] = !isset($frame['type']) ? '' : $frame['type']; + $frame['function'] = !isset($frame['function']) ? '' : $frame['function']; + $frame['line'] = !isset($frame['line']) ? '' : $frame['line']; + $this->_displayLine("#$i: $frame[class]$frame[type]$frame[function] $frame[line]"); + } + } + } - /** - * @var boolean - * @access private - */ - var $_internalDownload = false; + exit(1); + } /** - * Temporary variable used in sorting packages by dependency in {@link sortPkgDeps()} - * @var array - * @access private + * Instruct the runInstallScript method to skip a paramgroup that matches the + * id value passed in. + * + * This method is useful for dynamically configuring which sections of a post-install script + * will be run based on the user's setup, which is very useful for making flexible + * post-install scripts without losing the cross-Frontend ability to retrieve user input + * @param string */ - var $_packageSortTree; + function skipParamgroup($id) + { + $this->_skipSections[$id] = true; + } - /** - * Temporary directory, or configuration value where downloads will occur - * @var string - */ - var $_downloadDir; - // {{{ PEAR_Downloader() + function runPostinstallScripts(&$scripts) + { + foreach ($scripts as $i => $script) { + $this->runInstallScript($scripts[$i]->_params, $scripts[$i]->_obj); + } + } /** - * @param PEAR_Frontend_* - * @param array - * @param PEAR_Config + * @param array $xml contents of postinstallscript tag + * @param object $script post-installation script + * @param string install|upgrade */ - function PEAR_Downloader(&$ui, $options, &$config) + function runInstallScript($xml, &$script) { - parent::PEAR_Common(); - $this->_options = $options; - $this->config = &$config; - $this->_preferredState = $this->config->get('preferred_state'); - $this->ui = &$ui; - if (!$this->_preferredState) { - // don't inadvertantly use a non-set preferred_state - $this->_preferredState = null; + $this->_skipSections = array(); + if (!is_array($xml) || !isset($xml['paramgroup'])) { + $script->run(array(), '_default'); + return; } - if (isset($this->_options['installroot'])) { - $this->config->setInstallRoot($this->_options['installroot']); + $completedPhases = array(); + if (!isset($xml['paramgroup'][0])) { + $xml['paramgroup'] = array($xml['paramgroup']); } - $this->_registry = &$config->getRegistry(); - if (isset($this->_options['alldeps']) || isset($this->_options['onlyreqdeps'])) { - $this->_installed = $this->_registry->listAllPackages(); - foreach ($this->_installed as $key => $unused) { - if (!count($unused)) { + foreach ($xml['paramgroup'] as $group) { + if (isset($this->_skipSections[$group['id']])) { + // the post-install script chose to skip this section dynamically + continue; + } + + if (isset($group['name'])) { + $paramname = explode('::', $group['name']); + if ($lastgroup['id'] != $paramname[0]) { continue; } - $strtolower = create_function('$a','return strtolower($a);'); - array_walk($this->_installed[$key], $strtolower); + + $group['name'] = $paramname[1]; + if (!isset($answers)) { + return; + } + + if (isset($answers[$group['name']])) { + switch ($group['conditiontype']) { + case '=' : + if ($answers[$group['name']] != $group['value']) { + continue 2; + } + break; + case '!=' : + if ($answers[$group['name']] == $group['value']) { + continue 2; + } + break; + case 'preg_match' : + if (!@preg_match('/' . $group['value'] . '/', + $answers[$group['name']])) { + continue 2; + } + break; + default : + return; + } + } + } + + $lastgroup = $group; + if (isset($group['instructions'])) { + $this->_display($group['instructions']); + } + + if (!isset($group['param'][0])) { + $group['param'] = array($group['param']); + } + + if (isset($group['param'])) { + if (method_exists($script, 'postProcessPrompts')) { + $prompts = $script->postProcessPrompts($group['param'], $group['id']); + if (!is_array($prompts) || count($prompts) != count($group['param'])) { + $this->outputData('postinstall', 'Error: post-install script did not ' . + 'return proper post-processed prompts'); + $prompts = $group['param']; + } else { + foreach ($prompts as $i => $var) { + if (!is_array($var) || !isset($var['prompt']) || + !isset($var['name']) || + ($var['name'] != $group['param'][$i]['name']) || + ($var['type'] != $group['param'][$i]['type']) + ) { + $this->outputData('postinstall', 'Error: post-install script ' . + 'modified the variables or prompts, severe security risk. ' . + 'Will instead use the defaults from the package.xml'); + $prompts = $group['param']; + } + } + } + + $answers = $this->confirmDialog($prompts); + } else { + $answers = $this->confirmDialog($group['param']); + } + } + + if ((isset($answers) && $answers) || !isset($group['param'])) { + if (!isset($answers)) { + $answers = array(); + } + + array_unshift($completedPhases, $group['id']); + if (!$script->run($answers, $group['id'])) { + $script->run($completedPhases, '_undoOnError'); + return; + } + } else { + $script->run($completedPhases, '_undoOnError'); + return; } } } /** - * Attempt to discover a channel's remote capabilities from - * its server name - * @param string - * @return boolean + * Ask for user input, confirm the answers and continue until the user is satisfied + * @param array an array of arrays, format array('name' => 'paramname', 'prompt' => + * 'text to display', 'type' => 'string'[, default => 'default value']) + * @return array */ - function discover($channel) + function confirmDialog($params) { - $this->log(1, 'Attempting to discover channel "' . $channel . '"...'); - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $callback = $this->ui ? array(&$this, '_downloadCallback') : null; - if (!class_exists('System')) { - require_once 'phar://install-pear-nozlib.phar/' . 'System.php'; + $answers = $prompts = $types = array(); + foreach ($params as $param) { + $prompts[$param['name']] = $param['prompt']; + $types[$param['name']] = $param['type']; + $answers[$param['name']] = isset($param['default']) ? $param['default'] : ''; } - $tmp = System::mktemp(array('-d')); - $a = $this->downloadHttp('http://' . $channel . '/channel.xml', $this->ui, $tmp, $callback, false); - PEAR::popErrorHandling(); - if (PEAR::isError($a)) { - // Attempt to fallback to https automatically. - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $this->log(1, 'Attempting fallback to https instead of http on channel "' . $channel . '"...'); - $a = $this->downloadHttp('https://' . $channel . '/channel.xml', $this->ui, $tmp, $callback, false); - PEAR::popErrorHandling(); - if (PEAR::isError($a)) { - return false; + $tried = false; + do { + if ($tried) { + $i = 1; + foreach ($answers as $var => $value) { + if (!strlen($value)) { + echo $this->bold("* Enter an answer for #" . $i . ": ({$prompts[$var]})\n"); + } + $i++; + } } - } - list($a, $lastmodified) = $a; - if (!class_exists('PEAR_ChannelFile')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/ChannelFile.php'; + $answers = $this->userDialog('', $prompts, $types, $answers); + $tried = true; + } while (is_array($answers) && count(array_filter($answers)) != count($prompts)); + + return $answers; + } + + function userDialog($command, $prompts, $types = array(), $defaults = array(), $screensize = 20) + { + if (!is_array($prompts)) { + return array(); } - $b = new PEAR_ChannelFile; - if ($b->fromXmlFile($a)) { - unlink($a); - if ($this->config->get('auto_discover')) { - $this->_registry->addChannel($b, $lastmodified); - $alias = $b->getName(); - if ($b->getName() == $this->_registry->channelName($b->getAlias())) { - $alias = $b->getAlias(); + $testprompts = array_keys($prompts); + $result = $defaults; + + reset($prompts); + if (count($prompts) === 1) { + foreach ($prompts as $key => $prompt) { + $type = $types[$key]; + $default = @$defaults[$key]; + print "$prompt "; + if ($default) { + print "[$default] "; } + print ": "; - $this->log(1, 'Auto-discovered channel "' . $channel . - '", alias "' . $alias . '", adding to registry'); + $line = fgets(STDIN, 2048); + $result[$key] = ($default && trim($line) == '') ? $default : trim($line); } - return true; + return $result; } - unlink($a); - return false; - } + $first_run = true; + while (true) { + $descLength = max(array_map('strlen', $prompts)); + $descFormat = "%-{$descLength}s"; + $last = count($prompts); - /** - * For simpler unit-testing - * @param PEAR_Downloader - * @return PEAR_Downloader_Package - */ - function &newDownloaderPackage(&$t) - { - if (!class_exists('PEAR_Downloader_Package')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Downloader/Package.php'; + $i = 0; + foreach ($prompts as $n => $var) { + $res = isset($result[$n]) ? $result[$n] : null; + printf("%2d. $descFormat : %s\n", ++$i, $prompts[$n], $res); + } + print "\n1-$last, 'all', 'abort', or Enter to continue: "; + + $tmp = trim(fgets(STDIN, 1024)); + if (empty($tmp)) { + break; + } + + if ($tmp == 'abort') { + return false; + } + + if (isset($testprompts[(int)$tmp - 1])) { + $var = $testprompts[(int)$tmp - 1]; + $desc = $prompts[$var]; + $current = @$result[$var]; + print "$desc [$current] : "; + $tmp = trim(fgets(STDIN, 1024)); + if ($tmp !== '') { + $result[$var] = $tmp; + } + } elseif ($tmp == 'all') { + foreach ($prompts as $var => $desc) { + $current = $result[$var]; + print "$desc [$current] : "; + $tmp = trim(fgets(STDIN, 1024)); + if (trim($tmp) !== '') { + $result[$var] = trim($tmp); + } + } + } + + $first_run = false; } - $a = &new PEAR_Downloader_Package($t); - return $a; + + return $result; } - /** - * For simpler unit-testing - * @param PEAR_Config - * @param array - * @param array - * @param int - */ - function &getDependency2Object(&$c, $i, $p, $s) + function userConfirm($prompt, $default = 'yes') { - if (!class_exists('PEAR_Dependency2')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Dependency2.php'; + trigger_error("PEAR_Frontend_CLI::userConfirm not yet converted", E_USER_ERROR); + static $positives = array('y', 'yes', 'on', '1'); + static $negatives = array('n', 'no', 'off', '0'); + print "$this->lp$prompt [$default] : "; + $fp = fopen("php://stdin", "r"); + $line = fgets($fp, 2048); + fclose($fp); + $answer = strtolower(trim($line)); + if (empty($answer)) { + $answer = $default; } - $z = &new PEAR_Dependency2($c, $i, $p, $s); - return $z; + if (in_array($answer, $positives)) { + return true; + } + if (in_array($answer, $negatives)) { + return false; + } + if (in_array($default, $positives)) { + return true; + } + return false; } - function &download($params) + function outputData($data, $command = '_default') { - if (!count($params)) { - $a = array(); - return $a; - } + switch ($command) { + case 'channel-info': + foreach ($data as $type => $section) { + if ($type == 'main') { + $section['data'] = array_values($section['data']); + } - if (!isset($this->_registry)) { - $this->_registry = &$this->config->getRegistry(); - } + $this->outputData($section); + } + break; + case 'install': + case 'upgrade': + case 'upgrade-all': + if (isset($data['release_warnings'])) { + $this->_displayLine(''); + $this->_startTable(array( + 'border' => false, + 'caption' => 'Release Warnings' + )); + $this->_tableRow(array($data['release_warnings']), null, array(1 => array('wrap' => 55))); + $this->_endTable(); + $this->_displayLine(''); + } - $channelschecked = array(); - // convert all parameters into PEAR_Downloader_Package objects - foreach ($params as $i => $param) { - $params[$i] = &$this->newDownloaderPackage($this); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $err = $params[$i]->initialize($param); - PEAR::staticPopErrorHandling(); - if (!$err) { - // skip parameters that were missed by preferred_state - continue; - } + $this->_displayLine($data['data']); + break; + case 'search': + $this->_startTable($data); + if (isset($data['headline']) && is_array($data['headline'])) { + $this->_tableRow($data['headline'], array('bold' => true), array(1 => array('wrap' => 55))); + } - if (PEAR::isError($err)) { - if (!isset($this->_options['soft']) && $err->getMessage() !== '') { - $this->log(0, $err->getMessage()); + foreach($data['data'] as $category) { + foreach($category as $pkg) { + $this->_tableRow($pkg, null, array(1 => array('wrap' => 55))); + } } - $params[$i] = false; - if (is_object($param)) { - $param = $param->getChannel() . '/' . $param->getPackage(); + $this->_endTable(); + break; + case 'list-all': + if (!isset($data['data'])) { + $this->_displayLine('No packages in channel'); + break; } - if (!isset($this->_options['soft'])) { - $this->log(2, 'Package "' . $param . '" is not valid'); + $this->_startTable($data); + if (isset($data['headline']) && is_array($data['headline'])) { + $this->_tableRow($data['headline'], array('bold' => true), array(1 => array('wrap' => 55))); } - // Message logged above in a specific verbose mode, passing null to not show up on CLI - $this->pushError(null, PEAR_INSTALLER_SKIPPED); - } else { - do { - if ($params[$i] && $params[$i]->getType() == 'local') { - // bug #7090 skip channel.xml check for local packages - break; + foreach($data['data'] as $category) { + foreach($category as $pkg) { + unset($pkg[4], $pkg[5]); + $this->_tableRow($pkg, null, array(1 => array('wrap' => 55))); } + } - if ($params[$i] && !isset($channelschecked[$params[$i]->getChannel()]) && - !isset($this->_options['offline'])) { - $channelschecked[$params[$i]->getChannel()] = true; - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - if (!class_exists('System')) { - require_once 'phar://install-pear-nozlib.phar/' . 'System.php'; - } + $this->_endTable(); + break; + case 'config-show': + $data['border'] = false; + $opts = array( + 0 => array('wrap' => 30), + 1 => array('wrap' => 20), + 2 => array('wrap' => 35) + ); - $curchannel = &$this->_registry->getChannel($params[$i]->getChannel()); - if (PEAR::isError($curchannel)) { - PEAR::staticPopErrorHandling(); - return $this->raiseError($curchannel); - } + $this->_startTable($data); + if (isset($data['headline']) && is_array($data['headline'])) { + $this->_tableRow($data['headline'], array('bold' => true), $opts); + } - if (PEAR::isError($dir = $this->getDownloadDir())) { - PEAR::staticPopErrorHandling(); - break; + foreach ($data['data'] as $group) { + foreach ($group as $value) { + if ($value[2] == '') { + $value[2] = ""; } - $mirror = $this->config->get('preferred_mirror', null, - $params[$i]->getChannel()); - $a = $this->downloadHttp('http://' . $mirror . - '/channel.xml', $this->ui, $dir, null, $curchannel->lastModified()); - - PEAR::staticPopErrorHandling(); - if (PEAR::isError($a) || !$a) { - // Attempt fallback to https automatically - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $a = $this->downloadHttp('https://' . $mirror . - '/channel.xml', $this->ui, $dir, null, $curchannel->lastModified()); - - PEAR::staticPopErrorHandling(); - if (PEAR::isError($a) || !$a) { - break; - } - } - $this->log(0, 'WARNING: channel "' . $params[$i]->getChannel() . '" has ' . - 'updated its protocols, use "' . PEAR_RUNTYPE . ' channel-update ' . $params[$i]->getChannel() . - '" to update'); + $this->_tableRow($value, null, $opts); } - } while (false); + } - if ($params[$i] && !isset($this->_options['downloadonly'])) { - if (isset($this->_options['packagingroot'])) { - $checkdir = $this->_prependPath( - $this->config->get('php_dir', null, $params[$i]->getChannel()), - $this->_options['packagingroot']); - } else { - $checkdir = $this->config->get('php_dir', - null, $params[$i]->getChannel()); - } + $this->_endTable(); + break; + case 'remote-info': + $d = $data; + $data = array( + 'caption' => 'Package details:', + 'border' => false, + 'data' => array( + array("Latest", $data['stable']), + array("Installed", $data['installed']), + array("Package", $data['name']), + array("License", $data['license']), + array("Category", $data['category']), + array("Summary", $data['summary']), + array("Description", $data['description']), + ), + ); - while ($checkdir && $checkdir != '/' && !file_exists($checkdir)) { - $checkdir = dirname($checkdir); + if (isset($d['deprecated']) && $d['deprecated']) { + $conf = &PEAR_Config::singleton(); + $reg = $conf->getRegistry(); + $name = $reg->parsedPackageNameToString($d['deprecated'], true); + $data['data'][] = array('Deprecated! use', $name); + } + default: { + if (is_array($data)) { + $this->_startTable($data); + $count = count($data['data'][0]); + if ($count == 2) { + $opts = array(0 => array('wrap' => 25), + 1 => array('wrap' => 48) + ); + } elseif ($count == 3) { + $opts = array(0 => array('wrap' => 30), + 1 => array('wrap' => 20), + 2 => array('wrap' => 35) + ); + } else { + $opts = null; } - - if ($checkdir == '.') { - $checkdir = '/'; + if (isset($data['headline']) && is_array($data['headline'])) { + $this->_tableRow($data['headline'], + array('bold' => true), + $opts); } - if (!is_writeable($checkdir)) { - return PEAR::raiseError('Cannot install, php_dir for channel "' . - $params[$i]->getChannel() . '" is not writeable by the current user'); + foreach($data['data'] as $row) { + $this->_tableRow($row, null, $opts); } + $this->_endTable(); + } else { + $this->_displayLine($data); } } } + } - unset($channelschecked); - PEAR_Downloader_Package::removeDuplicates($params); - if (!count($params)) { - $a = array(); - return $a; + function log($text, $append_crlf = true) + { + if ($append_crlf) { + return $this->_displayLine($text); } - if (!isset($this->_options['nodeps']) && !isset($this->_options['offline'])) { - $reverify = true; - while ($reverify) { - $reverify = false; - foreach ($params as $i => $param) { - //PHP Bug 40768 / PEAR Bug #10944 - //Nested foreaches fail in PHP 5.2.1 - key($params); - $ret = $params[$i]->detectDependencies($params); - if (PEAR::isError($ret)) { - $reverify = true; - $params[$i] = false; - PEAR_Downloader_Package::removeDuplicates($params); - if (!isset($this->_options['soft'])) { - $this->log(0, $ret->getMessage()); - } - continue 2; - } - } - } - } + return $this->_display($text); + } - if (isset($this->_options['offline'])) { - $this->log(3, 'Skipping dependency download check, --offline specified'); + function bold($text) + { + if (empty($this->term['bold'])) { + return strtoupper($text); } - if (!count($params)) { - $a = array(); - return $a; - } + return $this->term['bold'] . $text . $this->term['normal']; + } - while (PEAR_Downloader_Package::mergeDependencies($params)); - PEAR_Downloader_Package::removeDuplicates($params, true); - $errorparams = array(); - if (PEAR_Downloader_Package::detectStupidDuplicates($params, $errorparams)) { - if (count($errorparams)) { - foreach ($errorparams as $param) { - $name = $this->_registry->parsedPackageNameToString($param->getParsedPackage()); - $this->pushError('Duplicate package ' . $name . ' found', PEAR_INSTALLER_FAILED); + function _displayHeading($title) + { + print $this->lp.$this->bold($title)."\n"; + print $this->lp.str_repeat("=", strlen($title))."\n"; + } + + function _startTable($params = array()) + { + $params['table_data'] = array(); + $params['widest'] = array(); // indexed by column + $params['highest'] = array(); // indexed by row + $params['ncols'] = 0; + $this->params = $params; + } + + function _tableRow($columns, $rowparams = array(), $colparams = array()) + { + $highest = 1; + for ($i = 0; $i < count($columns); $i++) { + $col = &$columns[$i]; + if (isset($colparams[$i]) && !empty($colparams[$i]['wrap'])) { + $col = wordwrap($col, $colparams[$i]['wrap']); + } + + if (strpos($col, "\n") !== false) { + $multiline = explode("\n", $col); + $w = 0; + foreach ($multiline as $n => $line) { + $len = strlen($line); + if ($len > $w) { + $w = $len; + } } - $a = array(); - return $a; + $lines = count($multiline); + } else { + $w = strlen($col); + } + + if (isset($this->params['widest'][$i])) { + if ($w > $this->params['widest'][$i]) { + $this->params['widest'][$i] = $w; + } + } else { + $this->params['widest'][$i] = $w; + } + + $tmp = count_chars($columns[$i], 1); + // handle unix, mac and windows formats + $lines = (isset($tmp[10]) ? $tmp[10] : (isset($tmp[13]) ? $tmp[13] : 0)) + 1; + if ($lines > $highest) { + $highest = $lines; } } - PEAR_Downloader_Package::removeInstalled($params); - if (!count($params)) { - $this->pushError('No valid packages found', PEAR_INSTALLER_FAILED); - $a = array(); - return $a; + if (count($columns) > $this->params['ncols']) { + $this->params['ncols'] = count($columns); } - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $err = $this->analyzeDependencies($params); - PEAR::popErrorHandling(); - if (!count($params)) { - $this->pushError('No valid packages found', PEAR_INSTALLER_FAILED); - $a = array(); - return $a; + $new_row = array( + 'data' => $columns, + 'height' => $highest, + 'rowparams' => $rowparams, + 'colparams' => $colparams, + ); + $this->params['table_data'][] = $new_row; + } + + function _endTable() + { + extract($this->params); + if (!empty($caption)) { + $this->_displayHeading($caption); } - $ret = array(); - $newparams = array(); - if (isset($this->_options['pretend'])) { - return $params; + if (count($table_data) === 0) { + return; } - $somefailed = false; - foreach ($params as $i => $package) { - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $pf = &$params[$i]->download(); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($pf)) { - if (!isset($this->_options['soft'])) { - $this->log(1, $pf->getMessage()); - $this->log(0, 'Error: cannot download "' . - $this->_registry->parsedPackageNameToString($package->getParsedPackage(), - true) . - '"'); + if (!isset($width)) { + $width = $widest; + } else { + for ($i = 0; $i < $ncols; $i++) { + if (!isset($width[$i])) { + $width[$i] = $widest[$i]; } - $somefailed = true; - continue; } - - $newparams[] = &$params[$i]; - $ret[] = array( - 'file' => $pf->getArchiveFile(), - 'info' => &$pf, - 'pkg' => $pf->getPackage() - ); } - if ($somefailed) { - // remove params that did not download successfully - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $err = $this->analyzeDependencies($newparams, true); - PEAR::popErrorHandling(); - if (!count($newparams)) { - $this->pushError('Download failed', PEAR_INSTALLER_FAILED); - $a = array(); - return $a; + $border = false; + if (empty($border)) { + $cellstart = ''; + $cellend = ' '; + $rowend = ''; + $padrowend = false; + $borderline = ''; + } else { + $cellstart = '| '; + $cellend = ' '; + $rowend = '|'; + $padrowend = true; + $borderline = '+'; + foreach ($width as $w) { + $borderline .= str_repeat('-', $w + strlen($cellstart) + strlen($cellend) - 1); + $borderline .= '+'; } } - $this->_downloadedPackages = $ret; - return $newparams; - } - - /** - * @param array all packages to be installed - */ - function analyzeDependencies(&$params, $force = false) - { - $hasfailed = $failed = false; - if (isset($this->_options['downloadonly'])) { - return; + if ($borderline) { + $this->_displayLine($borderline); } - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $redo = true; - $reset = false; - while ($redo) { - $redo = false; - foreach ($params as $i => $param) { - $deps = $param->getDeps(); - if (!$deps) { - $depchecker = &$this->getDependency2Object($this->config, $this->getOptions(), - $param->getParsedPackage(), PEAR_VALIDATE_DOWNLOADING); - $send = $param->getPackageFile(); + for ($i = 0; $i < count($table_data); $i++) { + extract($table_data[$i]); + if (!is_array($rowparams)) { + $rowparams = array(); + } - $installcheck = $depchecker->validatePackage($send, $this, $params); - if (PEAR::isError($installcheck)) { - if (!isset($this->_options['soft'])) { - $this->log(0, $installcheck->getMessage()); - } - $hasfailed = true; - $params[$i] = false; - $reset = true; - $redo = true; - $failed = false; - PEAR_Downloader_Package::removeDuplicates($params); - continue 2; + if (!is_array($colparams)) { + $colparams = array(); + } + + $rowlines = array(); + if ($height > 1) { + for ($c = 0; $c < count($data); $c++) { + $rowlines[$c] = preg_split('/(\r?\n|\r)/', $data[$c]); + if (count($rowlines[$c]) < $height) { + $rowlines[$c] = array_pad($rowlines[$c], $height, ''); } - continue; } - - if (!$reset && $param->alreadyValidated() && !$force) { - continue; + } else { + for ($c = 0; $c < count($data); $c++) { + $rowlines[$c] = array($data[$c]); } + } - if (count($deps)) { - $depchecker = &$this->getDependency2Object($this->config, $this->getOptions(), - $param->getParsedPackage(), PEAR_VALIDATE_DOWNLOADING); - $send = $param->getPackageFile(); - if ($send === null) { - $send = $param->getDownloadURL(); + for ($r = 0; $r < $height; $r++) { + $rowtext = ''; + for ($c = 0; $c < count($data); $c++) { + if (isset($colparams[$c])) { + $attribs = array_merge($rowparams, $colparams); + } else { + $attribs = $rowparams; } - $installcheck = $depchecker->validatePackage($send, $this, $params); - if (PEAR::isError($installcheck)) { - if (!isset($this->_options['soft'])) { - $this->log(0, $installcheck->getMessage()); - } - $hasfailed = true; - $params[$i] = false; - $reset = true; - $redo = true; - $failed = false; - PEAR_Downloader_Package::removeDuplicates($params); - continue 2; + $w = isset($width[$c]) ? $width[$c] : 0; + //$cell = $data[$c]; + $cell = $rowlines[$c][$r]; + $l = strlen($cell); + if ($l > $w) { + $cell = substr($cell, 0, $w); } - $failed = false; - if (isset($deps['required'])) { - foreach ($deps['required'] as $type => $dep) { - // note: Dependency2 will never return a PEAR_Error if ignore-errors - // is specified, so soft is needed to turn off logging - if (!isset($dep[0])) { - if (PEAR::isError($e = $depchecker->{"validate{$type}Dependency"}($dep, - true, $params))) { - $failed = true; - if (!isset($this->_options['soft'])) { - $this->log(0, $e->getMessage()); - } - } elseif (is_array($e) && !$param->alreadyValidated()) { - if (!isset($this->_options['soft'])) { - $this->log(0, $e[0]); - } - } - } else { - foreach ($dep as $d) { - if (PEAR::isError($e = - $depchecker->{"validate{$type}Dependency"}($d, - true, $params))) { - $failed = true; - if (!isset($this->_options['soft'])) { - $this->log(0, $e->getMessage()); - } - } elseif (is_array($e) && !$param->alreadyValidated()) { - if (!isset($this->_options['soft'])) { - $this->log(0, $e[0]); - } - } - } - } - } - - if (isset($deps['optional'])) { - foreach ($deps['optional'] as $type => $dep) { - if (!isset($dep[0])) { - if (PEAR::isError($e = - $depchecker->{"validate{$type}Dependency"}($dep, - false, $params))) { - $failed = true; - if (!isset($this->_options['soft'])) { - $this->log(0, $e->getMessage()); - } - } elseif (is_array($e) && !$param->alreadyValidated()) { - if (!isset($this->_options['soft'])) { - $this->log(0, $e[0]); - } - } - } else { - foreach ($dep as $d) { - if (PEAR::isError($e = - $depchecker->{"validate{$type}Dependency"}($d, - false, $params))) { - $failed = true; - if (!isset($this->_options['soft'])) { - $this->log(0, $e->getMessage()); - } - } elseif (is_array($e) && !$param->alreadyValidated()) { - if (!isset($this->_options['soft'])) { - $this->log(0, $e[0]); - } - } - } - } - } - } + if (isset($attribs['bold'])) { + $cell = $this->bold($cell); + } - $groupname = $param->getGroup(); - if (isset($deps['group']) && $groupname) { - if (!isset($deps['group'][0])) { - $deps['group'] = array($deps['group']); - } + if ($l < $w) { + // not using str_pad here because we may + // add bold escape characters to $cell + $cell .= str_repeat(' ', $w - $l); + } - $found = false; - foreach ($deps['group'] as $group) { - if ($group['attribs']['name'] == $groupname) { - $found = true; - break; - } - } + $rowtext .= $cellstart . $cell . $cellend; + } - if ($found) { - unset($group['attribs']); - foreach ($group as $type => $dep) { - if (!isset($dep[0])) { - if (PEAR::isError($e = - $depchecker->{"validate{$type}Dependency"}($dep, - false, $params))) { - $failed = true; - if (!isset($this->_options['soft'])) { - $this->log(0, $e->getMessage()); - } - } elseif (is_array($e) && !$param->alreadyValidated()) { - if (!isset($this->_options['soft'])) { - $this->log(0, $e[0]); - } - } - } else { - foreach ($dep as $d) { - if (PEAR::isError($e = - $depchecker->{"validate{$type}Dependency"}($d, - false, $params))) { - $failed = true; - if (!isset($this->_options['soft'])) { - $this->log(0, $e->getMessage()); - } - } elseif (is_array($e) && !$param->alreadyValidated()) { - if (!isset($this->_options['soft'])) { - $this->log(0, $e[0]); - } - } - } - } - } - } - } - } else { - foreach ($deps as $dep) { - if (PEAR::isError($e = $depchecker->validateDependency1($dep, $params))) { - $failed = true; - if (!isset($this->_options['soft'])) { - $this->log(0, $e->getMessage()); - } - } elseif (is_array($e) && !$param->alreadyValidated()) { - if (!isset($this->_options['soft'])) { - $this->log(0, $e[0]); - } - } - } - } - $params[$i]->setValidated(); + if (!$border) { + $rowtext = rtrim($rowtext); } - if ($failed) { - $hasfailed = true; - $params[$i] = false; - $reset = true; - $redo = true; - $failed = false; - PEAR_Downloader_Package::removeDuplicates($params); - continue 2; - } - } - } - PEAR::staticPopErrorHandling(); - if ($hasfailed && (isset($this->_options['ignore-errors']) || - isset($this->_options['nodeps']))) { - // this is probably not needed, but just in case - if (!isset($this->_options['soft'])) { - $this->log(0, 'WARNING: dependencies failed'); - } - } - } + $rowtext .= $rowend; + $this->_displayLine($rowtext); + } + } + + if ($borderline) { + $this->_displayLine($borderline); + } + } + + function _displayLine($text) + { + print "$this->lp$text\n"; + } + + function _display($text) + { + print $text; + } +} + * @author Tomas V.V. Cox + * @author Martin Jansen + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Installer.php 287446 2009-08-18 11:45:05Z dufuz $ + * @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 'phar://install-pear-nozlib.phar/' . 'OS/Guess.php'; +require_once 'phar://install-pear-nozlib.phar/' . '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 + * @author Tomas V.V. Cox + * @author Martin Jansen + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @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; /** - * Retrieve the directory that downloads will happen in - * @access private - * @return string + * PEAR_Registry object used by the installer + * @var PEAR_Registry */ - function getDownloadDir() - { - if (isset($this->_downloadDir)) { - return $this->_downloadDir; - } - $downloaddir = $this->config->get('download_dir'); - if (empty($downloaddir) || (is_dir($downloaddir) && !is_writable($downloaddir))) { - if (is_dir($downloaddir) && !is_writable($downloaddir)) { - $this->log(0, 'WARNING: configuration download directory "' . $downloaddir . - '" is not writeable. Change download_dir config variable to ' . - 'a writeable dir to avoid this warning'); - } - if (!class_exists('System')) { - require_once 'phar://install-pear-nozlib.phar/' . 'System.php'; - } - if (PEAR::isError($downloaddir = System::mktemp('-d'))) { - return $downloaddir; - } - $this->log(3, '+ tmp dir created at ' . $downloaddir); - } - if (!is_writable($downloaddir)) { - if (PEAR::isError(System::mkdir(array('-p', $downloaddir))) || - !is_writable($downloaddir)) { - return PEAR::raiseError('download directory "' . $downloaddir . - '" is not writeable. Change download_dir config variable to ' . - 'a writeable dir'); - } - } - return $this->_downloadDir = $downloaddir; - } + var $registry; - function setDownloadDir($dir) - { - if (!@is_writable($dir)) { - if (PEAR::isError(System::mkdir(array('-p', $dir)))) { - return PEAR::raiseError('download directory "' . $dir . - '" is not writeable. Change download_dir config variable to ' . - 'a writeable dir'); - } - } - $this->_downloadDir = $dir; - } + /** + * 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(); // }}} - // {{{ configSet() - function configSet($key, $value, $layer = 'user', $channel = false) + + // {{{ constructor + + /** + * PEAR_Installer constructor. + * + * @param object $ui user interface object (instance of PEAR_Frontend_*) + * + * @access public + */ + function PEAR_Installer(&$ui) { - $this->config->set($key, $value, $layer, $channel); - $this->_preferredState = $this->config->get('preferred_state', null, $channel); - if (!$this->_preferredState) { - // don't inadvertantly use a non-set preferred_state - $this->_preferredState = null; - } + parent::PEAR_Common(); + $this->setFrontendObject($ui); + $this->debug = $this->config->get('verbose'); } - // }}} - // {{{ setOptions() function setOptions($options) { $this->_options = $options; } - // }}} - // {{{ setOptions() - function getOptions() + function setConfig(&$config) { - return $this->_options; + $this->config = &$config; + $this->_registry = &$config->getRegistry(); } // }}} - /** - * For simpler unit-testing - * @param PEAR_Config - * @param int - * @param string - */ - function &getPackagefileObject(&$c, $d, $t = false) + function _removeBackups($files) { - if (!class_exists('PEAR_PackageFile')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile.php'; + foreach ($files as $path) { + $this->addFileOperation('removebackup', array($path)); } - $a = &new PEAR_PackageFile($c, $d, $t); - return $a; } - // {{{ _getPackageDownloadUrl() + // {{{ _deletePackageFiles() /** - * @param array output of {@link parsePackageName()} - * @access private + * 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 _getPackageDownloadUrl($parr) + function _deletePackageFiles($package, $channel = false, $backup = false) { - $curchannel = $this->config->get('default_channel'); - $this->configSet('default_channel', $parr['channel']); - // getDownloadURL returns an array. On error, it only contains information - // on the latest release as array(version, info). On success it contains - // array(version, info, download url string) - $state = isset($parr['state']) ? $parr['state'] : $this->config->get('preferred_state'); - if (!$this->_registry->channelExists($parr['channel'])) { - do { - if ($this->config->get('auto_discover') && $this->discover($parr['channel'])) { - break; - } - - $this->configSet('default_channel', $curchannel); - return PEAR::raiseError('Unknown remote channel: ' . $parr['channel']); - } while (false); + if (!$channel) { + $channel = 'pear.php.net'; } - $chan = &$this->_registry->getChannel($parr['channel']); - if (PEAR::isError($chan)) { - return $chan; + if (!strlen($package)) { + return $this->raiseError("No package to uninstall given"); } - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $version = $this->_registry->packageInfo($parr['package'], 'version', $parr['channel']); - $stability = $this->_registry->packageInfo($parr['package'], 'stability', $parr['channel']); - // package is installed - use the installed release stability level - if (!isset($parr['state']) && $stability !== null) { - $state = $stability['release']; + if (strtolower($package) == 'pear' && $channel == 'pear.php.net') { + // to avoid race conditions, include all possible needed files + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Task/Common.php'; + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Task/Replace.php'; + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Task/Unixeol.php'; + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Task/Windowseol.php'; + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/v1.php'; + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/v2.php'; + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/Generator/v1.php'; + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/Generator/v2.php'; } - PEAR::staticPopErrorHandling(); - $base2 = false; - $preferred_mirror = $this->config->get('preferred_mirror'); - if (!$chan->supportsREST($preferred_mirror) || - ( - !($base2 = $chan->getBaseURL('REST1.3', $preferred_mirror)) - && - !($base = $chan->getBaseURL('REST1.0', $preferred_mirror)) - ) - ) { - return $this->raiseError($parr['channel'] . ' is using a unsupported protocal - This should never happen.'); + $filelist = $this->_registry->packageInfo($package, 'filelist', $channel); + if ($filelist == null) { + return $this->raiseError("$channel/$package not installed"); } - if ($base2) { - $rest = &$this->config->getREST('1.3', $this->_options); - $base = $base2; - } else { - $rest = &$this->config->getREST('1.0', $this->_options); - } + $ret = array(); + foreach ($filelist as $file => $props) { + if (empty($props['installed_as'])) { + continue; + } - if (!isset($parr['version']) && !isset($parr['state']) && $version - && !PEAR::isError($version) - && !isset($this->_options['downloadonly'])) { - $url = $rest->getDownloadURL($base, $parr, $state, $version, $chan->getName()); - } else { - $url = $rest->getDownloadURL($base, $parr, $state, false, $chan->getName()); - } + $path = $props['installed_as']; + if ($backup) { + $this->addFileOperation('backup', array($path)); + $ret[] = $path; + } - if (PEAR::isError($url)) { - $this->configSet('default_channel', $curchannel); - return $url; + $this->addFileOperation('delete', array($path)); } - if ($parr['channel'] != $curchannel) { - $this->configSet('default_channel', $curchannel); + if ($backup) { + return $ret; } - if (!is_array($url)) { - return $url; - } + return true; + } - $url['raw'] = false; // no checking is necessary for REST - if (!is_array($url['info'])) { - return PEAR::raiseError('Invalid remote dependencies retrieved from REST - ' . - 'this should never happen'); + // }}} + // {{{ _installFile() + + /** + * @param string filename + * @param array attributes from 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($this->_options['force']) && - !isset($this->_options['downloadonly']) && - $version && - !PEAR::isError($version) && - !isset($parr['group']) - ) { - if (version_compare($version, $url['version'], '=')) { - return PEAR::raiseError($this->_registry->parsedPackageNameToString( - $parr, true) . ' is already installed and is the same as the ' . - 'released version ' . $url['version'], -976); + if (isset($atts['platform'])) { + if (empty($os)) { + $os = new OS_Guess(); } - if (version_compare($version, $url['version'], '>')) { - return PEAR::raiseError($this->_registry->parsedPackageNameToString( - $parr, true) . ' is already installed and is newer than detected ' . - 'released version ' . $url['version'], -976); + if (strlen($atts['platform']) && $atts['platform']{0} == '!') { + $negate = true; + $platform = substr($atts['platform'], 1); + } else { + $negate = false; + $platform = $atts['platform']; } - } - if (isset($url['info']['required']) || $url['compatible']) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/v2.php'; - $pf = new PEAR_PackageFile_v2; - $pf->setRawChannel($parr['channel']); - if ($url['compatible']) { - $pf->setRawCompatible($url['compatible']); + if ((bool) $os->matchSignature($platform) === $negate) { + $this->log(3, "skipped $file (meant for $atts[platform], we are ".$os->getSignature().")"); + return PEAR_INSTALLER_SKIPPED; } - } else { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/v1.php'; - $pf = new PEAR_PackageFile_v1; } + // }}} - $pf->setRawPackage($url['package']); - $pf->setDeps($url['info']); - if ($url['compatible']) { - $pf->setCompatible($url['compatible']); + $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"); } - $pf->setRawState($url['stability']); - $url['info'] = &$pf; - if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) { - $ext = '.tar'; + $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 { - $ext = '.tgz'; + $dest_file = $dest_dir . DIRECTORY_SEPARATOR . $atts['install-as']; } + $orig_file = $tmp_path . DIRECTORY_SEPARATOR . $file; - if (is_array($url) && isset($url['url'])) { - $url['url'] .= $ext; + // 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); } - return $url; - } - // }}} - // {{{ getDepPackageDownloadUrl() + $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); + } + // }}} - /** - * @param array dependency array - * @access private - */ - function _getDepPackageDownloadUrl($dep, $parr) - { - $xsdversion = isset($dep['rel']) ? '1.0' : '2.0'; - $curchannel = $this->config->get('default_channel'); - if (isset($dep['uri'])) { - $xsdversion = '2.0'; - $chan = &$this->_registry->getChannel('__uri'); - if (PEAR::isError($chan)) { - return $chan; + 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"); + } - $version = $this->_registry->packageInfo($dep['name'], 'version', '__uri'); - $this->configSet('default_channel', '__uri'); - } else { - if (isset($dep['channel'])) { - $remotechannel = $dep['channel']; - } else { - $remotechannel = 'pear.php.net'; - } + // 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 (!$this->_registry->channelExists($remotechannel)) { - do { - if ($this->config->get('auto_discover')) { - if ($this->discover($remotechannel)) { - break; - } - } - return PEAR::raiseError('Unknown remote channel: ' . $remotechannel); - } while (false); - } + if (!@copy($orig_file, $dest_file)) { + return $this->raiseError("failed to write $dest_file: $php_errormsg", + PEAR_INSTALLER_FAILED); + } - $chan = &$this->_registry->getChannel($remotechannel); - if (PEAR::isError($chan)) { - return $chan; - } + $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); + } - $version = $this->_registry->packageInfo($dep['name'], 'version', $remotechannel); - $this->configSet('default_channel', $remotechannel); - } + $contents = file_get_contents($orig_file); + if ($contents === false) { + $contents = ''; + } - $state = isset($parr['state']) ? $parr['state'] : $this->config->get('preferred_state'); - if (isset($parr['state']) && isset($parr['version'])) { - unset($parr['state']); - } + if (isset($atts['md5sum'])) { + $md5sum = md5($contents); + } - if (isset($dep['uri'])) { - $info = &$this->newDownloaderPackage($this); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - $err = $info->initialize($dep); - PEAR::staticPopErrorHandling(); - if (!$err) { - // skip parameters that were missed by preferred_state - return PEAR::raiseError('Cannot initialize dependency'); - } + $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); + } - if (PEAR::isError($err)) { - if (!isset($this->_options['soft'])) { - $this->log(0, $err->getMessage()); + $wp = @fopen($dest_file, "wb"); + if (!is_resource($wp)) { + return $this->raiseError("failed to create $dest_file: $php_errormsg", + PEAR_INSTALLER_FAILED); } - if (is_object($info)) { - $param = $info->getChannel() . '/' . $info->getPackage(); + if (@fwrite($wp, $contents) === false) { + return $this->raiseError("failed writing to $dest_file: $php_errormsg", + PEAR_INSTALLER_FAILED); } - return PEAR::raiseError('Package "' . $param . '" is not valid'); - } - return $info; - } elseif ($chan->supportsREST($this->config->get('preferred_mirror')) - && $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror')) - ) { - $rest = &$this->config->getREST('1.0', $this->_options); - $url = $rest->getDepDownloadURL($base, $xsdversion, $dep, $parr, - $state, $version, $chan->getName()); - if (PEAR::isError($url)) { - return $url; - } - if ($parr['channel'] != $curchannel) { - $this->configSet('default_channel', $curchannel); + fclose($wp); + // }}} } - if (!is_array($url)) { - return $url; - } + // {{{ 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); + } - $url['raw'] = false; // no checking is necessary for REST - if (!is_array($url['info'])) { - return PEAR::raiseError('Invalid remote dependencies retrieved from REST - ' . - 'this should never happen'); - } + if (!isset($options['ignore-errors'])) { + return $this->raiseError("bad md5sum for file $final_dest_file", + PEAR_INSTALLER_FAILED); + } - if (isset($url['info']['required'])) { - if (!class_exists('PEAR_PackageFile_v2')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/v2.php'; + 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"); + } + } } - $pf = new PEAR_PackageFile_v2; - $pf->setRawChannel($remotechannel); - } else { - if (!class_exists('PEAR_PackageFile_v1')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/v1.php'; + } + // }}} + // {{{ 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')); } - $pf = new PEAR_PackageFile_v1; + 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"); + } + } + } } - $pf->setRawPackage($url['package']); - $pf->setDeps($url['info']); - if ($url['compatible']) { - $pf->setCompatible($url['compatible']); - } + // }}} - $pf->setRawState($url['stability']); - $url['info'] = &$pf; - if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) { - $ext = '.tar'; + if ($atts['role'] == 'src') { + rename($dest_file, $final_dest_file); + $this->log(2, "renamed source file $dest_file to $final_dest_file"); } else { - $ext = '.tgz'; - } - - if (is_array($url) && isset($url['url'])) { - $url['url'] .= $ext; + $this->addFileOperation("rename", array($dest_file, $final_dest_file, + $atts['role'] == 'ext')); } - - return $url; } - return $this->raiseError($parr['channel'] . ' is using a unsupported protocal - This should never happen.'); - } - // }}} - // {{{ getPackageDownloadUrl() - - /** - * @deprecated in favor of _getPackageDownloadUrl - */ - function getPackageDownloadUrl($package, $version = null, $channel = false) - { - if ($version) { - $package .= "-$version"; - } - if ($this === null || $this->_registry === null) { - $package = "http://pear.php.net/get/$package"; + // Store the full path where the file was installed for easy unistall + if ($atts['role'] != 'script') { + $loc = $this->config->get($atts['role'] . '_dir'); } else { - $chan = $this->_registry->getChannel($channel); - if (PEAR::isError($chan)) { - return ''; - } - $package = "http://" . $chan->getServer() . "/get/$package"; + $loc = $this->config->get('bin_dir'); } - if (!extension_loaded("zlib")) { - $package .= '?uncompress=yes'; + + if ($atts['role'] != 'src') { + $this->addFileOperation("installed_as", array($file, $installed_as, + $loc, + dirname(substr($installedas_dest_file, strlen($loc))))); } - return $package; + + //$this->log(2, "installed: $dest_file"); + return PEAR_INSTALLER_OK; } // }}} - // {{{ getDownloadedPackages() + // {{{ _installFile2() /** - * Retrieve a list of downloaded packages after a call to {@link download()}. - * - * Also resets the list of downloaded packages. - * @return array + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @param string filename + * @param array attributes from tag in package.xml + * @param string path to install the file in + * @param array options from command-line + * @access private */ - function getDownloadedPackages() - { - $ret = $this->_downloadedPackages; - $this->_downloadedPackages = array(); - $this->_toDownload = array(); - return $ret; - } - - // }}} - // {{{ _downloadCallback() - - function _downloadCallback($msg, $params = null) + function _installFile2(&$pkg, $file, &$real_atts, $tmp_path, $options) { - switch ($msg) { - case 'saveas': - $this->log(1, "downloading $params ..."); - break; - case 'done': - $this->log(1, '...done: ' . number_format($params, 0, '', ',') . ' bytes'); - break; - case 'bytesread': - static $bytes; - if (empty($bytes)) { - $bytes = 0; - } - if (!($bytes % 10240)) { - $this->log(1, '.', false); - } - $bytes += $params; - break; - case 'start': - if($params[1] == -1) { - $length = "Unknown size"; - } else { - $length = number_format($params[1], 0, '', ',')." bytes"; - } - $this->log(1, "Starting to download {$params[0]} ($length)"); - break; + $atts = $real_atts; + if (!isset($this->_registry)) { + $this->_registry = &$this->config->getRegistry(); } - if (method_exists($this->ui, '_downloadCallback')) - $this->ui->_downloadCallback($msg, $params); - } - - // }}} - // {{{ _prependPath($path, $prepend) - function _prependPath($path, $prepend) - { - if (strlen($prepend) > 0) { - if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) { - if (preg_match('/^[a-z]:/i', $prepend)) { - $prepend = substr($prepend, 2); - } elseif ($prepend{0} != '\\') { - $prepend = "\\$prepend"; - } - $path = substr($path, 0, 2) . $prepend . substr($path, 2); - } else { - $path = $prepend . $path; - } + $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"); } - return $path; - } - // }}} - // {{{ pushError($errmsg, $code) - - /** - * @param string - * @param integer - */ - function pushError($errmsg, $code = -1) - { - array_push($this->_errorStack, array($errmsg, $code)); - } - - // }}} - // {{{ getErrorMsgs() - function getErrorMsgs() - { - $msgs = array(); - $errs = $this->_errorStack; - foreach ($errs as $err) { - $msgs[] = $err[0]; + $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; } - $this->_errorStack = array(); - return $msgs; - } - - // }}} - - /** - * for BC - */ - function sortPkgDeps(&$packages, $uninstall = false) - { - $uninstall ? - $this->sortPackagesForUninstall($packages) : - $this->sortPackagesForInstall($packages); - } - /** - * Sort a list of arrays of array(downloaded packagefilename) by dependency. - * - * This uses the topological sort method from graph theory, and the - * Structures_Graph package to properly sort dependencies for installation. - * @param array an array of downloaded PEAR_Downloader_Packages - * @return array array of array(packagefilename, package.xml contents) - */ - function sortPackagesForInstall(&$packages) - { - require_once 'phar://install-pear-nozlib.phar/' . 'Structures/Graph.php'; - require_once 'phar://install-pear-nozlib.phar/' . 'Structures/Graph/Node.php'; - require_once 'phar://install-pear-nozlib.phar/' . 'Structures/Graph/Manipulator/TopologicalSorter.php'; - $depgraph = new Structures_Graph(true); - $nodes = array(); - $reg = &$this->config->getRegistry(); - foreach ($packages as $i => $package) { - $pname = $reg->parsedPackageNameToString( - array( - 'channel' => $package->getChannel(), - 'package' => strtolower($package->getPackage()), - )); - $nodes[$pname] = new Structures_Graph_Node; - $nodes[$pname]->setData($packages[$i]); - $depgraph->addNode($nodes[$pname]); + if (!$role->isInstallable()) { + return; } - $deplinks = array(); - foreach ($nodes as $package => $node) { - $pf = &$node->getData(); - $pdeps = $pf->getDeps(true); - if (!$pdeps) { - continue; - } + $info = $role->processInstallation($pkg, $atts['attribs'], $file, $tmp_path); + if (PEAR::isError($info)) { + return $info; + } - if ($pf->getPackagexmlVersion() == '1.0') { - foreach ($pdeps as $dep) { - if ($dep['type'] != 'pkg' || - (isset($dep['optional']) && $dep['optional'] == 'yes')) { - continue; - } + 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); + } - $dname = $reg->parsedPackageNameToString( - array( - 'channel' => 'pear.php.net', - 'package' => strtolower($dep['name']), - )); + $final_dest_file = $installed_as = $dest_file; + if (isset($this->_options['packagingroot'])) { + $final_dest_file = $this->_prependPath($final_dest_file, + $this->_options['packagingroot']); + } - if (isset($nodes[$dname])) { - if (!isset($deplinks[$dname])) { - $deplinks[$dname] = array(); - } + $dest_dir = dirname($final_dest_file); + $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); + // }}} - $deplinks[$dname][$package] = 1; - // dependency is in installed packages - continue; - } + 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"); + } + } - $dname = $reg->parsedPackageNameToString( - array( - 'channel' => 'pecl.php.net', - 'package' => strtolower($dep['name']), - )); + $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 (isset($nodes[$dname])) { - if (!isset($deplinks[$dname])) { - $deplinks[$dname] = array(); - } + if (!@copy($orig_file, $dest_file)) { + return $this->raiseError("failed to write $dest_file: $php_errormsg", + PEAR_INSTALLER_FAILED); + } - $deplinks[$dname][$package] = 1; - // dependency is in installed packages - continue; - } + $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); } - } else { - // the only ordering we care about is: - // 1) subpackages must be installed before packages that depend on them - // 2) required deps must be installed before packages that depend on them - if (isset($pdeps['required']['subpackage'])) { - $t = $pdeps['required']['subpackage']; - if (!isset($t[0])) { - $t = array($t); - } - $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); + $contents = file_get_contents($orig_file); + if ($contents === false) { + $contents = ''; } - if (isset($pdeps['group'])) { - if (!isset($pdeps['group'][0])) { - $pdeps['group'] = array($pdeps['group']); - } + if (isset($attribs['md5sum'])) { + $md5sum = md5($contents); + } - foreach ($pdeps['group'] as $group) { - if (isset($group['subpackage'])) { - $t = $group['subpackage']; - if (!isset($t[0])) { - $t = array($t); - } + 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 + } - $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); + if (PEAR::isError($res)) { + return $res; } - } - } - if (isset($pdeps['optional']['subpackage'])) { - $t = $pdeps['optional']['subpackage']; - if (!isset($t[0])) { - $t = array($t); + $contents = $res; // save changes } - $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); - } - - if (isset($pdeps['required']['package'])) { - $t = $pdeps['required']['package']; - if (!isset($t[0])) { - $t = array($t); + $wp = @fopen($dest_file, "wb"); + if (!is_resource($wp)) { + return $this->raiseError("failed to create $dest_file: $php_errormsg", + PEAR_INSTALLER_FAILED); } - $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); - } - - if (isset($pdeps['group'])) { - if (!isset($pdeps['group'][0])) { - $pdeps['group'] = array($pdeps['group']); + if (fwrite($wp, $contents) === false) { + return $this->raiseError("failed writing to $dest_file: $php_errormsg", + PEAR_INSTALLER_FAILED); } - foreach ($pdeps['group'] as $group) { - if (isset($group['package'])) { - $t = $group['package']; - if (!isset($t[0])) { - $t = array($t); - } - - $this->_setupGraph($t, $reg, $deplinks, $nodes, $package); - } - } + fclose($wp); } } - } - $this->_detectDepCycle($deplinks); - foreach ($deplinks as $dependent => $parents) { - foreach ($parents as $parent => $unused) { - $nodes[$dependent]->connectTo($nodes[$parent]); - } - } + // {{{ check the md5 + if (isset($md5sum)) { + // Make sure the original md5 sum matches with expected + if (strtolower($md5sum) === strtolower($attribs['md5sum'])) { + $this->log(2, "md5sum ok: $final_dest_file"); - $installOrder = Structures_Graph_Manipulator_TopologicalSorter::sort($depgraph); - $ret = array(); - for ($i = 0; $i < count($installOrder); $i++) { - foreach ($installOrder[$i] as $index => $sortedpackage) { - $data = &$installOrder[$i][$index]->getData(); - $ret[] = &$nodes[$reg->parsedPackageNameToString( - array( - 'channel' => $data->getChannel(), - 'package' => strtolower($data->getPackage()), - ))]->getData(); - } - } + if (isset($contents)) { + // set md5 sum based on $content in case any tasks were run. + $real_atts['attribs']['md5sum'] = md5($contents); + } + } else { + if (empty($options['force'])) { + // delete the file + if (file_exists($dest_file)) { + unlink($dest_file); + } - $packages = $ret; - return; - } + if (!isset($options['ignore-errors'])) { + return $this->raiseError("bad md5sum for file $final_dest_file", + PEAR_INSTALLER_FAILED); + } - /** - * Detect recursive links between dependencies and break the cycles - * - * @param array - * @access private - */ - function _detectDepCycle(&$deplinks) - { - do { - $keepgoing = false; - foreach ($deplinks as $dep => $parents) { - foreach ($parents as $parent => $unused) { - // reset the parent cycle detector - $this->_testCycle(null, null, null); - if ($this->_testCycle($dep, $deplinks, $parent)) { - $keepgoing = true; - unset($deplinks[$dep][$parent]); - if (count($deplinks[$dep]) == 0) { - unset($deplinks[$dep]); + 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"); } - continue 3; } } + } else { + $real_atts['attribs']['md5sum'] = md5_file($dest_file); } - } while ($keepgoing); - } - function _testCycle($test, $deplinks, $dep) - { - static $visited = array(); - if ($test === null) { - $visited = array(); - return; - } - // this happens when a parent has a dep cycle on another dependency - // but the child is not part of the cycle - if (isset($visited[$dep])) { - return false; - } - $visited[$dep] = 1; - if ($test == $dep) { - return true; - } - if (isset($deplinks[$dep])) { - if (in_array($test, array_keys($deplinks[$dep]), true)) { - return true; - } - foreach ($deplinks[$dep] as $parent => $unused) { - if ($this->_testCycle($test, $deplinks, $parent)) { - return true; + // }}} + // {{{ 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')); } - } - } - return false; - } - - /** - * Set up the dependency for installation parsing - * - * @param array $t dependency information - * @param PEAR_Registry $reg - * @param array $deplinks list of dependency links already established - * @param array $nodes all existing package nodes - * @param string $package parent package name - * @access private - */ - function _setupGraph($t, $reg, &$deplinks, &$nodes, $package) - { - foreach ($t as $dep) { - $depchannel = !isset($dep['channel']) ? '__uri': $dep['channel']; - $dname = $reg->parsedPackageNameToString( - array( - 'channel' => $depchannel, - 'package' => strtolower($dep['name']), - )); - if (isset($nodes[$dname])) { - if (!isset($deplinks[$dname])) { - $deplinks[$dname] = array(); + 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"); + } + } } - $deplinks[$dname][$package] = 1; } - } - } - - function _dependsOn($a, $b) - { - return $this->_checkDepTree(strtolower($a->getChannel()), strtolower($a->getPackage()), $b); - } - - function _checkDepTree($channel, $package, $b, $checked = array()) - { - $checked[$channel][$package] = true; - if (!isset($this->_depTree[$channel][$package])) { - return false; - } + // }}} - if (isset($this->_depTree[$channel][$package][strtolower($b->getChannel())] - [strtolower($b->getPackage())])) { - return true; + 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())); + } } - foreach ($this->_depTree[$channel][$package] as $ch => $packages) { - foreach ($packages as $pa => $true) { - if ($this->_checkDepTree($ch, $pa, $b, $checked)) { - return true; - } - } + // 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))))); } - return false; + //$this->log(2, "installed: $dest_file"); + return PEAR_INSTALLER_OK; } - function _sortInstall($a, $b) - { - if (!$a->getDeps() && !$b->getDeps()) { - return 0; // neither package has dependencies, order is insignificant - } - if ($a->getDeps() && !$b->getDeps()) { - return 1; // $a must be installed after $b because $a has dependencies - } - if (!$a->getDeps() && $b->getDeps()) { - return -1; // $b must be installed after $a because $b has dependencies - } - // both packages have dependencies - if ($this->_dependsOn($a, $b)) { - return 1; - } - if ($this->_dependsOn($b, $a)) { - return -1; - } - return 0; - } + // }}} + // {{{ addFileOperation() /** - * Download a file through HTTP. Considers suggested file name in - * Content-disposition: header and can run a callback function for - * different events. The callback will be called with two - * parameters: the callback type, and parameters. The implemented - * callback types are: - * - * 'setup' called at the very beginning, parameter is a UI object - * that should be used for all output - * 'message' the parameter is a string with an informational message - * 'saveas' may be used to save with a different file name, the - * parameter is the filename that is about to be used. - * If a 'saveas' callback returns a non-empty string, - * that file name will be used as the filename instead. - * Note that $save_dir will not be affected by this, only - * the basename of the file. - * 'start' download is starting, parameter is number of bytes - * that are expected, or -1 if unknown - * 'bytesread' parameter is the number of bytes read so far - * 'done' download is complete, parameter is the total number - * of bytes read - * 'connfailed' if the TCP/SSL connection fails, this callback is called - * with array(host,port,errno,errmsg) - * 'writefailed' if writing to disk fails, this callback is called - * with array(destfile,errmsg) - * - * If an HTTP proxy has been configured (http_proxy PEAR_Config - * setting), the proxy will be used. + * Add a file operation to the current file transaction. * - * @param string $url the URL to download - * @param object $ui PEAR_Frontend_* instance - * @param object $config PEAR_Config instance - * @param string $save_dir directory to save file in - * @param mixed $callback function/method to call for status - * updates - * @param false|string|array $lastmodified header values to check against for caching - * use false to return the header values from this download - * @param false|array $accept Accept headers to send - * @param false|string $channel Channel to use for retrieving authentication - * @return string|array Returns the full path of the downloaded file or a PEAR - * error on failure. If the error is caused by - * socket-related errors, the error object will - * have the fsockopen error code available through - * getCode(). If caching is requested, then return the header - * values. + * @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. * - * @access public + * 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 downloadHttp($url, &$ui, $save_dir = '.', $callback = null, $lastmodified = null, - $accept = false, $channel = false) + function addFileOperation($type, $data) { - static $redirect = 0; - // always reset , so we are clean case of error - $wasredirect = $redirect; - $redirect = 0; - if ($callback) { - call_user_func($callback, 'setup', array(&$ui)); - } - - $info = parse_url($url); - if (!isset($info['scheme']) || !in_array($info['scheme'], array('http', 'https'))) { - return PEAR::raiseError('Cannot download non-http URL "' . $url . '"'); - } - - if (!isset($info['host'])) { - return PEAR::raiseError('Cannot download from non-URL "' . $url . '"'); + if (!is_array($data)) { + return $this->raiseError('Internal Error: $data in addFileOperation' + . ' must be an array, was ' . gettype($data)); } - $host = isset($info['host']) ? $info['host'] : null; - $port = isset($info['port']) ? $info['port'] : null; - $path = isset($info['path']) ? $info['path'] : null; - - if (isset($this)) { - $config = &$this->config; + if ($type == 'chmod') { + $octmode = decoct($data[0]); + $this->log(3, "adding to transaction: $type $octmode $data[1]"); } else { - $config = &PEAR_Config::singleton(); + $this->log(3, "adding to transaction: $type " . implode(" ", $data)); } + $this->file_operations[] = array($type, $data); + } - $proxy_host = $proxy_port = $proxy_user = $proxy_pass = ''; - if ($config->get('http_proxy') && - $proxy = parse_url($config->get('http_proxy'))) { - $proxy_host = isset($proxy['host']) ? $proxy['host'] : null; - if (isset($proxy['scheme']) && $proxy['scheme'] == 'https') { - $proxy_host = 'ssl://' . $proxy_host; - } - $proxy_port = isset($proxy['port']) ? $proxy['port'] : 8080; - $proxy_user = isset($proxy['user']) ? urldecode($proxy['user']) : null; - $proxy_pass = isset($proxy['pass']) ? urldecode($proxy['pass']) : null; - - if ($callback) { - call_user_func($callback, 'message', "Using HTTP proxy $host:$port"); - } - } + // }}} + // {{{ startFileTransaction() - if (empty($port)) { - $port = (isset($info['scheme']) && $info['scheme'] == 'https') ? 443 : 80; + function startFileTransaction($rollback_in_case = false) + { + if (count($this->file_operations) && $rollback_in_case) { + $this->rollbackFileTransaction(); } + $this->file_operations = array(); + } - $scheme = (isset($info['scheme']) && $info['scheme'] == 'https') ? 'https' : 'http'; + // }}} + // {{{ commitFileTransaction() - if ($proxy_host != '') { - $fp = @fsockopen($proxy_host, $proxy_port, $errno, $errstr); - if (!$fp) { - if ($callback) { - call_user_func($callback, 'connfailed', array($proxy_host, $proxy_port, - $errno, $errstr)); - } - return PEAR::raiseError("Connection to `$proxy_host:$proxy_port' failed: $errstr", $errno); - } + 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"; + } - if ($lastmodified === false || $lastmodified) { - $request = "GET $url HTTP/1.1\r\n"; - $request .= "Host: $host:$port\r\n"; - } else { - $request = "GET $url HTTP/1.0\r\n"; - $request .= "Host: $host\r\n"; - } - } else { - $network_host = $host; - if (isset($info['scheme']) && $info['scheme'] == 'https') { - $network_host = 'ssl://' . $host; + // 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; } - $fp = @fsockopen($network_host, $port, $errno, $errstr); - if (!$fp) { - if ($callback) { - call_user_func($callback, 'connfailed', array($host, $port, - $errno, $errstr)); + } + // }}} + $m = count($errors); + if ($m > 0) { + foreach ($errors as $error) { + if (!isset($this->_options['soft'])) { + $this->log(1, $error); } - return PEAR::raiseError("Connection to `$host:$port' failed: $errstr", $errno); } - if ($lastmodified === false || $lastmodified) { - $request = "GET $path HTTP/1.1\r\n"; - $request .= "Host: $host:$port\r\n"; - } else { - $request = "GET $path HTTP/1.0\r\n"; - $request .= "Host: $host\r\n"; + if (!isset($this->_options['ignore-errors'])) { + return false; } } - $ifmodifiedsince = ''; - if (is_array($lastmodified)) { - if (isset($lastmodified['Last-Modified'])) { - $ifmodifiedsince = 'If-Modified-Since: ' . $lastmodified['Last-Modified'] . "\r\n"; + $this->_dirtree = array(); + // {{{ really commit the transaction + foreach ($this->file_operations as $i => $tr) { + if (!$tr) { + // support removal of non-existing backups + continue; } - if (isset($lastmodified['ETag'])) { - $ifmodifiedsince .= "If-None-Match: $lastmodified[ETag]\r\n"; + 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': + $test = file_exists($data[1]) ? @unlink($data[1]) : 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; } - } else { - $ifmodifiedsince = ($lastmodified ? "If-Modified-Since: $lastmodified\r\n" : ''); } + // }}} + $this->log(2, "successfully committed $n file operations"); + $this->file_operations = array(); + return true; + } - $request .= $ifmodifiedsince . - "User-Agent: PEAR/1.8.0/PHP/" . PHP_VERSION . "\r\n"; + // }}} + // {{{ rollbackFileTransaction() - if (isset($this)) { // only pass in authentication for non-static calls - $username = $config->get('username', null, $channel); - $password = $config->get('password', null, $channel); - if ($username && $password) { - $tmp = base64_encode("$username:$password"); - $request .= "Authorization: Basic $tmp\r\n"; + 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(); + } - if ($proxy_host != '' && $proxy_user != '') { - $request .= 'Proxy-Authorization: Basic ' . - base64_encode($proxy_user . ':' . $proxy_pass) . "\r\n"; - } - - if ($accept) { - $request .= 'Accept: ' . implode(', ', $accept) . "\r\n"; - } - - $request .= "Connection: close\r\n"; - $request .= "\r\n"; - fwrite($fp, $request); - $headers = array(); - $reply = 0; - while (trim($line = fgets($fp, 1024))) { - if (preg_match('/^([^:]+):\s+(.*)\s*\\z/', $line, $matches)) { - $headers[strtolower($matches[1])] = trim($matches[2]); - } elseif (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) { - $reply = (int)$matches[1]; - if ($reply == 304 && ($lastmodified || ($lastmodified === false))) { - return false; - } + // }}} + // {{{ mkDirHier($dir) - if (!in_array($reply, array(200, 301, 302, 303, 305, 307))) { - return PEAR::raiseError("File $scheme://$host:$port$path not valid (received: $line)"); - } - } - } + function mkDirHier($dir) + { + $this->addFileOperation('mkdir', array($dir)); + return parent::mkDirHier($dir); + } - if ($reply != 200) { - if (!isset($headers['location'])) { - return PEAR::raiseError("File $scheme://$host:$port$path not valid (redirected but no location)"); - } + // }}} + // {{{ download() - if ($wasredirect > 4) { - return PEAR::raiseError("File $scheme://$host:$port$path not valid (redirection looped more than 5 times)"); - } + /** + * 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: + * + * + * array('pkg' => 'package_name', 'file' => '/path/to/local/file', + * 'info' => array() // parsed package.xml + * ); + * + * @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; + } - $redirect = $wasredirect + 1; - return $this->downloadHttp($headers['location'], - $ui, $save_dir, $callback, $lastmodified, $accept); - } + // }}} + // {{{ _parsePackageXml() - if (isset($headers['content-disposition']) && - preg_match('/\sfilename=\"([^;]*\S)\"\s*(;|\\z)/', $headers['content-disposition'], $matches)) { - $save_as = basename($matches[1]); + function _parsePackageXml(&$descfile, &$tmpdir) + { + if (substr($descfile, -4) == '.xml') { + $tmpdir = false; } else { - $save_as = basename($url); - } + // {{{ Decompress pack in tmp dir ------------------------------------- - if ($callback) { - $tmp = call_user_func($callback, 'saveas', $save_as); - if ($tmp) { - $save_as = $tmp; - } - } + // To allow relative package file names + $descfile = realpath($descfile); - $dest_file = $save_dir . DIRECTORY_SEPARATOR . $save_as; - if (!$wp = @fopen($dest_file, 'wb')) { - fclose($fp); - if ($callback) { - call_user_func($callback, 'writefailed', array($dest_file, $php_errormsg)); + if (PEAR::isError($tmpdir = System::mktemp('-d'))) { + return $tmpdir; } - return PEAR::raiseError("could not open $dest_file for writing"); - } - - $length = isset($headers['content-length']) ? $headers['content-length'] : -1; - - $bytes = 0; - if ($callback) { - call_user_func($callback, 'start', array(basename($dest_file), $length)); + $this->log(3, '+ tmp dir created at ' . $tmpdir); + // }}} } - while ($data = fread($fp, 1024)) { - $bytes += strlen($data); - if ($callback) { - call_user_func($callback, 'bytesread', $bytes); - } - if (!@fwrite($wp, $data)) { - fclose($fp); - if ($callback) { - call_user_func($callback, 'writefailed', array($dest_file, $php_errormsg)); + // 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 PEAR::raiseError("$dest_file: write failed ($php_errormsg)"); } - } - fclose($fp); - fclose($wp); - if ($callback) { - call_user_func($callback, 'done', $bytes); + return $this->raiseError('Installation failed: invalid package file'); } - if ($lastmodified === false || $lastmodified) { - if (isset($headers['etag'])) { - $lastmodified = array('ETag' => $headers['etag']); - } - if (isset($headers['last-modified'])) { - if (is_array($lastmodified)) { - $lastmodified['Last-Modified'] = $headers['last-modified']; - } else { - $lastmodified = $headers['last-modified']; - } - } - return array($dest_file, $lastmodified, $headers); - } - return $dest_file; + $descfile = $p->getPackageFile(); + return $p; } -} -// }}} - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Package.php,v 1.126 2009/03/07 21:51:52 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * Error code when parameter initialization fails because no releases - * exist within preferred_state, but releases do exist - */ -define('PEAR_DOWNLOADER_PACKAGE_STATE', -1003); -/** - * Error code when parameter initialization fails because no releases - * exist that will work with the existing PHP version - */ -define('PEAR_DOWNLOADER_PACKAGE_PHPVERSION', -1004); -/** - * Coordinates download parameters and manages their dependencies - * prior to downloading them. - * - * Input can come from three sources: - * - * - local files (archives or package.xml) - * - remote files (downloadable urls) - * - abstract package names - * - * The first two elements are handled cleanly by PEAR_PackageFile, but the third requires - * accessing pearweb's xml-rpc interface to determine necessary dependencies, and the - * format returned of dependencies is slightly different from that used in package.xml. - * - * This class hides the differences between these elements, and makes automatic - * dependency resolution a piece of cake. It also manages conflicts when - * two classes depend on incompatible dependencies, or differing versions of the same - * package dependency. In addition, download will not be attempted if the php version is - * not supported, PEAR installer version is not supported, or non-PECL extensions are not - * installed. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Downloader_Package -{ - /** - * @var PEAR_Downloader - */ - var $_downloader; - /** - * @var PEAR_Config - */ - var $_config; - /** - * @var PEAR_Registry - */ - var $_registry; - /** - * Used to implement packagingroot properly - * @var PEAR_Registry - */ - var $_installRegistry; - /** - * @var PEAR_PackageFile_v1|PEAR_PackageFile|v2 - */ - var $_packagefile; - /** - * @var array - */ - var $_parsedname; - /** - * @var array - */ - var $_downloadURL; - /** - * @var array - */ - var $_downloadDeps = array(); - /** - * @var boolean - */ - var $_valid = false; - /** - * @var boolean - */ - var $_analyzed = false; - /** - * if this or a parent package was invoked with Package-state, this is set to the - * state variable. - * - * This allows temporary reassignment of preferred_state for a parent package and all of - * its dependencies. - * @var string|false - */ - var $_explicitState = false; - /** - * If this package is invoked with Package#group, this variable will be true - */ - var $_explicitGroup = false; - /** - * Package type local|url - * @var string - */ - var $_type; - /** - * Contents of package.xml, if downloaded from a remote channel - * @var string|false - * @access private - */ - var $_rawpackagefile; + // }}} /** - * @var boolean - * @access private + * Set the list of PEAR_Downloader_Package objects to allow more sane + * dependency validation + * @param array */ - var $_validated = false; + function setDownloadedPackages(&$pkgs) + { + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $err = $this->analyzeDependencies($pkgs); + PEAR::popErrorHandling(); + if (PEAR::isError($err)) { + return $err; + } + $this->_downloadedPackages = &$pkgs; + } /** - * @param PEAR_Downloader + * Set the list of PEAR_Downloader_Package objects to allow more sane + * dependency validation + * @param array */ - function PEAR_Downloader_Package(&$downloader) + function setUninstallPackages(&$pkgs) { - $this->_downloader = &$downloader; - $this->_config = &$this->_downloader->config; - $this->_registry = &$this->_config->getRegistry(); - $options = $downloader->getOptions(); - if (isset($options['packagingroot'])) { - $this->_config->setInstallRoot($options['packagingroot']); - $this->_installRegistry = &$this->_config->getRegistry(); - $this->_config->setInstallRoot(false); - } else { - $this->_installRegistry = &$this->_registry; - } - $this->_valid = $this->_analyzed = false; + $this->_downloadedPackages = &$pkgs; + } + + function getInstallPackages() + { + return $this->_downloadedPackages; } + // {{{ install() + /** - * Parse the input and determine whether this is a local file, a remote uri, or an - * abstract package name. + * Installs the files within the package file specified. * - * This is the heart of the PEAR_Downloader_Package(), and is used in - * {@link PEAR_Downloader::download()} - * @param string - * @return bool|PEAR_Error + * @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 initialize($param) + function install($pkgfile, $options = array()) { - $origErr = $this->_fromFile($param); - if ($this->_valid) { - return true; + $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 = ''; + $pkg = $this->_parsePackageXml($descfile, $tmpdir); + if (PEAR::isError($pkg)) { + return $pkg; + } } - $options = $this->_downloader->getOptions(); - if (isset($options['offline'])) { - if (PEAR::isError($origErr) && !isset($options['soft'])) { - $this->_downloader->log(0, $origErr->getMessage()); + if (realpath($descfile) != realpath($pkgfile)) { + $tar = new Archive_Tar($pkgfile); + if (!$tar->extract($tmpdir)) { + return $this->raiseError("unable to unpack $pkgfile"); } + } - return PEAR::raiseError('Cannot download non-local package "' . $param . '"'); + $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']); } - $err = $this->_fromUrl($param); - if (PEAR::isError($err) || !$this->_valid) { - if ($this->_type == 'url') { - if (PEAR::isError($err) && !isset($options['soft'])) { - $this->_downloader->log(0, $err->getMessage()); + 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 = ''; + } - return PEAR::raiseError("Invalid or missing remote package file"); + // {{{ 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; } - $err = $this->_fromString($param); - if (PEAR::isError($err) || !$this->_valid) { - if (PEAR::isError($err) && $err->getCode() == PEAR_DOWNLOADER_PACKAGE_STATE) { - return false; // instruct the downloader to silently skip + // 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; + } } - if (isset($this->_type) && $this->_type == 'local' && PEAR::isError($origErr)) { - if (is_array($origErr->getUserInfo())) { - foreach ($origErr->getUserInfo() as $err) { - if (is_array($err)) { - $err = $err['message']; + if ($found) { + // subpackages can conflict with earlier versions of parent packages + $parentreg = $installregistry->packageInfo($param->getPackage(), null, $param->getChannel()); + $tmp = $test; + foreach ($tmp as $file => $info) { + if (is_array($info)) { + if (strtolower($info[1]) == strtolower($param->getPackage()) && + strtolower($info[0]) == strtolower($param->getChannel()) + ) { + if (isset($parentreg['filelist'][$file])) { + unset($parentreg['filelist'][$file]); + } else{ + $pos = strpos($file, '/'); + $basedir = substr($file, 0, $pos); + $file2 = substr($file, $pos + 1); + if (isset($parentreg['filelist'][$file2]['baseinstalldir']) + && $parentreg['filelist'][$file2]['baseinstalldir'] === $basedir + ) { + unset($parentreg['filelist'][$file2]); + } + } + + unset($test[$file]); + } + } else { + if (strtolower($param->getChannel()) != 'pear.php.net') { + continue; } - if (!isset($options['soft'])) { - $this->_downloader->log(0, $err); + if (strtolower($info) == strtolower($param->getPackage())) { + if (isset($parentreg['filelist'][$file])) { + unset($parentreg['filelist'][$file]); + } else{ + $pos = strpos($file, '/'); + $basedir = substr($file, 0, $pos); + $file2 = substr($file, $pos + 1); + if (isset($parentreg['filelist'][$file2]['baseinstalldir']) + && $parentreg['filelist'][$file2]['baseinstalldir'] === $basedir + ) { + unset($parentreg['filelist'][$file2]); + } + } + + unset($test[$file]); + } + } + } + + $pfk = &new PEAR_PackageFile($this->config); + $parentpkg = &$pfk->fromArray($parentreg); + $installregistry->updatePackage2($parentpkg); + } + + if ($param->getChannel() == 'pecl.php.net' && isset($options['upgrade'])) { + $tmp = $test; + foreach ($tmp as $file => $info) { + if (is_string($info)) { + // pear.php.net packages are always stored as strings + if (strtolower($info) == strtolower($param->getPackage())) { + // upgrading existing package + unset($test[$file]); } } } + } - if (!isset($options['soft'])) { - $this->_downloader->log(0, $origErr->getMessage()); + if (count($test)) { + $msg = "$channel/$pkgname: conflicting files found:\n"; + $longest = max(array_map("strlen", array_keys($test))); + $fmt = "%${longest}s (%s)\n"; + foreach ($test as $file => $info) { + if (!is_array($info)) { + $info = array('pear.php.net', $info); + } + $info = $info[0] . '/' . $info[1]; + $msg .= sprintf($fmt, $file, $info); } - if (is_array($param)) { - $param = $this->_registry->parsedPackageNameToString($param, true); + if (!isset($options['ignore-errors'])) { + return $this->raiseError($msg); } if (!isset($options['soft'])) { - $this->_downloader->log(2, "Cannot initialize '$param', invalid or missing package file"); + $this->log(0, "WARNING: $msg"); } - - // Passing no message back - already logged above - return PEAR::raiseError(); } + } + } + // }}} - if (PEAR::isError($err) && !isset($options['soft'])) { - $this->_downloader->log(0, $err->getMessage()); - } + $this->startFileTransaction(); - if (is_array($param)) { - $param = $this->_registry->parsedPackageNameToString($param, true); + if (empty($options['upgrade']) && empty($options['soft'])) { + // checks to do only when installing new packages + if ($channel == 'pecl.php.net') { + $test = $installregistry->packageExists($pkgname, $channel); + if (!$test) { + $test = $installregistry->packageExists($pkgname, 'pear.php.net'); } + } else { + $test = $installregistry->packageExists($pkgname, $channel); + } - if (!isset($options['soft'])) { - $this->_downloader->log(2, "Cannot initialize '$param', invalid or missing package file"); + if (empty($options['force']) && $test) { + return $this->raiseError("$channel/$pkgname is already installed"); + } + } else { + $usechannel = $channel; + if ($channel == 'pecl.php.net') { + $test = $installregistry->packageExists($pkgname, $channel); + if (!$test) { + $test = $installregistry->packageExists($pkgname, 'pear.php.net'); + $usechannel = 'pear.php.net'; } - - // Passing no message back - already logged above - return PEAR::raiseError(); + } else { + $test = $installregistry->packageExists($pkgname, $channel); } - } - return true; - } + if ($test) { + $v1 = $installregistry->packageInfo($pkgname, 'version', $usechannel); + $v2 = $pkg->getVersion(); + $cmp = version_compare("$v1", "$v2", 'gt'); + if (empty($options['force']) && !version_compare("$v2", "$v1", 'gt')) { + return $this->raiseError("upgrade to a newer version ($v2 is not newer than $v1)"); + } - /** - * Retrieve any non-local packages - * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|PEAR_Error - */ - function &download() - { - if (isset($this->_packagefile)) { - return $this->_packagefile; - } + if (empty($options['register-only'])) { + // when upgrading, remove old release's files first: + if (PEAR::isError($err = $this->_deletePackageFiles($pkgname, $usechannel, + true))) { + if (!isset($options['ignore-errors'])) { + return $this->raiseError($err); + } - if (isset($this->_downloadURL['url'])) { - $this->_isvalid = false; - $info = $this->getParsedPackage(); - foreach ($info as $i => $p) { - $info[$i] = strtolower($p); + if (!isset($options['soft'])) { + $this->log(0, 'WARNING: ' . $err->getMessage()); + } + } else { + $backedup = $err; + } + } } + } - $err = $this->_fromUrl($this->_downloadURL['url'], - $this->_registry->parsedPackageNameToString($this->_parsedname, true)); - $newinfo = $this->getParsedPackage(); - foreach ($newinfo as $i => $p) { - $newinfo[$i] = strtolower($p); - } + // {{{ Copy files to dest dir --------------------------------------- - if ($info != $newinfo) { - do { - if ($info['package'] == 'pecl.php.net' && $newinfo['package'] == 'pear.php.net') { - $info['package'] = 'pear.php.net'; - if ($info == $newinfo) { - // skip the channel check if a pecl package says it's a PEAR package - break; - } - } + // info from the package it self we want to access from _installFile + $this->pkginfo = &$pkg; + // used to determine whether we should build any C code + $this->source_files = 0; - return PEAR::raiseError('CRITICAL ERROR: We are ' . - $this->_registry->parsedPackageNameToString($info) . ', but the file ' . - 'downloaded claims to be ' . - $this->_registry->parsedPackageNameToString($this->getParsedPackage())); - } while (false); + $savechannel = $this->config->get('default_channel'); + if (empty($options['register-only']) && !is_dir($php_dir)) { + if (PEAR::isError(System::mkdir(array('-p'), $php_dir))) { + return $this->raiseError("no installation destination directory '$php_dir'\n"); } + } - if (PEAR::isError($err) || !$this->_valid) { - return $err; - } + $tmp_path = dirname($descfile); + if (substr($pkgfile, -4) != '.xml') { + $tmp_path .= DIRECTORY_SEPARATOR . $pkgname . '-' . $pkg->getVersion(); } - $this->_type = 'local'; - return $this->_packagefile; - } + $this->configSet('default_channel', $channel); + // {{{ install files - function &getPackageFile() - { - return $this->_packagefile; - } + $ver = $pkg->getPackagexmlVersion(); + if (version_compare($ver, '2.0', '>=')) { + $filelist = $pkg->getInstallationFilelist(); + } else { + $filelist = $pkg->getFileList(); + } - function &getDownloader() - { - return $this->_downloader; - } + if (PEAR::isError($filelist)) { + return $filelist; + } - function getType() - { - return $this->_type; - } + $p = &$installregistry->getPackage($pkgname, $channel); + $dirtree = (empty($options['register-only']) && $p) ? $p->getDirTree() : false; - /** - * Like {@link initialize()}, but operates on a dependency - */ - function fromDepURL($dep) - { - $this->_downloadURL = $dep; - if (isset($dep['uri'])) { - $options = $this->_downloader->getOptions(); - if (!extension_loaded("zlib") || isset($options['nocompress'])) { - $ext = '.tar'; + $pkg->resetFilelist(); + $pkg->setLastInstalledVersion($installregistry->packageInfo($pkg->getPackage(), + 'version', $pkg->getChannel())); + foreach ($filelist as $file => $atts) { + $this->expectError(PEAR_INSTALLER_FAILED); + if ($pkg->getPackagexmlVersion() == '1.0') { + $res = $this->_installFile($file, $atts, $tmp_path, $options); } else { - $ext = '.tgz'; + $res = $this->_installFile2($pkg, $file, $atts, $tmp_path, $options); } + $this->popExpect(); - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $err = $this->_fromUrl($dep['uri'] . $ext); - PEAR::popErrorHandling(); - if (PEAR::isError($err)) { - if (!isset($options['soft'])) { - $this->_downloader->log(0, $err->getMessage()); + if (PEAR::isError($res)) { + if (empty($options['ignore-errors'])) { + $this->rollbackFileTransaction(); + if ($res->getMessage() == "file does not exist") { + $this->raiseError("file $file in package.xml does not exist"); + } + + return $this->raiseError($res); } - return PEAR::raiseError('Invalid uri dependency "' . $dep['uri'] . $ext . '", ' . - 'cannot download'); - } - } else { - $this->_parsedname = - array( - 'package' => $dep['info']->getPackage(), - 'channel' => $dep['info']->getChannel(), - 'version' => $dep['version'] - ); - if (!isset($dep['nodefault'])) { - $this->_parsedname['group'] = 'default'; // download the default dependency group - $this->_explicitGroup = false; + if (!isset($options['soft'])) { + $this->log(0, "Warning: " . $res->getMessage()); + } } - $this->_rawpackagefile = $dep['raw']; - } - } - - function detectDependencies($params) - { - $options = $this->_downloader->getOptions(); - if (isset($options['downloadonly'])) { - return; - } - - if (isset($options['offline'])) { - $this->_downloader->log(3, 'Skipping dependency download check, --offline specified'); - return; - } - - $pname = $this->getParsedPackage(); - if (!$pname) { - return; + $real = isset($atts['attribs']) ? $atts['attribs'] : $atts; + if ($res == PEAR_INSTALLER_OK && $real['role'] != 'src') { + // Register files that were installed + $pkg->installedFile($file, $atts); + } } + // }}} - $deps = $this->getDeps(); - if (!$deps) { - return; + // {{{ compile and install source files + if ($this->source_files > 0 && empty($options['nobuild'])) { + if (PEAR::isError($err = + $this->_compileSourceFiles($savechannel, $pkg))) { + return $err; + } } + // }}} - if (isset($deps['required'])) { // package.xml 2.0 - return $this->_detect2($deps, $pname, $options, $params); + if (isset($backedup)) { + $this->_removeBackups($backedup); } - return $this->_detect1($deps, $pname, $options, $params); - } - - function setValidated() - { - $this->_validated = true; - } - - function alreadyValidated() - { - return $this->_validated; - } - - /** - * Remove packages to be downloaded that are already installed - * @param array of PEAR_Downloader_Package objects - * @static - */ - function removeInstalled(&$params) - { - if (!isset($params[0])) { - return; + if (!$this->commitFileTransaction()) { + $this->rollbackFileTransaction(); + $this->configSet('default_channel', $savechannel); + return $this->raiseError("commit failed", PEAR_INSTALLER_FAILED); } + // }}} - $options = $params[0]->_downloader->getOptions(); - if (!isset($options['downloadonly'])) { - foreach ($params as $i => $param) { - $package = $param->getPackage(); - $channel = $param->getChannel(); - // remove self if already installed with this version - // this does not need any pecl magic - we only remove exact matches - if ($param->_installRegistry->packageExists($package, $channel)) { - $packageVersion = $param->_installRegistry->packageInfo($package, 'version', $channel); - if (version_compare($packageVersion, $param->getVersion(), '==')) { - if (!isset($options['force'])) { - $info = $param->getParsedPackage(); - unset($info['version']); - unset($info['state']); - if (!isset($options['soft'])) { - $param->_downloader->log(1, 'Skipping package "' . - $param->getShortName() . - '", already installed as version ' . $packageVersion); - } - $params[$i] = false; - } - } elseif (!isset($options['force']) && !isset($options['upgrade']) && - !isset($options['soft'])) { - $info = $param->getParsedPackage(); - $param->_downloader->log(1, 'Skipping package "' . - $param->getShortName() . - '", already installed as version ' . $packageVersion); - $params[$i] = false; - } + $ret = false; + $installphase = 'install'; + $oldversion = false; + // {{{ Register that the package is installed ----------------------- + if (empty($options['upgrade'])) { + // if 'force' is used, replace the info in registry + $usechannel = $channel; + if ($channel == 'pecl.php.net') { + $test = $installregistry->packageExists($pkgname, $channel); + if (!$test) { + $test = $installregistry->packageExists($pkgname, 'pear.php.net'); + $usechannel = 'pear.php.net'; } + } else { + $test = $installregistry->packageExists($pkgname, $channel); } - } - PEAR_Downloader_Package::removeDuplicates($params); - } + if (!empty($options['force']) && $test) { + $oldversion = $installregistry->packageInfo($pkgname, 'version', $usechannel); + $installregistry->deletePackage($pkgname, $usechannel); + } + $ret = $installregistry->addPackage2($pkg); + } else { + if ($dirtree) { + $this->startFileTransaction(); + // attempt to delete empty directories + uksort($dirtree, array($this, '_sortDirs')); + foreach($dirtree as $dir => $notused) { + $this->addFileOperation('rmdir', array($dir)); + } + $this->commitFileTransaction(); + } - function _detect2($deps, $pname, $options, $params) - { - $this->_downloadDeps = array(); - $groupnotfound = false; - foreach (array('package', 'subpackage') as $packagetype) { - // get required dependency group - if (isset($deps['required'][$packagetype])) { - if (isset($deps['required'][$packagetype][0])) { - foreach ($deps['required'][$packagetype] as $dep) { - if (isset($dep['conflicts'])) { - // skip any package that this package conflicts with - continue; - } - $ret = $this->_detect2Dep($dep, $pname, 'required', $params); - if (is_array($ret)) { - $this->_downloadDeps[] = $ret; - } elseif (PEAR::isError($ret) && !isset($options['soft'])) { - $this->_downloader->log(0, $ret->getMessage()); - } - } - } else { - $dep = $deps['required'][$packagetype]; - if (!isset($dep['conflicts'])) { - // skip any package that this package conflicts with - $ret = $this->_detect2Dep($dep, $pname, 'required', $params); - if (is_array($ret)) { - $this->_downloadDeps[] = $ret; - } elseif (PEAR::isError($ret) && !isset($options['soft'])) { - $this->_downloader->log(0, $ret->getMessage()); - } - } + $usechannel = $channel; + if ($channel == 'pecl.php.net') { + $test = $installregistry->packageExists($pkgname, $channel); + if (!$test) { + $test = $installregistry->packageExists($pkgname, 'pear.php.net'); + $usechannel = 'pear.php.net'; } + } else { + $test = $installregistry->packageExists($pkgname, $channel); } - // get optional dependency group, if any - if (isset($deps['optional'][$packagetype])) { - $skipnames = array(); - if (!isset($deps['optional'][$packagetype][0])) { - $deps['optional'][$packagetype] = array($deps['optional'][$packagetype]); + // new: upgrade installs a package if it isn't installed + if (!$test) { + $ret = $installregistry->addPackage2($pkg); + } else { + if ($usechannel != $channel) { + $installregistry->deletePackage($pkgname, $usechannel); + $ret = $installregistry->addPackage2($pkg); + } else { + $ret = $installregistry->updatePackage2($pkg); } + $installphase = 'upgrade'; + } + } - foreach ($deps['optional'][$packagetype] as $dep) { - $skip = false; - if (!isset($options['alldeps'])) { - $dep['package'] = $dep['name']; - if (!isset($options['soft'])) { - $this->_downloader->log(3, 'Notice: package "' . - $this->_registry->parsedPackageNameToString($this->getParsedPackage(), - true) . '" optional dependency "' . - $this->_registry->parsedPackageNameToString(array('package' => - $dep['name'], 'channel' => 'pear.php.net'), true) . - '" will not be automatically downloaded'); - } - $skipnames[] = $this->_registry->parsedPackageNameToString($dep, true); - $skip = true; - unset($dep['package']); - } + if (!$ret) { + $this->configSet('default_channel', $savechannel); + return $this->raiseError("Adding package $channel/$pkgname to registry failed"); + } + // }}} - $ret = $this->_detect2Dep($dep, $pname, 'optional', $params); - if (PEAR::isError($ret) && !isset($options['soft'])) { - $this->_downloader->log(0, $ret->getMessage()); - } + $this->configSet('default_channel', $savechannel); + if (class_exists('PEAR_Task_Common')) { // this is auto-included if any tasks exist + if (PEAR_Task_Common::hasPostinstallTasks()) { + PEAR_Task_Common::runPostinstallTasks($installphase); + } + } - if (!$ret) { - $dep['package'] = $dep['name']; - $skip = count($skipnames) ? - $skipnames[count($skipnames) - 1] : ''; - if ($skip == - $this->_registry->parsedPackageNameToString($dep, true)) { - array_pop($skipnames); - } - } + return $pkg->toArray(true); + } - if (!$skip && is_array($ret)) { - $this->_downloadDeps[] = $ret; - } - } + // }}} - if (count($skipnames)) { - if (!isset($options['soft'])) { - $this->_downloader->log(1, 'Did not download optional dependencies: ' . - implode(', ', $skipnames) . - ', use --alldeps to download automatically'); - } - } - } + // {{{ _compileSourceFiles() + /** + * @param string + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + */ + function _compileSourceFiles($savechannel, &$filelist) + { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Builder.php'; + $this->log(1, "$this->source_files source files, building"); + $bob = &new PEAR_Builder($this->ui); + $bob->debug = $this->debug; + $built = $bob->build($filelist, array(&$this, '_buildCallback')); + if (PEAR::isError($built)) { + $this->rollbackFileTransaction(); + $this->configSet('default_channel', $savechannel); + return $built; + } - // get requested dependency group, if any - $groupname = $this->getGroup(); - $explicit = $this->_explicitGroup; - if (!$groupname) { - if (!$this->canDefault()) { - continue; + $this->log(1, "\nBuild process completed successfully"); + foreach ($built as $ext) { + $bn = basename($ext['file']); + list($_ext_name, $_ext_suff) = explode('.', $bn); + if ($_ext_suff == '.so' || $_ext_suff == '.dll') { + if (extension_loaded($_ext_name)) { + $this->raiseError("Extension '$_ext_name' already loaded. " . + 'Please unload it in your php.ini file ' . + 'prior to install or upgrade'); } - - $groupname = 'default'; // try the default dependency group + $role = 'ext'; + } else { + $role = 'src'; } - if ($groupnotfound) { - continue; + $dest = $ext['dest']; + $packagingroot = ''; + if (isset($this->_options['packagingroot'])) { + $packagingroot = $this->_options['packagingroot']; } - if (isset($deps['group'])) { - if (isset($deps['group']['attribs'])) { - if (strtolower($deps['group']['attribs']['name']) == strtolower($groupname)) { - $group = $deps['group']; - } elseif ($explicit) { - if (!isset($options['soft'])) { - $this->_downloader->log(0, 'Warning: package "' . - $this->_registry->parsedPackageNameToString($pname, true) . - '" has no dependency ' . 'group named "' . $groupname . '"'); - } + $copyto = $this->_prependPath($dest, $packagingroot); + $extra = $copyto != $dest ? " as '$copyto'" : ''; + $this->log(1, "Installing '$dest'$extra"); - $groupnotfound = true; - continue; - } - } else { - $found = false; - foreach ($deps['group'] as $group) { - if (strtolower($group['attribs']['name']) == strtolower($groupname)) { - $found = true; - break; - } + $copydir = dirname($copyto); + // pretty much nothing happens if we are only registering the install + if (empty($this->_options['register-only'])) { + if (!file_exists($copydir) || !is_dir($copydir)) { + if (!$this->mkDirHier($copydir)) { + return $this->raiseError("failed to mkdir $copydir", + PEAR_INSTALLER_FAILED); } - if (!$found) { - if ($explicit) { - if (!isset($options['soft'])) { - $this->_downloader->log(0, 'Warning: package "' . - $this->_registry->parsedPackageNameToString($pname, true) . - '" has no dependency ' . 'group named "' . $groupname . '"'); - } - } + $this->log(3, "+ mkdir $copydir"); + } - $groupnotfound = true; - continue; - } + if (!@copy($ext['file'], $copyto)) { + return $this->raiseError("failed to write $copyto ($php_errormsg)", PEAR_INSTALLER_FAILED); } - } - if (isset($group) && isset($group[$packagetype])) { - if (isset($group[$packagetype][0])) { - foreach ($group[$packagetype] as $dep) { - $ret = $this->_detect2Dep($dep, $pname, 'dependency group "' . - $group['attribs']['name'] . '"', $params); - if (is_array($ret)) { - $this->_downloadDeps[] = $ret; - } elseif (PEAR::isError($ret) && !isset($options['soft'])) { - $this->_downloader->log(0, $ret->getMessage()); - } - } - } else { - $ret = $this->_detect2Dep($group[$packagetype], $pname, - 'dependency group "' . - $group['attribs']['name'] . '"', $params); - if (is_array($ret)) { - $this->_downloadDeps[] = $ret; - } elseif (PEAR::isError($ret) && !isset($options['soft'])) { - $this->_downloader->log(0, $ret->getMessage()); + $this->log(3, "+ cp $ext[file] $copyto"); + $this->addFileOperation('rename', array($ext['file'], $copyto)); + if (!OS_WINDOWS) { + $mode = 0666 & ~(int)octdec($this->config->get('umask')); + $this->addFileOperation('chmod', array($mode, $copyto)); + if (!@chmod($copyto, $mode)) { + $this->log(0, "failed to change mode of $copyto ($php_errormsg)"); } } } + + + $data = array( + 'role' => $role, + 'name' => $bn, + 'installed_as' => $dest, + 'php_api' => $ext['php_api'], + 'zend_mod_api' => $ext['zend_mod_api'], + 'zend_ext_api' => $ext['zend_ext_api'], + ); + + if ($filelist->getPackageXmlVersion() == '1.0') { + $filelist->installedFile($bn, $data); + } else { + $filelist->installedFile($bn, array('attribs' => $data)); + } } } - function _detect2Dep($dep, $pname, $group, $params) + // }}} + function &getUninstallPackages() { - if (isset($dep['conflicts'])) { - return true; - } + return $this->_downloadedPackages; + } + // {{{ uninstall() - $options = $this->_downloader->getOptions(); - if (isset($dep['uri'])) { - return array('uri' => $dep['uri'], 'dep' => $dep);; - } + /** + * Uninstall a package + * + * This method removes all files installed by the application, and then + * removes any empty directories. + * @param string package name + * @param array Command-line options. Possibilities include: + * + * - installroot: base installation dir, if not the default + * - register-only : update registry but don't remove files + * - nodeps: do not process dependencies of other packages to ensure + * uninstallation does not break things + */ + function uninstall($package, $options = array()) + { + $installRoot = isset($options['installroot']) ? $options['installroot'] : ''; + $this->config->setInstallRoot($installRoot); - $testdep = $dep; - $testdep['package'] = $dep['name']; - if (PEAR_Downloader_Package::willDownload($testdep, $params)) { - $dep['package'] = $dep['name']; - if (!isset($options['soft'])) { - $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group . - ' dependency "' . - $this->_registry->parsedPackageNameToString($dep, true) . - '", will be installed'); - } - return false; + $this->installroot = ''; + $this->_registry = &$this->config->getRegistry(); + if (is_object($package)) { + $channel = $package->getChannel(); + $pkg = $package; + $package = $pkg->getPackage(); + } else { + $pkg = false; + $info = $this->_registry->parsePackageName($package, + $this->config->get('default_channel')); + $channel = $info['channel']; + $package = $info['package']; } - $options = $this->_downloader->getOptions(); - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - if ($this->_explicitState) { - $pname['state'] = $this->_explicitState; + $savechannel = $this->config->get('default_channel'); + $this->configSet('default_channel', $channel); + if (!is_object($pkg)) { + $pkg = $this->_registry->getPackage($package, $channel); } - $url = $this->_downloader->_getDepPackageDownloadUrl($dep, $pname); - if (PEAR::isError($url)) { - PEAR::popErrorHandling(); - return $url; + if (!$pkg) { + $this->configSet('default_channel', $savechannel); + return $this->raiseError($this->_registry->parsedPackageNameToString( + array( + 'channel' => $channel, + 'package' => $package + ), true) . ' not installed'); } - $dep['package'] = $dep['name']; - $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params, $group == 'optional' && - !isset($options['alldeps']), true); - PEAR::popErrorHandling(); - if (PEAR::isError($ret)) { - if (!isset($options['soft'])) { - $this->_downloader->log(0, $ret->getMessage()); - } - - return false; + if ($pkg->getInstalledBinary()) { + // this is just an alias for a binary package + return $this->_registry->deletePackage($package, $channel); } - // check to see if a dep is already installed and is the same or newer - if (!isset($dep['min']) && !isset($dep['max']) && !isset($dep['recommended'])) { - $oper = 'has'; - } else { - $oper = 'gt'; + $filelist = $pkg->getFilelist(); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + if (!class_exists('PEAR_Dependency2')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Dependency2.php'; } - // do not try to move this before getDepPackageDownloadURL - // we can't determine whether upgrade is necessary until we know what - // version would be downloaded - if (!isset($options['force']) && $this->isInstalled($ret, $oper)) { - $version = $this->_installRegistry->packageInfo($dep['name'], 'version', - $dep['channel']); - $dep['package'] = $dep['name']; - if (!isset($options['soft'])) { - $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group . - ' dependency "' . - $this->_registry->parsedPackageNameToString($dep, true) . - '" version ' . $url['version'] . ', already installed as version ' . - $version); + $depchecker = &new PEAR_Dependency2($this->config, $options, + array('channel' => $channel, 'package' => $package), + PEAR_VALIDATE_UNINSTALLING); + $e = $depchecker->validatePackageUninstall($this); + PEAR::staticPopErrorHandling(); + if (PEAR::isError($e)) { + if (!isset($options['ignore-errors'])) { + return $this->raiseError($e); } - return false; - } - - if (isset($dep['nodefault'])) { - $ret['nodefault'] = true; + if (!isset($options['soft'])) { + $this->log(0, 'WARNING: ' . $e->getMessage()); + } + } elseif (is_array($e)) { + if (!isset($options['soft'])) { + $this->log(0, $e[0]); + } } - return $ret; - } - - function _detect1($deps, $pname, $options, $params) - { - $this->_downloadDeps = array(); - $skipnames = array(); - foreach ($deps as $dep) { - $nodownload = false; - if (isset ($dep['type']) && $dep['type'] === 'pkg') { - $dep['channel'] = 'pear.php.net'; - $dep['package'] = $dep['name']; - switch ($dep['rel']) { - case 'not' : - continue 2; - case 'ge' : - case 'eq' : - case 'gt' : - case 'has' : - $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ? - 'required' : - 'optional'; - if (PEAR_Downloader_Package::willDownload($dep, $params)) { - $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group - . ' dependency "' . - $this->_registry->parsedPackageNameToString($dep, true) . - '", will be installed'); - continue 2; - } - $fakedp = new PEAR_PackageFile_v1; - $fakedp->setPackage($dep['name']); - // skip internet check if we are not upgrading (bug #5810) - if (!isset($options['upgrade']) && $this->isInstalled( - $fakedp, $dep['rel'])) { - $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group - . ' dependency "' . - $this->_registry->parsedPackageNameToString($dep, true) . - '", is already installed'); - continue 2; - } - } - - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - if ($this->_explicitState) { - $pname['state'] = $this->_explicitState; + $this->pkginfo = &$pkg; + // pretty much nothing happens if we are only registering the uninstall + if (empty($options['register-only'])) { + // {{{ Delete the files + $this->startFileTransaction(); + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + if (PEAR::isError($err = $this->_deletePackageFiles($package, $channel))) { + PEAR::popErrorHandling(); + $this->rollbackFileTransaction(); + $this->configSet('default_channel', $savechannel); + if (!isset($options['ignore-errors'])) { + return $this->raiseError($err); } - $url = $this->_downloader->_getDepPackageDownloadUrl($dep, $pname); - $chan = 'pear.php.net'; - if (PEAR::isError($url)) { - // check to see if this is a pecl package that has jumped - // from pear.php.net to pecl.php.net channel - if (!class_exists('PEAR_Dependency2')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Dependency2.php'; - } - - $newdep = PEAR_Dependency2::normalizeDep($dep); - $newdep = $newdep[0]; - $newdep['channel'] = 'pecl.php.net'; - $chan = 'pecl.php.net'; - $url = - $this->_downloader->_getDepPackageDownloadUrl($newdep, $pname); - $obj = &$this->_installRegistry->getPackage($dep['name']); - if (PEAR::isError($url)) { - PEAR::popErrorHandling(); - if ($obj !== null && $this->isInstalled($obj, $dep['rel'])) { - $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ? - 'required' : - 'optional'; - $dep['package'] = $dep['name']; - if (!isset($options['soft'])) { - $this->_downloader->log(3, $this->getShortName() . - ': Skipping ' . $group . ' dependency "' . - $this->_registry->parsedPackageNameToString($dep, true) . - '", already installed as version ' . $obj->getVersion()); - } - $skip = count($skipnames) ? - $skipnames[count($skipnames) - 1] : ''; - if ($skip == - $this->_registry->parsedPackageNameToString($dep, true)) { - array_pop($skipnames); - } - continue; - } else { - if (isset($dep['optional']) && $dep['optional'] == 'yes') { - $this->_downloader->log(2, $this->getShortName() . - ': Skipping optional dependency "' . - $this->_registry->parsedPackageNameToString($dep, true) . - '", no releases exist'); - continue; - } else { - return $url; - } - } - } + if (!isset($options['soft'])) { + $this->log(0, 'WARNING: ' . $err->getMessage()); } - + } else { PEAR::popErrorHandling(); - if (!isset($options['alldeps'])) { - if (isset($dep['optional']) && $dep['optional'] == 'yes') { - if (!isset($options['soft'])) { - $this->_downloader->log(3, 'Notice: package "' . - $this->getShortName() . - '" optional dependency "' . - $this->_registry->parsedPackageNameToString( - array('channel' => $chan, 'package' => - $dep['name']), true) . - '" will not be automatically downloaded'); - } - $skipnames[] = $this->_registry->parsedPackageNameToString( - array('channel' => $chan, 'package' => - $dep['name']), true); - $nodownload = true; - } - } + } - if (!isset($options['alldeps']) && !isset($options['onlyreqdeps'])) { - if (!isset($dep['optional']) || $dep['optional'] == 'no') { - if (!isset($options['soft'])) { - $this->_downloader->log(3, 'Notice: package "' . - $this->getShortName() . - '" required dependency "' . - $this->_registry->parsedPackageNameToString( - array('channel' => $chan, 'package' => - $dep['name']), true) . - '" will not be automatically downloaded'); - } - $skipnames[] = $this->_registry->parsedPackageNameToString( - array('channel' => $chan, 'package' => - $dep['name']), true); - $nodownload = true; - } + if (!$this->commitFileTransaction()) { + $this->rollbackFileTransaction(); + if (!isset($options['ignore-errors'])) { + return $this->raiseError("uninstall failed"); } - // check to see if a dep is already installed - // do not try to move this before getDepPackageDownloadURL - // we can't determine whether upgrade is necessary until we know what - // version would be downloaded - if (!isset($options['force']) && $this->isInstalled( - $url, $dep['rel'])) { - $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ? - 'required' : - 'optional'; - $dep['package'] = $dep['name']; - if (isset($newdep)) { - $version = $this->_installRegistry->packageInfo($newdep['name'], 'version', - $newdep['channel']); - } else { - $version = $this->_installRegistry->packageInfo($dep['name'], 'version'); - } - - $dep['version'] = $url['version']; - if (!isset($options['soft'])) { - $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group . - ' dependency "' . - $this->_registry->parsedPackageNameToString($dep, true) . - '", already installed as version ' . $version); - } - - $skip = count($skipnames) ? - $skipnames[count($skipnames) - 1] : ''; - if ($skip == - $this->_registry->parsedPackageNameToString($dep, true)) { - array_pop($skipnames); - } - - continue; + if (!isset($options['soft'])) { + $this->log(0, 'WARNING: uninstall failed'); } - - if ($nodownload) { - continue; + } else { + $this->startFileTransaction(); + $dirtree = $pkg->getDirTree(); + if ($dirtree === false) { + $this->configSet('default_channel', $savechannel); + return $this->_registry->deletePackage($package, $channel); } - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - if (isset($newdep)) { - $dep = $newdep; + // attempt to delete empty directories + uksort($dirtree, array($this, '_sortDirs')); + foreach($dirtree as $dir => $notused) { + $this->addFileOperation('rmdir', array($dir)); } - $dep['package'] = $dep['name']; - $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params, - isset($dep['optional']) && $dep['optional'] == 'yes' && - !isset($options['alldeps']), true); - PEAR::popErrorHandling(); - if (PEAR::isError($ret)) { + if (!$this->commitFileTransaction()) { + $this->rollbackFileTransaction(); + if (!isset($options['ignore-errors'])) { + return $this->raiseError("uninstall failed"); + } + if (!isset($options['soft'])) { - $this->_downloader->log(0, $ret->getMessage()); + $this->log(0, 'WARNING: uninstall failed'); } - continue; } - - $this->_downloadDeps[] = $ret; - } - } - - if (count($skipnames)) { - if (!isset($options['soft'])) { - $this->_downloader->log(1, 'Did not download dependencies: ' . - implode(', ', $skipnames) . - ', use --alldeps or --onlyreqdeps to download automatically'); } + // }}} } - } - function setDownloadURL($pkg) - { - $this->_downloadURL = $pkg; + $this->configSet('default_channel', $savechannel); + // Register that the package is no longer installed + return $this->_registry->deletePackage($package, $channel); } /** - * Set the package.xml object for this downloaded package + * Sort a list of arrays of array(downloaded packagefilename) by dependency. * - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 $pkg + * It also removes duplicate dependencies + * @param array an array of PEAR_PackageFile_v[1/2] objects + * @return array|PEAR_Error array of array(packagefilename, package.xml contents) */ - function setPackageFile(&$pkg) - { - $this->_packagefile = &$pkg; - } - - function getShortName() + function sortPackagesForUninstall(&$packages) { - return $this->_registry->parsedPackageNameToString(array('channel' => $this->getChannel(), - 'package' => $this->getPackage()), true); + $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->config); + if (PEAR::isError($this->_dependencyDB)) { + return $this->_dependencyDB; + } + usort($packages, array(&$this, '_sortUninstall')); } - function getParsedPackage() + function _sortUninstall($a, $b) { - if (isset($this->_packagefile) || isset($this->_parsedname)) { - return array('channel' => $this->getChannel(), - 'package' => $this->getPackage(), - 'version' => $this->getVersion()); + if (!$a->getDeps() && !$b->getDeps()) { + return 0; // neither package has dependencies, order is insignificant } - - return false; + if ($a->getDeps() && !$b->getDeps()) { + return -1; // $a must be installed after $b because $a has dependencies + } + if (!$a->getDeps() && $b->getDeps()) { + return 1; // $b must be installed after $a because $b has dependencies + } + // both packages have dependencies + if ($this->_dependencyDB->dependsOn($a, $b)) { + return -1; + } + if ($this->_dependencyDB->dependsOn($b, $a)) { + return 1; + } + return 0; } - function getDownloadURL() + // }}} + // {{{ _sortDirs() + function _sortDirs($a, $b) { - return $this->_downloadURL; + if (strnatcmp($a, $b) == -1) return 1; + if (strnatcmp($a, $b) == 1) return -1; + return 0; } - function canDefault() + // }}} + + // {{{ _buildCallback() + + function _buildCallback($what, $data) { - if (isset($this->_downloadURL) && isset($this->_downloadURL['nodefault'])) { - return false; + if (($what == 'cmdoutput' && $this->debug > 1) || + ($what == 'output' && $this->debug > 0)) { + $this->ui->outputData(rtrim($data), 'build'); } - - return true; } - function getPackage() + // }}} +} + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Role.php 278552 2009-04-10 19:42:49Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ + +/** + * base class for installer roles + */ +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Installer/Role/Common.php'; +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/XMLParser.php'; +/** + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Installer_Role +{ + /** + * Set up any additional configuration variables that file roles require + * + * Never call this directly, it is called by the PEAR_Config constructor + * @param PEAR_Config + * @access private + * @static + */ + function initializeConfig(&$config) { - if (isset($this->_packagefile)) { - return $this->_packagefile->getPackage(); - } elseif (isset($this->_downloadURL['info'])) { - return $this->_downloadURL['info']->getPackage(); + if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { + PEAR_Installer_Role::registerRoles(); } - return false; + foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $class => $info) { + if (!$info['config_vars']) { + continue; + } + + $config->_addConfigVars($class, $info['config_vars']); + } } /** - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @param PEAR_PackageFile_v2 + * @param string role name + * @param PEAR_Config + * @return PEAR_Installer_Role_Common + * @static */ - function isSubpackage(&$pf) + function &factory($pkg, $role, &$config) { - if (isset($this->_packagefile)) { - return $this->_packagefile->isSubpackage($pf); - } elseif (isset($this->_downloadURL['info'])) { - return $this->_downloadURL['info']->isSubpackage($pf); + if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { + PEAR_Installer_Role::registerRoles(); } - return false; - } + if (!in_array($role, PEAR_Installer_Role::getValidRoles($pkg->getPackageType()))) { + $a = false; + return $a; + } - function getPackageType() - { - if (isset($this->_packagefile)) { - return $this->_packagefile->getPackageType(); - } elseif (isset($this->_downloadURL['info'])) { - return $this->_downloadURL['info']->getPackageType(); + $a = 'PEAR_Installer_Role_' . ucfirst($role); + if (!class_exists($a)) { + require_once 'phar://install-pear-nozlib.phar/' . str_replace('_', '/', $a) . '.php'; } - return false; + $b = new $a($config); + return $b; } - function isBundle() + /** + * Get a list of file roles that are valid for the particular release type. + * + * For instance, src files serve no purpose in regular php releases. + * @param string + * @param bool clear cache + * @return array + * @static + */ + function getValidRoles($release, $clear = false) { - if (isset($this->_packagefile)) { - return $this->_packagefile->getPackageType() == 'bundle'; + if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { + PEAR_Installer_Role::registerRoles(); } - return false; - } - - function getPackageXmlVersion() - { - if (isset($this->_packagefile)) { - return $this->_packagefile->getPackagexmlVersion(); - } elseif (isset($this->_downloadURL['info'])) { - return $this->_downloadURL['info']->getPackagexmlVersion(); + static $ret = array(); + if ($clear) { + $ret = array(); } - return '1.0'; - } + if (isset($ret[$release])) { + return $ret[$release]; + } - function getChannel() - { - if (isset($this->_packagefile)) { - return $this->_packagefile->getChannel(); - } elseif (isset($this->_downloadURL['info'])) { - return $this->_downloadURL['info']->getChannel(); + $ret[$release] = array(); + foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) { + if (in_array($release, $okreleases['releasetypes'])) { + $ret[$release][] = strtolower(str_replace('PEAR_Installer_Role_', '', $role)); + } } - return false; + return $ret[$release]; } - function getURI() + /** + * Get a list of roles that require their files to be installed + * + * Most roles must be installed, but src and package roles, for instance + * are pseudo-roles. src files are compiled into a new extension. Package + * roles are actually fully bundled releases of a package + * @param bool clear cache + * @return array + * @static + */ + function getInstallableRoles($clear = false) { - if (isset($this->_packagefile)) { - return $this->_packagefile->getURI(); - } elseif (isset($this->_downloadURL['info'])) { - return $this->_downloadURL['info']->getURI(); + if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { + PEAR_Installer_Role::registerRoles(); } - return false; - } - - function getVersion() - { - if (isset($this->_packagefile)) { - return $this->_packagefile->getVersion(); - } elseif (isset($this->_downloadURL['version'])) { - return $this->_downloadURL['version']; + static $ret; + if ($clear) { + unset($ret); } - return false; - } + if (isset($ret)) { + return $ret; + } - function isCompatible($pf) - { - if (isset($this->_packagefile)) { - return $this->_packagefile->isCompatible($pf); - } elseif (isset($this->_downloadURL['info'])) { - return $this->_downloadURL['info']->isCompatible($pf); + $ret = array(); + foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) { + if ($okreleases['installable']) { + $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role)); + } } - return true; + return $ret; } - function setGroup($group) + /** + * Return an array of roles that are affected by the baseinstalldir attribute + * + * Most roles ignore this attribute, and instead install directly into: + * PackageName/filepath + * so a tests file tests/file.phpt is installed into PackageName/tests/filepath.php + * @param bool clear cache + * @return array + * @static + */ + function getBaseinstallRoles($clear = false) { - $this->_parsedname['group'] = $group; - } + if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { + PEAR_Installer_Role::registerRoles(); + } - function getGroup() - { - if (isset($this->_parsedname['group'])) { - return $this->_parsedname['group']; + static $ret; + if ($clear) { + unset($ret); } - return ''; - } + if (isset($ret)) { + return $ret; + } - function isExtension($name) - { - if (isset($this->_packagefile)) { - return $this->_packagefile->isExtension($name); - } elseif (isset($this->_downloadURL['info'])) { - if ($this->_downloadURL['info']->getPackagexmlVersion() == '2.0') { - return $this->_downloadURL['info']->getProvidesExtension() == $name; + $ret = array(); + foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) { + if ($okreleases['honorsbaseinstall']) { + $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role)); } - - return false; } - return false; + return $ret; } - function getDeps() + /** + * Return an array of file roles that should be analyzed for PHP content at package time, + * like the "php" role. + * @param bool clear cache + * @return array + * @static + */ + function getPhpRoles($clear = false) { - if (isset($this->_packagefile)) { - $ver = $this->_packagefile->getPackagexmlVersion(); - if (version_compare($ver, '2.0', '>=')) { - return $this->_packagefile->getDeps(true); - } + if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { + PEAR_Installer_Role::registerRoles(); + } - return $this->_packagefile->getDeps(); - } elseif (isset($this->_downloadURL['info'])) { - $ver = $this->_downloadURL['info']->getPackagexmlVersion(); - if (version_compare($ver, '2.0', '>=')) { - return $this->_downloadURL['info']->getDeps(true); - } + static $ret; + if ($clear) { + unset($ret); + } - return $this->_downloadURL['info']->getDeps(); + if (isset($ret)) { + return $ret; } - return array(); + $ret = array(); + foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) { + if ($okreleases['phpfile']) { + $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role)); + } + } + + return $ret; } /** - * @param array Parsed array from {@link PEAR_Registry::parsePackageName()} or a dependency - * returned from getDepDownloadURL() + * Scan through the Command directory looking for classes + * and see what commands they implement. + * @param string which directory to look for classes, defaults to + * the Installer/Roles subdirectory of + * the directory from where this file (__FILE__) is + * included. + * + * @return bool TRUE on success, a PEAR error on failure + * @access public + * @static */ - function isEqual($param) + function registerRoles($dir = null) { - if (is_object($param)) { - $channel = $param->getChannel(); - $package = $param->getPackage(); - if ($param->getURI()) { - $param = array( - 'channel' => $param->getChannel(), - 'package' => $param->getPackage(), - 'version' => $param->getVersion(), - 'uri' => $param->getURI(), - ); - } else { - $param = array( - 'channel' => $param->getChannel(), - 'package' => $param->getPackage(), - 'version' => $param->getVersion(), - ); - } - } else { - if (isset($param['uri'])) { - if ($this->getChannel() != '__uri') { - return false; - } - return $param['uri'] == $this->getURI(); + $GLOBALS['_PEAR_INSTALLER_ROLES'] = array(); + $parser = new PEAR_XMLParser; + if ($dir === null) { + $dir = dirname(__FILE__) . '/Role'; + } + + if (!file_exists($dir) || !is_dir($dir)) { + return PEAR::raiseError("registerRoles: opendir($dir) failed: does not exist/is not directory"); + } + + $dp = @opendir($dir); + if (empty($dp)) { + return PEAR::raiseError("registerRoles: opendir($dir) failed: $php_errmsg"); + } + + while ($entry = readdir($dp)) { + if ($entry{0} == '.' || substr($entry, -4) != '.xml') { + continue; } - $package = isset($param['package']) ? $param['package'] : $param['info']->getPackage(); - $channel = isset($param['channel']) ? $param['channel'] : $param['info']->getChannel(); - if (isset($param['rel'])) { - if (!class_exists('PEAR_Dependency2')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Dependency2.php'; + $class = "PEAR_Installer_Role_".substr($entry, 0, -4); + // List of roles + if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'][$class])) { + $file = "$dir/$entry"; + $parser->parse(file_get_contents($file)); + $data = $parser->getData(); + if (!is_array($data['releasetypes'])) { + $data['releasetypes'] = array($data['releasetypes']); } - $newdep = PEAR_Dependency2::normalizeDep($param); - $newdep = $newdep[0]; - } elseif (isset($param['min'])) { - $newdep = $param; + $GLOBALS['_PEAR_INSTALLER_ROLES'][$class] = $data; } } - if (isset($newdep)) { - if (!isset($newdep['min'])) { - $newdep['min'] = '0'; - } + closedir($dp); + ksort($GLOBALS['_PEAR_INSTALLER_ROLES']); + PEAR_Installer_Role::getBaseinstallRoles(true); + PEAR_Installer_Role::getInstallableRoles(true); + PEAR_Installer_Role::getPhpRoles(true); + PEAR_Installer_Role::getValidRoles('****', true); + return true; + } +} + * @copyright 1997-2006 The PHP Group + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Common.php 276383 2009-02-24 23:39:37Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/** + * Base class for all installation roles. + * + * This class allows extensibility of file roles. Packages with complex + * customization can now provide custom file roles along with the possibility of + * adding configuration values to match. + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2006 The PHP Group + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Installer_Role_Common +{ + /** + * @var PEAR_Config + * @access protected + */ + var $config; - if (!isset($newdep['max'])) { - $newdep['max'] = '100000000000000000000'; - } + /** + * @param PEAR_Config + */ + function PEAR_Installer_Role_Common(&$config) + { + $this->config = $config; + } - // use magic to support pecl packages suddenly jumping to the pecl channel - // we need to support both dependency possibilities - if ($channel == 'pear.php.net' && $this->getChannel() == 'pecl.php.net') { - if ($package == $this->getPackage()) { - $channel = 'pecl.php.net'; - } - } - if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') { - if ($package == $this->getPackage()) { - $channel = 'pear.php.net'; - } - } - return (strtolower($package) == strtolower($this->getPackage()) && - $channel == $this->getChannel() && - version_compare($newdep['min'], $this->getVersion(), '<=') && - version_compare($newdep['max'], $this->getVersion(), '>=')); + /** + * Retrieve configuration information about a file role from its XML info + * + * @param string $role Role Classname, as in "PEAR_Installer_Role_Data" + * @return array + */ + function getInfo($role) + { + if (empty($GLOBALS['_PEAR_INSTALLER_ROLES'][$role])) { + return PEAR::raiseError('Unknown Role class: "' . $role . '"'); } + return $GLOBALS['_PEAR_INSTALLER_ROLES'][$role]; + } - // use magic to support pecl packages suddenly jumping to the pecl channel - if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') { - if (strtolower($package) == strtolower($this->getPackage())) { - $channel = 'pear.php.net'; + /** + * This is called for each file to set up the directories and files + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @param array attributes from the tag + * @param string file name + * @return array an array consisting of: + * + * 1 the original, pre-baseinstalldir installation directory + * 2 the final installation directory + * 3 the full path to the final location of the file + * 4 the location of the pre-installation file + */ + function processInstallation($pkg, $atts, $file, $tmp_path, $layer = null) + { + $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . + ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this))))); + if (PEAR::isError($roleInfo)) { + return $roleInfo; + } + if (!$roleInfo['locationconfig']) { + return false; + } + if ($roleInfo['honorsbaseinstall']) { + $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'], $layer, + $pkg->getChannel()); + if (!empty($atts['baseinstalldir'])) { + $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir']; + } + } elseif ($roleInfo['unusualbaseinstall']) { + $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'], + $layer, $pkg->getChannel()) . DIRECTORY_SEPARATOR . $pkg->getPackage(); + if (!empty($atts['baseinstalldir'])) { + $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir']; } + } else { + $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'], + $layer, $pkg->getChannel()) . DIRECTORY_SEPARATOR . $pkg->getPackage(); } - - if (isset($param['version'])) { - return (strtolower($package) == strtolower($this->getPackage()) && - $channel == $this->getChannel() && - $param['version'] == $this->getVersion()); + 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; - return strtolower($package) == strtolower($this->getPackage()) && - $channel == $this->getChannel(); + // Clean up the DIRECTORY_SEPARATOR mess + $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR; + + list($dest_dir, $dest_file, $orig_file) = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"), + array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR, + DIRECTORY_SEPARATOR), + array($dest_dir, $dest_file, $orig_file)); + return array($save_destdir, $dest_dir, $dest_file, $orig_file); } - function isInstalled($dep, $oper = '==') + /** + * Get the name of the configuration variable that specifies the location of this file + * @return string|false + */ + function getLocationConfig() { - if (!$dep) { - return false; + $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . + ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this))))); + if (PEAR::isError($roleInfo)) { + return $roleInfo; } + return $roleInfo['locationconfig']; + } - if ($oper != 'ge' && $oper != 'gt' && $oper != 'has' && $oper != '==') { - return false; + /** + * Do any unusual setup here + * @param PEAR_Installer + * @param PEAR_PackageFile_v2 + * @param array file attributes + * @param string file name + */ + function setup(&$installer, $pkg, $atts, $file) + { + } + + function isExecutable() + { + $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . + ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this))))); + if (PEAR::isError($roleInfo)) { + return $roleInfo; } + return $roleInfo['executable']; + } - if (is_object($dep)) { - $package = $dep->getPackage(); - $channel = $dep->getChannel(); - if ($dep->getURI()) { - $dep = array( - 'uri' => $dep->getURI(), - 'version' => $dep->getVersion(), - ); - } else { - $dep = array( - 'version' => $dep->getVersion(), - ); - } - } else { - if (isset($dep['uri'])) { - $channel = '__uri'; - $package = $dep['dep']['name']; - } else { - $channel = $dep['info']->getChannel(); - $package = $dep['info']->getPackage(); - } + function isInstallable() + { + $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . + ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this))))); + if (PEAR::isError($roleInfo)) { + return $roleInfo; } + return $roleInfo['installable']; + } - $options = $this->_downloader->getOptions(); - $test = $this->_installRegistry->packageExists($package, $channel); - if (!$test && $channel == 'pecl.php.net') { - // do magic to allow upgrading from old pecl packages to new ones - $test = $this->_installRegistry->packageExists($package, 'pear.php.net'); - $channel = 'pear.php.net'; + function isExtension() + { + $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . + ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this))))); + if (PEAR::isError($roleInfo)) { + return $roleInfo; } + return $roleInfo['phpextension']; + } +} +?> + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Data.php 276383 2009-02-24 23:39:37Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ - if ($test) { - if (isset($dep['uri'])) { - if ($this->_installRegistry->packageInfo($package, 'uri', '__uri') == $dep['uri']) { - return true; - } - } +/** + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Installer_Role_Data extends PEAR_Installer_Role_Common {} +?> + php + extsrc + extbin + zendextsrc + zendextbin + 1 + data_dir + + + + + + + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Doc.php 276383 2009-02-24 23:39:37Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ - if (isset($options['upgrade'])) { - $packageVersion = $this->_installRegistry->packageInfo($package, 'version', $channel); - if (version_compare($packageVersion, $dep['version'], '>=')) { - return true; - } +/** + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Installer_Role_Doc extends PEAR_Installer_Role_Common {} +?> + php + extsrc + extbin + zendextsrc + zendextbin + 1 + doc_dir + + + + + + + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Php.php 276383 2009-02-24 23:39:37Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ - return false; - } +/** + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Installer_Role_Php extends PEAR_Installer_Role_Common {} +?> + php + extsrc + extbin + zendextsrc + zendextbin + 1 + php_dir + 1 + + 1 + + + + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Script.php 276383 2009-02-24 23:39:37Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ - return true; - } +/** + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Installer_Role_Script extends PEAR_Installer_Role_Common {} +?> + php + extsrc + extbin + zendextsrc + zendextbin + 1 + bin_dir + 1 + + + 1 + + + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: Test.php 276383 2009-02-24 23:39:37Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ - return false; - } +/** + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_Installer_Role_Test extends PEAR_Installer_Role_Common {} +?> + php + extsrc + extbin + zendextsrc + zendextbin + 1 + test_dir + + + + + + + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: PackageFile.php 286670 2009-08-02 14:16:06Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/** + * needed for PEAR_VALIDATE_* constants + */ +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Validate.php'; +/** + * Error code if the package.xml tag does not contain a valid version + */ +define('PEAR_PACKAGEFILE_ERROR_NO_PACKAGEVERSION', 1); +/** + * Error code if the package.xml tag version is not supported (version 1.0 and 1.1 are the only supported versions, + * currently + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_PACKAGEVERSION', 2); +/** + * Abstraction for the package.xml package description file + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_PackageFile +{ /** - * Detect duplicate package names with differing versions - * - * If a user requests to install Date 1.4.6 and Date 1.4.7, - * for instance, this is a logic error. This method - * detects this situation. - * - * @param array $params array of PEAR_Downloader_Package objects - * @param array $errorparams empty array - * @return array array of stupid duplicated packages in PEAR_Downloader_Package obejcts + * @var PEAR_Config */ - function detectStupidDuplicates($params, &$errorparams) - { - $existing = array(); - foreach ($params as $i => $param) { - $package = $param->getPackage(); - $channel = $param->getChannel(); - $group = $param->getGroup(); - if (!isset($existing[$channel . '/' . $package])) { - $existing[$channel . '/' . $package] = array(); - } - - if (!isset($existing[$channel . '/' . $package][$group])) { - $existing[$channel . '/' . $package][$group] = array(); - } - - $existing[$channel . '/' . $package][$group][] = $i; - } - - $indices = array(); - foreach ($existing as $package => $groups) { - foreach ($groups as $group => $dupes) { - if (count($dupes) > 1) { - $indices = $indices + $dupes; - } - } - } - - $indices = array_unique($indices); - foreach ($indices as $index) { - $errorparams[] = $params[$index]; - } - - return count($errorparams); - } + var $_config; + var $_debug; + /** + * Temp directory for uncompressing tgz files. + * @var string|false + */ + var $_tmpdir; + var $_logger = false; + /** + * @var boolean + */ + var $_rawReturn = false; /** - * @param array - * @param bool ignore install groups - for final removal of dupe packages - * @static + * + * @param PEAR_Config $config + * @param ? $debug + * @param string @tmpdir Optional temporary directory for uncompressing + * files */ - function removeDuplicates(&$params, $ignoreGroups = false) + function PEAR_PackageFile(&$config, $debug = false, $tmpdir = false) { - $pnames = array(); - foreach ($params as $i => $param) { - if (!$param) { - continue; - } - if ($param->getPackage()) { - if ($ignoreGroups) { - $group = ''; - } else { - $group = $param->getGroup(); - } - - $pnames[$i] = $param->getChannel() . '/' . - $param->getPackage() . '-' . $param->getVersion() . '#' . $group; - } - } - - $pnames = array_unique($pnames); - $unset = array_diff(array_keys($params), array_keys($pnames)); - $testp = array_flip($pnames); - foreach ($params as $i => $param) { - if (!$param) { - $unset[] = $i; - continue; - } - - if (!is_a($param, 'PEAR_Downloader_Package')) { - $unset[] = $i; - continue; - } - - $group = $ignoreGroups ? '' : $param->getGroup(); - if (!isset($testp[$param->getChannel() . '/' . $param->getPackage() . '-' . - $param->getVersion() . '#' . $group])) { - $unset[] = $i; - } - } - - foreach ($unset as $i) { - unset($params[$i]); - } - - $ret = array(); - foreach ($params as $i => $param) { - $ret[] = &$params[$i]; - } - - $params = array(); - foreach ($ret as $i => $param) { - $params[] = &$ret[$i]; - } + $this->_config = $config; + $this->_debug = $debug; + $this->_tmpdir = $tmpdir; } - function explicitState() + /** + * Turn off validation - return a parsed package.xml without checking it + * + * This is used by the package-validate command + */ + function rawReturn() { - return $this->_explicitState; + $this->_rawReturn = true; } - function setExplicitState($s) + function setLogger(&$l) { - $this->_explicitState = $s; + $this->_logger = &$l; } /** - * @static + * Create a PEAR_PackageFile_Parser_v* of a given version. + * @param int $version + * @return PEAR_PackageFile_Parser_v1|PEAR_PackageFile_Parser_v1 */ - function mergeDependencies(&$params) + function &parserFactory($version) { - $bundles = $newparams = array(); - foreach ($params as $i => $param) { - if (!$param->isBundle()) { - continue; - } - - $bundles[] = $i; - $pf = &$param->getPackageFile(); - $newdeps = array(); - $contents = $pf->getBundledPackages(); - if (!is_array($contents)) { - $contents = array($contents); - } - - foreach ($contents as $file) { - $filecontents = $pf->getFileContents($file); - $dl = &$param->getDownloader(); - $options = $dl->getOptions(); - if (PEAR::isError($dir = $dl->getDownloadDir())) { - return $dir; - } - - $fp = @fopen($dir . DIRECTORY_SEPARATOR . $file, 'wb'); - if (!$fp) { - continue; - } - - fwrite($fp, $filecontents, strlen($filecontents)); - fclose($fp); - if ($s = $params[$i]->explicitState()) { - $obj->setExplicitState($s); - } - - $obj = &new PEAR_Downloader_Package($params[$i]->getDownloader()); - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - if (PEAR::isError($dir = $dl->getDownloadDir())) { - PEAR::popErrorHandling(); - return $dir; - } - - $e = $obj->_fromFile($a = $dir . DIRECTORY_SEPARATOR . $file); - PEAR::popErrorHandling(); - if (PEAR::isError($e)) { - if (!isset($options['soft'])) { - $dl->log(0, $e->getMessage()); - } - continue; - } - - $j = &$obj; - if (!PEAR_Downloader_Package::willDownload($j, - array_merge($params, $newparams)) && !$param->isInstalled($j)) { - $newparams[] = &$j; - } - } - } - - foreach ($bundles as $i) { - unset($params[$i]); // remove bundles - only their contents matter for installation - } - - PEAR_Downloader_Package::removeDuplicates($params); // strip any unset indices - if (count($newparams)) { // add in bundled packages for install - foreach ($newparams as $i => $unused) { - $params[] = &$newparams[$i]; - } - $newparams = array(); - } - - foreach ($params as $i => $param) { - $newdeps = array(); - foreach ($param->_downloadDeps as $dep) { - $merge = array_merge($params, $newparams); - if (!PEAR_Downloader_Package::willDownload($dep, $merge) - && !$param->isInstalled($dep) - ) { - $newdeps[] = $dep; - } else { - //var_dump($dep); - // detect versioning conflicts here - } - } - - // convert the dependencies into PEAR_Downloader_Package objects for the next time around - $params[$i]->_downloadDeps = array(); - foreach ($newdeps as $dep) { - $obj = &new PEAR_Downloader_Package($params[$i]->getDownloader()); - if ($s = $params[$i]->explicitState()) { - $obj->setExplicitState($s); - } - - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $e = $obj->fromDepURL($dep); - PEAR::popErrorHandling(); - if (PEAR::isError($e)) { - if (!isset($options['soft'])) { - $obj->_downloader->log(0, $e->getMessage()); - } - continue; - } - - $e = $obj->detectDependencies($params); - if (PEAR::isError($e)) { - if (!isset($options['soft'])) { - $obj->_downloader->log(0, $e->getMessage()); - } - } - - $j = &$obj; - $newparams[] = &$j; - } - } - - if (count($newparams)) { - foreach ($newparams as $i => $unused) { - $params[] = &$newparams[$i]; - } - return true; + if (!in_array($version{0}, array('1', '2'))) { + $a = false; + return $a; } - return false; + include_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/Parser/v' . $version{0} . '.php'; + $version = $version{0}; + $class = "PEAR_PackageFile_Parser_v$version"; + $a = new $class; + return $a; } - /** - * @static + * For simpler unit-testing + * @return string */ - function willDownload($param, $params) + function getClassPrefix() { - if (!is_array($params)) { - return false; - } - - foreach ($params as $obj) { - if ($obj->isEqual($param)) { - return true; - } - } - - return false; + return 'PEAR_PackageFile_v'; } /** - * For simpler unit-testing - * @param PEAR_Config - * @param int - * @param string + * Create a PEAR_PackageFile_v* of a given version. + * @param int $version + * @return PEAR_PackageFile_v1|PEAR_PackageFile_v1 */ - function &getPackagefileObject(&$c, $d, $t = false) + function &factory($version) { - $a = &new PEAR_PackageFile($c, $d, $t); + if (!in_array($version{0}, array('1', '2'))) { + $a = false; + return $a; + } + + include_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/v' . $version{0} . '.php'; + $version = $version{0}; + $class = $this->getClassPrefix() . $version; + $a = new $class; return $a; } - /** - * This will retrieve from a local file if possible, and parse out - * a group name as well. The original parameter will be modified to reflect this. - * @param string|array can be a parsed package name as well - * @access private + * Create a PEAR_PackageFile_v* from its toArray() method + * + * WARNING: no validation is performed, the array is assumed to be valid, + * always parse from xml if you want validation. + * @param array $arr + * @return PEAR_PackageFileManager_v1|PEAR_PackageFileManager_v2 + * @uses factory() to construct the returned object. */ - function _fromFile(&$param) + function &fromArray($arr) { - $saveparam = $param; - if (is_string($param)) { - if (!@file_exists($param)) { - $test = explode('#', $param); - $group = array_pop($test); - if (@file_exists(implode('#', $test))) { - $this->setGroup($group); - $param = implode('#', $test); - $this->_explicitGroup = true; - } + if (isset($arr['xsdversion'])) { + $obj = &$this->factory($arr['xsdversion']); + if ($this->_logger) { + $obj->setLogger($this->_logger); } - if (@is_file($param)) { - $this->_type = 'local'; - $options = $this->_downloader->getOptions(); - if (isset($options['downloadonly'])) { - $pkg = &$this->getPackagefileObject($this->_config, - $this->_downloader->_debug); - } else { - if (PEAR::isError($dir = $this->_downloader->getDownloadDir())) { - return $dir; - } - $pkg = &$this->getPackagefileObject($this->_config, - $this->_downloader->_debug, $dir); - } - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $pf = &$pkg->fromAnyFile($param, PEAR_VALIDATE_INSTALLING); - PEAR::popErrorHandling(); - if (PEAR::isError($pf)) { - $this->_valid = false; - $param = $saveparam; - return $pf; - } - $this->_packagefile = &$pf; - if (!$this->getGroup()) { - $this->setGroup('default'); // install the default dependency group - } - return $this->_valid = true; - } + $obj->setConfig($this->_config); + $obj->fromArray($arr); + return $obj; + } + + if (isset($arr['package']['attribs']['version'])) { + $obj = &$this->factory($arr['package']['attribs']['version']); + } else { + $obj = &$this->factory('1.0'); + } + + if ($this->_logger) { + $obj->setLogger($this->_logger); } - $param = $saveparam; - return $this->_valid = false; + + $obj->setConfig($this->_config); + $obj->fromArray($arr); + return $obj; } - function _fromUrl($param, $saveparam = '') + /** + * Create a PEAR_PackageFile_v* from an XML string. + * @access public + * @param string $data contents of package.xml file + * @param int $state package state (one of PEAR_VALIDATE_* constants) + * @param string $file full path to the package.xml file (and the files + * it references) + * @param string $archive optional name of the archive that the XML was + * extracted from, if any + * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @uses parserFactory() to construct a parser to load the package. + */ + function &fromXmlString($data, $state, $file, $archive = false) { - if (!is_array($param) && (preg_match('#^(http|https|ftp)://#', $param))) { - $options = $this->_downloader->getOptions(); - $this->_type = 'url'; - $callback = $this->_downloader->ui ? - array(&$this->_downloader, '_downloadCallback') : null; - $this->_downloader->pushErrorHandling(PEAR_ERROR_RETURN); - if (PEAR::isError($dir = $this->_downloader->getDownloadDir())) { - $this->_downloader->popErrorHandling(); - return $dir; + if (preg_match('/]+version="([0-9]+\.[0-9]+)"/', $data, $packageversion)) { + if (!in_array($packageversion[1], array('1.0', '2.0', '2.1'))) { + return PEAR::raiseError('package.xml version "' . $packageversion[1] . + '" is not supported, only 1.0, 2.0, and 2.1 are supported.'); } - $this->_downloader->log(3, 'Downloading "' . $param . '"'); - $file = $this->_downloader->downloadHttp($param, $this->_downloader->ui, - $dir, $callback, null, false, $this->getChannel()); - $this->_downloader->popErrorHandling(); - if (PEAR::isError($file)) { - if (!empty($saveparam)) { - $saveparam = ", cannot download \"$saveparam\""; - } - $err = PEAR::raiseError('Could not download from "' . $param . - '"' . $saveparam . ' (' . $file->getMessage() . ')'); - return $err; + $object = &$this->parserFactory($packageversion[1]); + if ($this->_logger) { + $object->setLogger($this->_logger); } - if ($this->_rawpackagefile) { - require_once 'phar://install-pear-nozlib.phar/' . 'Archive/Tar.php'; - $tar = &new Archive_Tar($file); - $packagexml = $tar->extractInString('package2.xml'); - if (!$packagexml) { - $packagexml = $tar->extractInString('package.xml'); - } + $object->setConfig($this->_config); + $pf = $object->parse($data, $file, $archive); + if (PEAR::isError($pf)) { + return $pf; + } - if (str_replace(array("\n", "\r"), array('',''), $packagexml) != - str_replace(array("\n", "\r"), array('',''), $this->_rawpackagefile)) { - if ($this->getChannel() != 'pear.php.net') { - return PEAR::raiseError('CRITICAL ERROR: package.xml downloaded does ' . - 'not match value returned from xml-rpc'); - } + if ($this->_rawReturn) { + return $pf; + } - // be more lax for the existing PEAR packages that have not-ok - // characters in their package.xml - $this->_downloader->log(0, 'CRITICAL WARNING: The "' . - $this->getPackage() . '" package has invalid characters in its ' . - 'package.xml. The next version of PEAR may not be able to install ' . - 'this package for security reasons. Please open a bug report at ' . - 'http://pear.php.net/package/' . $this->getPackage() . '/bugs'); + if (!$pf->validate($state)) {; + if ($this->_config->get('verbose') > 0 + && $this->_logger && $pf->getValidationWarnings(false) + ) { + foreach ($pf->getValidationWarnings(false) as $warning) { + $this->_logger->log(0, 'ERROR: ' . $warning['message']); + } } + + $a = PEAR::raiseError('Parsing of package.xml from file "' . $file . '" failed', + 2, null, null, $pf->getValidationWarnings()); + return $a; } - // whew, download worked! - if (isset($options['downloadonly'])) { - $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->debug); - } else { - $dir = $this->_downloader->getDownloadDir(); - if (PEAR::isError($dir)) { - return $dir; + if ($this->_logger && $pf->getValidationWarnings(false)) { + foreach ($pf->getValidationWarnings() as $warning) { + $this->_logger->log(0, 'WARNING: ' . $warning['message']); } - $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->debug, $dir); } - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $pf = &$pkg->fromAnyFile($file, PEAR_VALIDATE_INSTALLING); - PEAR::popErrorHandling(); + if (method_exists($pf, 'flattenFilelist')) { + $pf->flattenFilelist(); // for v2 + } + + return $pf; + } elseif (preg_match('/]+version="([^"]+)"/', $data, $packageversion)) { + $a = PEAR::raiseError('package.xml file "' . $file . + '" has unsupported package.xml version "' . $packageversion[1] . '"'); + return $a; + } else { + if (!class_exists('PEAR_ErrorStack')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/ErrorStack.php'; + } + + PEAR_ErrorStack::staticPush('PEAR_PackageFile', + PEAR_PACKAGEFILE_ERROR_NO_PACKAGEVERSION, + 'warning', array('xml' => $data), 'package.xml "' . $file . + '" has no package.xml version'); + $object = &$this->parserFactory('1.0'); + $object->setConfig($this->_config); + $pf = $object->parse($data, $file, $archive); if (PEAR::isError($pf)) { - if (is_array($pf->getUserInfo())) { - foreach ($pf->getUserInfo() as $err) { - if (is_array($err)) { - $err = $err['message']; - } + return $pf; + } - if (!isset($options['soft'])) { - $this->_downloader->log(0, "Validation Error: $err"); - } - } - } + if ($this->_rawReturn) { + return $pf; + } - if (!isset($options['soft'])) { - $this->_downloader->log(0, $pf->getMessage()); + if (!$pf->validate($state)) { + $a = PEAR::raiseError('Parsing of package.xml from file "' . $file . '" failed', + 2, null, null, $pf->getValidationWarnings()); + return $a; + } + + if ($this->_logger && $pf->getValidationWarnings(false)) { + foreach ($pf->getValidationWarnings() as $warning) { + $this->_logger->log(0, 'WARNING: ' . $warning['message']); } + } - ///FIXME need to pass back some error code that we can use to match with to cancel all further operations - /// At least stop all deps of this package from being installed - $out = $saveparam ? $saveparam : $param; - $err = PEAR::raiseError('Download of "' . $out . '" succeeded, but it is not a valid package archive'); - $this->_valid = false; - return $err; + if (method_exists($pf, 'flattenFilelist')) { + $pf->flattenFilelist(); // for v2 } - $this->_packagefile = &$pf; - $this->setGroup('default'); // install the default dependency group - return $this->_valid = true; + return $pf; } - - return $this->_valid = false; } /** + * Register a temporary file or directory. When the destructor is + * executed, all registered temporary files and directories are + * removed. * - * @param string|array pass in an array of format - * array( - * 'package' => 'pname', - * ['channel' => 'channame',] - * ['version' => 'version',] - * ['state' => 'state',]) - * or a string of format [channame/]pname[-version|-state] + * @param string $file name of file or directory + * @return void */ - function _fromString($param) + function addTempFile($file) { - $options = $this->_downloader->getOptions(); - $channel = $this->_config->get('default_channel'); - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $pname = $this->_registry->parsePackageName($param, $channel); - PEAR::popErrorHandling(); - if (PEAR::isError($pname)) { - if ($pname->getCode() == 'invalid') { - $this->_valid = false; - return false; - } - - if ($pname->getCode() == 'channel') { - $parsed = $pname->getUserInfo(); - if ($this->_downloader->discover($parsed['channel'])) { - if ($this->_config->get('auto_discover')) { - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $pname = $this->_registry->parsePackageName($param, $channel); - PEAR::popErrorHandling(); - } else { - if (!isset($options['soft'])) { - $this->_downloader->log(0, 'Channel "' . $parsed['channel'] . - '" is not initialized, use ' . - '"pear channel-discover ' . $parsed['channel'] . '" to initialize' . - 'or pear config-set auto_discover 1'); - } - } - } - - if (PEAR::isError($pname)) { - if (!isset($options['soft'])) { - $this->_downloader->log(0, $pname->getMessage()); - } - - if (is_array($param)) { - $param = $this->_registry->parsedPackageNameToString($param); - } - - $err = PEAR::raiseError('invalid package name/package file "' . $param . '"'); - $this->_valid = false; - return $err; - } - } else { - if (!isset($options['soft'])) { - $this->_downloader->log(0, $pname->getMessage()); - } + $GLOBALS['_PEAR_Common_tempfiles'][] = $file; + } - $err = PEAR::raiseError('invalid package name/package file "' . $param . '"'); - $this->_valid = false; - return $err; - } + /** + * Create a PEAR_PackageFile_v* from a compresed Tar or Tgz file. + * @access public + * @param string contents of package.xml file + * @param int package state (one of PEAR_VALIDATE_* constants) + * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @using Archive_Tar to extract the files + * @using fromPackageFile() to load the package after the package.xml + * file is extracted. + */ + function &fromTgzFile($file, $state) + { + if (!class_exists('Archive_Tar')) { + require_once 'phar://install-pear-nozlib.phar/' . 'Archive/Tar.php'; } - if (!isset($this->_type)) { - $this->_type = 'rest'; + $tar = new Archive_Tar($file); + if ($this->_debug <= 1) { + $tar->pushErrorHandling(PEAR_ERROR_RETURN); } - $this->_parsedname = $pname; - $this->_explicitState = isset($pname['state']) ? $pname['state'] : false; - $this->_explicitGroup = isset($pname['group']) ? true : false; + $content = $tar->listContent(); + if ($this->_debug <= 1) { + $tar->popErrorHandling(); + } - $info = $this->_downloader->_getPackageDownloadUrl($pname); - if (PEAR::isError($info)) { - if ($info->getCode() != -976 && $pname['channel'] == 'pear.php.net') { - // try pecl - $pname['channel'] = 'pecl.php.net'; - if ($test = $this->_downloader->_getPackageDownloadUrl($pname)) { - if (!PEAR::isError($test)) { - $info = PEAR::raiseError($info->getMessage() . ' - package ' . - $this->_registry->parsedPackageNameToString($pname, true) . - ' can be installed with "pecl install ' . $pname['package'] . - '"'); - } else { - $pname['channel'] = 'pear.php.net'; - } - } else { - $pname['channel'] = 'pear.php.net'; - } + if (!is_array($content)) { + if (is_string($file) && strlen($file < 255) && + (!file_exists($file) || !@is_file($file))) { + $ret = PEAR::raiseError("could not open file \"$file\""); + return $ret; } - return $info; - } - - $this->_rawpackagefile = $info['raw']; - $ret = $this->_analyzeDownloadURL($info, $param, $pname); - if (PEAR::isError($ret)) { + $file = realpath($file); + $ret = PEAR::raiseError("Could not get contents of package \"$file\"". + '. Invalid tgz file.'); return $ret; } - if ($ret) { - $this->_downloadURL = $ret; - return $this->_valid = (bool) $ret; - } - } - - /** - * @param array output of package.getDownloadURL - * @param string|array|object information for detecting packages to be downloaded, and - * for errors - * @param array name information of the package - * @param array|null packages to be downloaded - * @param bool is this an optional dependency? - * @param bool is this any kind of dependency? - * @access private - */ - function _analyzeDownloadURL($info, $param, $pname, $params = null, $optional = false, - $isdependency = false) - { - if (!is_string($param) && PEAR_Downloader_Package::willDownload($param, $params)) { - return false; - } - - if ($info === false) { - $saveparam = !is_string($param) ? ", cannot download \"$param\"" : ''; - - // no releases exist - return PEAR::raiseError('No releases for package "' . - $this->_registry->parsedPackageNameToString($pname, true) . '" exist' . $saveparam); + if (!count($content) && !@is_file($file)) { + $ret = PEAR::raiseError("could not open file \"$file\""); + return $ret; } - if (strtolower($info['info']->getChannel()) != strtolower($pname['channel'])) { - $err = false; - if ($pname['channel'] == 'pecl.php.net') { - if ($info['info']->getChannel() != 'pear.php.net') { - $err = true; - } - } elseif ($info['info']->getChannel() == 'pecl.php.net') { - if ($pname['channel'] != 'pear.php.net') { - $err = true; - } - } else { - $err = true; + $xml = null; + $origfile = $file; + foreach ($content as $file) { + $name = $file['filename']; + if ($name == 'package2.xml') { // allow a .tgz to distribute both versions + $xml = $name; + break; } - if ($err) { - return PEAR::raiseError('SECURITY ERROR: package in channel "' . $pname['channel'] . - '" retrieved another channel\'s name for download! ("' . - $info['info']->getChannel() . '")'); + if ($name == 'package.xml') { + $xml = $name; + break; + } elseif (preg_match('/package.xml$/', $name, $match)) { + $xml = $name; + break; } } - $preferred_state = $this->_config->get('preferred_state'); - if (!isset($info['url'])) { - $package_version = $this->_registry->packageInfo($info['info']->getPackage(), - 'version', $info['info']->getChannel()); - if ($this->isInstalled($info)) { - if ($isdependency && version_compare($info['version'], $package_version, '<=')) { - // ignore bogus errors of "failed to download dependency" - // if it is already installed and the one that would be - // downloaded is older or the same version (Bug #7219) - return false; - } + if ($this->_tmpdir) { + $tmpdir = $this->_tmpdir; + } else { + $tmpdir = System::mkTemp(array('-t', $this->_config->get('temp_dir'), '-d', 'pear')); + if ($tmpdir === false) { + $ret = PEAR::raiseError("there was a problem with getting the configured temp directory"); + return $ret; } - if ($info['version'] === $package_version) { - if (!isset($options['soft'])) { - $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] . - '/' . $pname['package'] . '-' . $pname['version'] . ', additionally the suggested version' . - ' (' . $package_version . ') is the same as the locally installed one.'); - } + PEAR_PackageFile::addTempFile($tmpdir); + } - return false; + $this->_extractErrors(); + PEAR::staticPushErrorHandling(PEAR_ERROR_CALLBACK, array($this, '_extractErrors')); + if (!$xml || !$tar->extractList(array($xml), $tmpdir)) { + $extra = implode("\n", $this->_extractErrors()); + if ($extra) { + $extra = ' ' . $extra; } - if (version_compare($info['version'], $package_version, '<=')) { - if (!isset($options['soft'])) { - $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] . - '/' . $pname['package'] . '-' . $pname['version'] . ', additionally the suggested version' . - ' (' . $info['version'] . ') is a lower version than the locally installed one (' . $package_version . ').'); - } + PEAR::staticPopErrorHandling(); + $ret = PEAR::raiseError('could not extract the package.xml file from "' . + $origfile . '"' . $extra); + return $ret; + } - return false; - } + PEAR::staticPopErrorHandling(); + $ret = &PEAR_PackageFile::fromPackageFile("$tmpdir/$xml", $state, $origfile); + return $ret; + } - $instead = ', will instead download version ' . $info['version'] . - ', stability "' . $info['info']->getState() . '"'; - // releases exist, but we failed to get any - if (isset($this->_downloader->_options['force'])) { - if (isset($pname['version'])) { - $vs = ', version "' . $pname['version'] . '"'; - } elseif (isset($pname['state'])) { - $vs = ', stability "' . $pname['state'] . '"'; - } elseif ($param == 'dependency') { - if (!class_exists('PEAR_Common')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Common.php'; - } + /** + * helper for extracting Archive_Tar errors + * @var array + * @access private + */ + var $_extractErrors = array(); - if (!in_array($info['info']->getState(), - PEAR_Common::betterStates($preferred_state, true))) { - if ($optional) { - // don't spit out confusing error message - return $this->_downloader->_getPackageDownloadUrl( - array('package' => $pname['package'], - 'channel' => $pname['channel'], - 'version' => $info['version'])); - } - $vs = ' within preferred state "' . $preferred_state . - '"'; - } else { - if (!class_exists('PEAR_Dependency2')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Dependency2.php'; - } + /** + * helper callback for extracting Archive_Tar errors + * + * @param PEAR_Error|null $err + * @return array + * @access private + */ + function _extractErrors($err = null) + { + static $errors = array(); + if ($err === null) { + $e = $errors; + $errors = array(); + return $e; + } + $errors[] = $err->getMessage(); + } - if ($optional) { - // don't spit out confusing error message - return $this->_downloader->_getPackageDownloadUrl( - array('package' => $pname['package'], - 'channel' => $pname['channel'], - 'version' => $info['version'])); - } - $vs = PEAR_Dependency2::_getExtraString($pname); - $instead = ''; - } - } else { - $vs = ' within preferred state "' . $preferred_state . '"'; - } + /** + * Create a PEAR_PackageFile_v* from a package.xml file. + * + * @access public + * @param string $descfile name of package xml file + * @param int $state package state (one of PEAR_VALIDATE_* constants) + * @param string|false $archive name of the archive this package.xml came + * from, if any + * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @uses PEAR_PackageFile::fromXmlString to create the oject after the + * XML is loaded from the package.xml file. + */ + function &fromPackageFile($descfile, $state, $archive = false) + { + $fp = false; + if (is_string($descfile) && strlen($descfile) < 255 && + ( + !file_exists($descfile) || !is_file($descfile) || !is_readable($descfile) + || (!$fp = @fopen($descfile, 'r')) + ) + ) { + $a = PEAR::raiseError("Unable to open $descfile"); + return $a; + } - if (!isset($options['soft'])) { - $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] . - '/' . $pname['package'] . $vs . $instead); - } + // read the whole thing so we only get one cdata callback + // for each block of cdata + fclose($fp); + $data = file_get_contents($descfile); + $ret = &PEAR_PackageFile::fromXmlString($data, $state, $descfile, $archive); + return $ret; + } - // download the latest release - return $this->_downloader->_getPackageDownloadUrl( - array('package' => $pname['package'], - 'channel' => $pname['channel'], - 'version' => $info['version'])); + + /** + * Create a PEAR_PackageFile_v* from a .tgz archive or package.xml file. + * + * This method is able to extract information about a package from a .tgz + * archive or from a XML package definition file. + * + * @access public + * @param string $info file name + * @param int $state package state (one of PEAR_VALIDATE_* constants) + * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @uses fromPackageFile() if the file appears to be XML + * @uses fromTgzFile() to load all non-XML files + */ + function &fromAnyFile($info, $state) + { + if (is_dir($info)) { + $dir_name = realpath($info); + if (file_exists($dir_name . '/package.xml')) { + $info = PEAR_PackageFile::fromPackageFile($dir_name . '/package.xml', $state); + } elseif (file_exists($dir_name . '/package2.xml')) { + $info = PEAR_PackageFile::fromPackageFile($dir_name . '/package2.xml', $state); } else { - if (isset($info['php']) && $info['php']) { - $err = PEAR::raiseError('Failed to download ' . - $this->_registry->parsedPackageNameToString( - array('channel' => $pname['channel'], - 'package' => $pname['package']), - true) . - ', latest release is version ' . $info['php']['v'] . - ', but it requires PHP version "' . - $info['php']['m'] . '", use "' . - $this->_registry->parsedPackageNameToString( - array('channel' => $pname['channel'], 'package' => $pname['package'], - 'version' => $info['php']['v'])) . '" to install', - PEAR_DOWNLOADER_PACKAGE_PHPVERSION); - return $err; - } - - // construct helpful error message - if (isset($pname['version'])) { - $vs = ', version "' . $pname['version'] . '"'; - } elseif (isset($pname['state'])) { - $vs = ', stability "' . $pname['state'] . '"'; - } elseif ($param == 'dependency') { - if (!class_exists('PEAR_Common')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Common.php'; - } + $info = PEAR::raiseError("No package definition found in '$info' directory"); + } - if (!in_array($info['info']->getState(), - PEAR_Common::betterStates($preferred_state, true))) { - if ($optional) { - // don't spit out confusing error message, and don't die on - // optional dep failure! - return $this->_downloader->_getPackageDownloadUrl( - array('package' => $pname['package'], - 'channel' => $pname['channel'], - 'version' => $info['version'])); - } - $vs = ' within preferred state "' . $preferred_state . '"'; - } else { - if (!class_exists('PEAR_Dependency2')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Dependency2.php'; - } + return $info; + } - if ($optional) { - // don't spit out confusing error message, and don't die on - // optional dep failure! - return $this->_downloader->_getPackageDownloadUrl( - array('package' => $pname['package'], - 'channel' => $pname['channel'], - 'version' => $info['version'])); - } - $vs = PEAR_Dependency2::_getExtraString($pname); - } - } else { - $vs = ' within preferred state "' . $this->_downloader->config->get('preferred_state') . '"'; - } + $fp = false; + if (is_string($info) && strlen($info) < 255 && + (file_exists($info) || ($fp = @fopen($info, 'r'))) + ) { - $options = $this->_downloader->getOptions(); - // this is only set by the "download-all" command - if (isset($options['ignorepreferred_state'])) { - $err = PEAR::raiseError( - 'Failed to download ' . $this->_registry->parsedPackageNameToString( - array('channel' => $pname['channel'], 'package' => $pname['package']), - true) - . $vs . - ', latest release is version ' . $info['version'] . - ', stability "' . $info['info']->getState() . '", use "' . - $this->_registry->parsedPackageNameToString( - array('channel' => $pname['channel'], 'package' => $pname['package'], - 'version' => $info['version'])) . '" to install', - PEAR_DOWNLOADER_PACKAGE_STATE); - return $err; - } + if ($fp) { + fclose($fp); + } - // Checks if the user has a package installed already and checks the release against - // the state against the installed package, this allows upgrades for packages - // with lower stability than the preferred_state - $stability = $this->_registry->packageInfo($pname['package'], 'stability', $pname['channel']); - if (!$this->isInstalled($info) - || !in_array($info['info']->getState(), PEAR_Common::betterStates($stability['release'], true)) - ) { - $err = PEAR::raiseError( - 'Failed to download ' . $this->_registry->parsedPackageNameToString( - array('channel' => $pname['channel'], 'package' => $pname['package']), - true) - . $vs . - ', latest release is version ' . $info['version'] . - ', stability "' . $info['info']->getState() . '", use "' . - $this->_registry->parsedPackageNameToString( - array('channel' => $pname['channel'], 'package' => $pname['package'], - 'version' => $info['version'])) . '" to install'); - return $err; + $tmp = substr($info, -4); + if ($tmp == '.xml') { + $info = &PEAR_PackageFile::fromPackageFile($info, $state); + } elseif ($tmp == '.tar' || $tmp == '.tgz') { + $info = &PEAR_PackageFile::fromTgzFile($info, $state); + } else { + $fp = fopen($info, 'r'); + $test = fread($fp, 5); + fclose($fp); + if ($test == '_downloader->log(0, - 'WARNING: "' . - $this->_registry->parsedPackageNameToString( - array('channel' => $info['info']->getChannel(), - 'package' => $info['info']->getPackage()), true) . - '" is deprecated in favor of "' . - $this->_registry->parsedPackageNameToString($info['deprecated'], true) . - '"'); + return $info; } + $info = PEAR::raiseError("Cannot open '$info' for parsing"); return $info; } -} - * @copyright 2004-2008 Greg Beaver - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: ErrorStack.php,v 1.29 2009/02/24 23:38:22 dufuz Exp $ - * @link http://pear.php.net/package/PEAR_ErrorStack - */ - -/** - * Singleton storage - * - * Format: - *
- * array(
- *  'package1' => PEAR_ErrorStack object,
- *  'package2' => PEAR_ErrorStack object,
- *  ...
- * )
- * 
- * @access private - * @global array $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] - */ -$GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] = array(); - -/** - * Global error callback (default) - * - * This is only used if set to non-false. * is the default callback for - * all packages, whereas specific packages may set a default callback - * for all instances, regardless of whether they are a singleton or not. - * - * To exclude non-singletons, only set the local callback for the singleton - * @see PEAR_ErrorStack::setDefaultCallback() - * @access private - * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] - */ -$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] = array( - '*' => false, -); - -/** - * Global Log object (default) - * - * This is only used if set to non-false. Use to set a default log object for - * all stacks, regardless of instantiation order or location - * @see PEAR_ErrorStack::setDefaultLogger() - * @access private - * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] - */ -$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = false; - -/** - * Global Overriding Callback - * - * This callback will override any error callbacks that specific loggers have set. - * Use with EXTREME caution - * @see PEAR_ErrorStack::staticPushCallback() - * @access private - * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] - */ -$GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array(); - -/**#@+ - * One of four possible return values from the error Callback - * @see PEAR_ErrorStack::_errorCallback() - */ -/** - * If this is returned, then the error will be both pushed onto the stack - * and logged. - */ -define('PEAR_ERRORSTACK_PUSHANDLOG', 1); -/** - * If this is returned, then the error will only be pushed onto the stack, - * and not logged. - */ -define('PEAR_ERRORSTACK_PUSH', 2); -/** - * If this is returned, then the error will only be logged, but not pushed - * onto the error stack. - */ -define('PEAR_ERRORSTACK_LOG', 3); -/** - * If this is returned, then the error is completely ignored. - */ -define('PEAR_ERRORSTACK_IGNORE', 4); -/** - * If this is returned, then the error is logged and die() is called. - */ -define('PEAR_ERRORSTACK_DIE', 5); -/**#@-*/ - -/** - * Error code for an attempt to instantiate a non-class as a PEAR_ErrorStack in - * the singleton method. - */ -define('PEAR_ERRORSTACK_ERR_NONCLASS', 1); - -/** - * Error code for an attempt to pass an object into {@link PEAR_ErrorStack::getMessage()} - * that has no __toString() method - */ -define('PEAR_ERRORSTACK_ERR_OBJTOSTRING', 2); -/** - * Error Stack Implementation - * - * Usage: - * - * // global error stack - * $global_stack = &PEAR_ErrorStack::singleton('MyPackage'); - * // local error stack - * $local_stack = new PEAR_ErrorStack('MyPackage'); - * - * @author Greg Beaver - * @version 1.8.0 - * @package PEAR_ErrorStack - * @category Debugging - * @copyright 2004-2008 Greg Beaver - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: ErrorStack.php,v 1.29 2009/02/24 23:38:22 dufuz Exp $ - * @link http://pear.php.net/package/PEAR_ErrorStack - */ -class PEAR_ErrorStack { - /** - * Errors are stored in the order that they are pushed on the stack. - * @since 0.4alpha Errors are no longer organized by error level. - * This renders pop() nearly unusable, and levels could be more easily - * handled in a callback anyway - * @var array - * @access private - */ - var $_errors = array(); - - /** - * Storage of errors by level. - * - * Allows easy retrieval and deletion of only errors from a particular level - * @since PEAR 1.4.0dev - * @var array - * @access private - */ - var $_errorsByLevel = array(); - - /** - * Package name this error stack represents - * @var string - * @access protected - */ - var $_package; - - /** - * Determines whether a PEAR_Error is thrown upon every error addition - * @var boolean - * @access private - */ - var $_compat = false; - - /** - * If set to a valid callback, this will be used to generate the error - * message from the error code, otherwise the message passed in will be - * used - * @var false|string|array - * @access private - */ - var $_msgCallback = false; - - /** - * If set to a valid callback, this will be used to generate the error - * context for an error. For PHP-related errors, this will be a file - * and line number as retrieved from debug_backtrace(), but can be - * customized for other purposes. The error might actually be in a separate - * configuration file, or in a database query. - * @var false|string|array - * @access protected - */ - var $_contextCallback = false; - - /** - * If set to a valid callback, this will be called every time an error - * is pushed onto the stack. The return value will be used to determine - * whether to allow an error to be pushed or logged. - * - * The return value must be one an PEAR_ERRORSTACK_* constant - * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG - * @var false|string|array - * @access protected - */ - var $_errorCallback = array(); - - /** - * PEAR::Log object for logging errors - * @var false|Log - * @access protected - */ - var $_logger = false; - - /** - * Error messages - designed to be overridden - * @var array - * @abstract - */ - var $_errorMsgs = array(); - - /** - * Set up a new error stack - * - * @param string $package name of the package this error stack represents - * @param callback $msgCallback callback used for error message generation - * @param callback $contextCallback callback used for context generation, - * defaults to {@link getFileLine()} - * @param boolean $throwPEAR_Error - */ - function PEAR_ErrorStack($package, $msgCallback = false, $contextCallback = false, - $throwPEAR_Error = false) - { - $this->_package = $package; - $this->setMessageCallback($msgCallback); - $this->setContextCallback($contextCallback); - $this->_compat = $throwPEAR_Error; - } - - /** - * Return a single error stack for this package. - * - * Note that all parameters are ignored if the stack for package $package - * has already been instantiated - * @param string $package name of the package this error stack represents - * @param callback $msgCallback callback used for error message generation - * @param callback $contextCallback callback used for context generation, - * defaults to {@link getFileLine()} - * @param boolean $throwPEAR_Error - * @param string $stackClass class to instantiate - * @static - * @return PEAR_ErrorStack - */ - function &singleton($package, $msgCallback = false, $contextCallback = false, - $throwPEAR_Error = false, $stackClass = 'PEAR_ErrorStack') - { - if (isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { - return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]; - } - if (!class_exists($stackClass)) { - if (function_exists('debug_backtrace')) { - $trace = debug_backtrace(); - } - PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_NONCLASS, - 'exception', array('stackclass' => $stackClass), - 'stack class "%stackclass%" is not a valid class name (should be like PEAR_ErrorStack)', - false, $trace); - } - $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package] = - new $stackClass($package, $msgCallback, $contextCallback, $throwPEAR_Error); - - return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]; - } - - /** - * Internal error handler for PEAR_ErrorStack class - * - * Dies if the error is an exception (and would have died anyway) - * @access private - */ - function _handleError($err) - { - if ($err['level'] == 'exception') { - $message = $err['message']; - if (isset($_SERVER['REQUEST_URI'])) { - echo '
'; - } else { - echo "\n"; - } - var_dump($err['context']); - die($message); - } - } - - /** - * Set up a PEAR::Log object for all error stacks that don't have one - * @param Log $log - * @static - */ - function setDefaultLogger(&$log) - { - if (is_object($log) && method_exists($log, 'log') ) { - $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log; - } elseif (is_callable($log)) { - $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log; - } - } - - /** - * Set up a PEAR::Log object for this error stack - * @param Log $log - */ - function setLogger(&$log) - { - if (is_object($log) && method_exists($log, 'log') ) { - $this->_logger = &$log; - } elseif (is_callable($log)) { - $this->_logger = &$log; - } - } - - /** - * Set an error code => error message mapping callback - * - * This method sets the callback that can be used to generate error - * messages for any instance - * @param array|string Callback function/method - */ - function setMessageCallback($msgCallback) - { - if (!$msgCallback) { - $this->_msgCallback = array(&$this, 'getErrorMessage'); - } else { - if (is_callable($msgCallback)) { - $this->_msgCallback = $msgCallback; - } - } - } - - /** - * Get an error code => error message mapping callback - * - * This method returns the current callback that can be used to generate error - * messages - * @return array|string|false Callback function/method or false if none - */ - function getMessageCallback() - { - return $this->_msgCallback; - } - - /** - * Sets a default callback to be used by all error stacks - * - * This method sets the callback that can be used to generate error - * messages for a singleton - * @param array|string Callback function/method - * @param string Package name, or false for all packages - * @static - */ - function setDefaultCallback($callback = false, $package = false) - { - if (!is_callable($callback)) { - $callback = false; - } - $package = $package ? $package : '*'; - $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$package] = $callback; - } - - /** - * Set a callback that generates context information (location of error) for an error stack - * - * This method sets the callback that can be used to generate context - * information for an error. Passing in NULL will disable context generation - * and remove the expensive call to debug_backtrace() - * @param array|string|null Callback function/method - */ - function setContextCallback($contextCallback) - { - if ($contextCallback === null) { - return $this->_contextCallback = false; - } - if (!$contextCallback) { - $this->_contextCallback = array(&$this, 'getFileLine'); - } else { - if (is_callable($contextCallback)) { - $this->_contextCallback = $contextCallback; - } - } - } - - /** - * Set an error Callback - * If set to a valid callback, this will be called every time an error - * is pushed onto the stack. The return value will be used to determine - * whether to allow an error to be pushed or logged. - * - * The return value must be one of the ERRORSTACK_* constants. - * - * This functionality can be used to emulate PEAR's pushErrorHandling, and - * the PEAR_ERROR_CALLBACK mode, without affecting the integrity of - * the error stack or logging - * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG - * @see popCallback() - * @param string|array $cb - */ - function pushCallback($cb) - { - array_push($this->_errorCallback, $cb); - } - - /** - * Remove a callback from the error callback stack - * @see pushCallback() - * @return array|string|false - */ - function popCallback() - { - if (!count($this->_errorCallback)) { - return false; - } - return array_pop($this->_errorCallback); - } - - /** - * Set a temporary overriding error callback for every package error stack - * - * Use this to temporarily disable all existing callbacks (can be used - * to emulate the @ operator, for instance) - * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG - * @see staticPopCallback(), pushCallback() - * @param string|array $cb - * @static - */ - function staticPushCallback($cb) - { - array_push($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'], $cb); - } - - /** - * Remove a temporary overriding error callback - * @see staticPushCallback() - * @return array|string|false - * @static - */ - function staticPopCallback() - { - $ret = array_pop($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK']); - if (!is_array($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'])) { - $GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array(); - } - return $ret; - } - - /** - * Add an error to the stack - * - * If the message generator exists, it is called with 2 parameters. - * - the current Error Stack object - * - an array that is in the same format as an error. Available indices - * are 'code', 'package', 'time', 'params', 'level', and 'context' - * - * Next, if the error should contain context information, this is - * handled by the context grabbing method. - * Finally, the error is pushed onto the proper error stack - * @param int $code Package-specific error code - * @param string $level Error level. This is NOT spell-checked - * @param array $params associative array of error parameters - * @param string $msg Error message, or a portion of it if the message - * is to be generated - * @param array $repackage If this error re-packages an error pushed by - * another package, place the array returned from - * {@link pop()} in this parameter - * @param array $backtrace Protected parameter: use this to pass in the - * {@link debug_backtrace()} that should be used - * to find error context - * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also - * thrown. If a PEAR_Error is returned, the userinfo - * property is set to the following array: - * - * - * array( - * 'code' => $code, - * 'params' => $params, - * 'package' => $this->_package, - * 'level' => $level, - * 'time' => time(), - * 'context' => $context, - * 'message' => $msg, - * //['repackage' => $err] repackaged error array/Exception class - * ); - * - * - * Normally, the previous array is returned. - */ - function push($code, $level = 'error', $params = array(), $msg = false, - $repackage = false, $backtrace = false) - { - $context = false; - // grab error context - if ($this->_contextCallback) { - if (!$backtrace) { - $backtrace = debug_backtrace(); - } - $context = call_user_func($this->_contextCallback, $code, $params, $backtrace); - } - - // save error - $time = explode(' ', microtime()); - $time = $time[1] + $time[0]; - $err = array( - 'code' => $code, - 'params' => $params, - 'package' => $this->_package, - 'level' => $level, - 'time' => $time, - 'context' => $context, - 'message' => $msg, - ); - - if ($repackage) { - $err['repackage'] = $repackage; - } - - // set up the error message, if necessary - if ($this->_msgCallback) { - $msg = call_user_func_array($this->_msgCallback, - array(&$this, $err)); - $err['message'] = $msg; - } - $push = $log = true; - $die = false; - // try the overriding callback first - $callback = $this->staticPopCallback(); - if ($callback) { - $this->staticPushCallback($callback); - } - if (!is_callable($callback)) { - // try the local callback next - $callback = $this->popCallback(); - if (is_callable($callback)) { - $this->pushCallback($callback); - } else { - // try the default callback - $callback = isset($GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package]) ? - $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package] : - $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']['*']; - } - } - if (is_callable($callback)) { - switch(call_user_func($callback, $err)){ - case PEAR_ERRORSTACK_IGNORE: - return $err; - break; - case PEAR_ERRORSTACK_PUSH: - $log = false; - break; - case PEAR_ERRORSTACK_LOG: - $push = false; - break; - case PEAR_ERRORSTACK_DIE: - $die = true; - break; - // anything else returned has the same effect as pushandlog - } - } - if ($push) { - array_unshift($this->_errors, $err); - if (!isset($this->_errorsByLevel[$err['level']])) { - $this->_errorsByLevel[$err['level']] = array(); - } - $this->_errorsByLevel[$err['level']][] = &$this->_errors[0]; - } - if ($log) { - if ($this->_logger || $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']) { - $this->_log($err); - } - } - if ($die) { - die(); - } - if ($this->_compat && $push) { - return $this->raiseError($msg, $code, null, null, $err); - } - return $err; - } - - /** - * Static version of {@link push()} - * - * @param string $package Package name this error belongs to - * @param int $code Package-specific error code - * @param string $level Error level. This is NOT spell-checked - * @param array $params associative array of error parameters - * @param string $msg Error message, or a portion of it if the message - * is to be generated - * @param array $repackage If this error re-packages an error pushed by - * another package, place the array returned from - * {@link pop()} in this parameter - * @param array $backtrace Protected parameter: use this to pass in the - * {@link debug_backtrace()} that should be used - * to find error context - * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also - * thrown. see docs for {@link push()} - * @static - */ - function staticPush($package, $code, $level = 'error', $params = array(), - $msg = false, $repackage = false, $backtrace = false) - { - $s = &PEAR_ErrorStack::singleton($package); - if ($s->_contextCallback) { - if (!$backtrace) { - if (function_exists('debug_backtrace')) { - $backtrace = debug_backtrace(); - } - } - } - return $s->push($code, $level, $params, $msg, $repackage, $backtrace); - } - - /** - * Log an error using PEAR::Log - * @param array $err Error array - * @param array $levels Error level => Log constant map - * @access protected - */ - function _log($err) - { - if ($this->_logger) { - $logger = &$this->_logger; - } else { - $logger = &$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']; - } - if (is_a($logger, 'Log')) { - $levels = array( - 'exception' => PEAR_LOG_CRIT, - 'alert' => PEAR_LOG_ALERT, - 'critical' => PEAR_LOG_CRIT, - 'error' => PEAR_LOG_ERR, - 'warning' => PEAR_LOG_WARNING, - 'notice' => PEAR_LOG_NOTICE, - 'info' => PEAR_LOG_INFO, - 'debug' => PEAR_LOG_DEBUG); - if (isset($levels[$err['level']])) { - $level = $levels[$err['level']]; - } else { - $level = PEAR_LOG_INFO; - } - $logger->log($err['message'], $level, $err); - } else { // support non-standard logs - call_user_func($logger, $err); - } - } - - - /** - * Pop an error off of the error stack - * - * @return false|array - * @since 0.4alpha it is no longer possible to specify a specific error - * level to return - the last error pushed will be returned, instead - */ - function pop() - { - $err = @array_shift($this->_errors); - if (!is_null($err)) { - @array_pop($this->_errorsByLevel[$err['level']]); - if (!count($this->_errorsByLevel[$err['level']])) { - unset($this->_errorsByLevel[$err['level']]); - } - } - return $err; - } - - /** - * Pop an error off of the error stack, static method - * - * @param string package name - * @return boolean - * @since PEAR1.5.0a1 - */ - function staticPop($package) - { - if ($package) { - if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { - return false; - } - return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->pop(); - } - } - - /** - * Determine whether there are any errors on the stack - * @param string|array Level name. Use to determine if any errors - * of level (string), or levels (array) have been pushed - * @return boolean - */ - function hasErrors($level = false) - { - if ($level) { - return isset($this->_errorsByLevel[$level]); - } - return count($this->_errors); - } - - /** - * Retrieve all errors since last purge - * - * @param boolean set in order to empty the error stack - * @param string level name, to return only errors of a particular severity - * @return array - */ - function getErrors($purge = false, $level = false) - { - if (!$purge) { - if ($level) { - if (!isset($this->_errorsByLevel[$level])) { - return array(); - } else { - return $this->_errorsByLevel[$level]; - } - } else { - return $this->_errors; - } - } - if ($level) { - $ret = $this->_errorsByLevel[$level]; - foreach ($this->_errorsByLevel[$level] as $i => $unused) { - // entries are references to the $_errors array - $this->_errorsByLevel[$level][$i] = false; - } - // array_filter removes all entries === false - $this->_errors = array_filter($this->_errors); - unset($this->_errorsByLevel[$level]); - return $ret; - } - $ret = $this->_errors; - $this->_errors = array(); - $this->_errorsByLevel = array(); - return $ret; - } - - /** - * Determine whether there are any errors on a single error stack, or on any error stack - * - * The optional parameter can be used to test the existence of any errors without the need of - * singleton instantiation - * @param string|false Package name to check for errors - * @param string Level name to check for a particular severity - * @return boolean - * @static - */ - function staticHasErrors($package = false, $level = false) - { - if ($package) { - if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) { - return false; - } - return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->hasErrors($level); - } - foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) { - if ($obj->hasErrors($level)) { - return true; - } - } - return false; - } - - /** - * Get a list of all errors since last purge, organized by package - * @since PEAR 1.4.0dev BC break! $level is now in the place $merge used to be - * @param boolean $purge Set to purge the error stack of existing errors - * @param string $level Set to a level name in order to retrieve only errors of a particular level - * @param boolean $merge Set to return a flat array, not organized by package - * @param array $sortfunc Function used to sort a merged array - default - * sorts by time, and should be good for most cases - * @static - * @return array - */ - function staticGetErrors($purge = false, $level = false, $merge = false, - $sortfunc = array('PEAR_ErrorStack', '_sortErrors')) - { - $ret = array(); - if (!is_callable($sortfunc)) { - $sortfunc = array('PEAR_ErrorStack', '_sortErrors'); - } - foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) { - $test = $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->getErrors($purge, $level); - if ($test) { - if ($merge) { - $ret = array_merge($ret, $test); - } else { - $ret[$package] = $test; - } - } - } - if ($merge) { - usort($ret, $sortfunc); - } - return $ret; - } - - /** - * Error sorting function, sorts by time - * @access private - */ - function _sortErrors($a, $b) - { - if ($a['time'] == $b['time']) { - return 0; - } - if ($a['time'] < $b['time']) { - return 1; - } - return -1; - } - - /** - * Standard file/line number/function/class context callback - * - * This function uses a backtrace generated from {@link debug_backtrace()} - * and so will not work at all in PHP < 4.3.0. The frame should - * reference the frame that contains the source of the error. - * @return array|false either array('file' => file, 'line' => line, - * 'function' => function name, 'class' => class name) or - * if this doesn't work, then false - * @param unused - * @param integer backtrace frame. - * @param array Results of debug_backtrace() - * @static - */ - function getFileLine($code, $params, $backtrace = null) - { - if ($backtrace === null) { - return false; - } - $frame = 0; - $functionframe = 1; - if (!isset($backtrace[1])) { - $functionframe = 0; - } else { - while (isset($backtrace[$functionframe]['function']) && - $backtrace[$functionframe]['function'] == 'eval' && - isset($backtrace[$functionframe + 1])) { - $functionframe++; - } - } - if (isset($backtrace[$frame])) { - if (!isset($backtrace[$frame]['file'])) { - $frame++; - } - $funcbacktrace = $backtrace[$functionframe]; - $filebacktrace = $backtrace[$frame]; - $ret = array('file' => $filebacktrace['file'], - 'line' => $filebacktrace['line']); - // rearrange for eval'd code or create function errors - if (strpos($filebacktrace['file'], '(') && - preg_match(';^(.*?)\((\d+)\) : (.*?)\\z;', $filebacktrace['file'], - $matches)) { - $ret['file'] = $matches[1]; - $ret['line'] = $matches[2] + 0; - } - if (isset($funcbacktrace['function']) && isset($backtrace[1])) { - if ($funcbacktrace['function'] != 'eval') { - if ($funcbacktrace['function'] == '__lambda_func') { - $ret['function'] = 'create_function() code'; - } else { - $ret['function'] = $funcbacktrace['function']; - } - } - } - if (isset($funcbacktrace['class']) && isset($backtrace[1])) { - $ret['class'] = $funcbacktrace['class']; - } - return $ret; - } - return false; - } - - /** - * Standard error message generation callback - * - * This method may also be called by a custom error message generator - * to fill in template values from the params array, simply - * set the third parameter to the error message template string to use - * - * The special variable %__msg% is reserved: use it only to specify - * where a message passed in by the user should be placed in the template, - * like so: - * - * Error message: %msg% - internal error - * - * If the message passed like so: - * - * - * $stack->push(ERROR_CODE, 'error', array(), 'server error 500'); - * - * - * The returned error message will be "Error message: server error 500 - - * internal error" - * @param PEAR_ErrorStack - * @param array - * @param string|false Pre-generated error message template - * @static - * @return string - */ - function getErrorMessage(&$stack, $err, $template = false) - { - if ($template) { - $mainmsg = $template; - } else { - $mainmsg = $stack->getErrorMessageTemplate($err['code']); - } - $mainmsg = str_replace('%__msg%', $err['message'], $mainmsg); - if (is_array($err['params']) && count($err['params'])) { - foreach ($err['params'] as $name => $val) { - if (is_array($val)) { - // @ is needed in case $val is a multi-dimensional array - $val = @implode(', ', $val); - } - if (is_object($val)) { - if (method_exists($val, '__toString')) { - $val = $val->__toString(); - } else { - PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_OBJTOSTRING, - 'warning', array('obj' => get_class($val)), - 'object %obj% passed into getErrorMessage, but has no __toString() method'); - $val = 'Object'; - } - } - $mainmsg = str_replace('%' . $name . '%', $val, $mainmsg); - } - } - return $mainmsg; - } - - /** - * Standard Error Message Template generator from code - * @return string - */ - function getErrorMessageTemplate($code) - { - if (!isset($this->_errorMsgs[$code])) { - return '%__msg%'; - } - return $this->_errorMsgs[$code]; - } - - /** - * Set the Error Message Template array - * - * The array format must be: - *
-     * array(error code => 'message template',...)
-     * 
- * - * Error message parameters passed into {@link push()} will be used as input - * for the error message. If the template is 'message %foo% was %bar%', and the - * parameters are array('foo' => 'one', 'bar' => 'six'), the error message returned will - * be 'message one was six' - * @return string - */ - function setErrorMessageTemplate($template) - { - $this->_errorMsgs = $template; - } - - - /** - * emulate PEAR::raiseError() - * - * @return PEAR_Error - */ - function raiseError() - { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR.php'; - $args = func_get_args(); - return call_user_func_array(array('PEAR', 'raiseError'), $args); - } -} -$stack = &PEAR_ErrorStack::singleton('PEAR_ErrorStack'); -$stack->pushCallback(array('PEAR_ErrorStack', '_handleError')); -?> - - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Frontend.php,v 1.18 2009/02/24 23:38:22 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * Include error handling - */ -//require_once 'PEAR.php'; - -/** - * Which user interface class is being used. - * @var string class name - */ -$GLOBALS['_PEAR_FRONTEND_CLASS'] = 'PEAR_Frontend_CLI'; - -/** - * Instance of $_PEAR_Command_uiclass. - * @var object - */ -$GLOBALS['_PEAR_FRONTEND_SINGLETON'] = null; - -/** - * Singleton-based frontend for PEAR user input/output - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Frontend extends PEAR -{ - /** - * Retrieve the frontend object - * @return PEAR_Frontend_CLI|PEAR_Frontend_Web|PEAR_Frontend_Gtk - * @static - */ - function &singleton($type = null) - { - if ($type === null) { - if (!isset($GLOBALS['_PEAR_FRONTEND_SINGLETON'])) { - $a = false; - return $a; - } - return $GLOBALS['_PEAR_FRONTEND_SINGLETON']; - } - - $a = PEAR_Frontend::setFrontendClass($type); - return $a; - } - - /** - * Set the frontend class that will be used by calls to {@link singleton()} - * - * Frontends are expected to conform to the PEAR naming standard of - * _ => DIRECTORY_SEPARATOR (PEAR_Frontend_CLI is in PEAR/Frontend/CLI.php) - * @param string $uiclass full class name - * @return PEAR_Frontend - * @static - */ - function &setFrontendClass($uiclass) - { - if (is_object($GLOBALS['_PEAR_FRONTEND_SINGLETON']) && - is_a($GLOBALS['_PEAR_FRONTEND_SINGLETON'], $uiclass)) { - return $GLOBALS['_PEAR_FRONTEND_SINGLETON']; - } - - if (!class_exists($uiclass)) { - $file = 'phar://install-pear-nozlib.phar/' . str_replace('_', '/', $uiclass) . '.php'; - if (PEAR_Frontend::isIncludeable($file)) { - include_once $file; - } - } - - if (class_exists($uiclass)) { - $obj = &new $uiclass; - // quick test to see if this class implements a few of the most - // important frontend methods - if (is_a($obj, 'PEAR_Frontend')) { - $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = &$obj; - $GLOBALS['_PEAR_FRONTEND_CLASS'] = $uiclass; - return $obj; - } - - $err = PEAR::raiseError("not a frontend class: $uiclass"); - return $err; - } - - $err = PEAR::raiseError("no such class: $uiclass"); - return $err; - } - - /** - * Set the frontend class that will be used by calls to {@link singleton()} - * - * Frontends are expected to be a descendant of PEAR_Frontend - * @param PEAR_Frontend - * @return PEAR_Frontend - * @static - */ - function &setFrontendObject($uiobject) - { - if (is_object($GLOBALS['_PEAR_FRONTEND_SINGLETON']) && - is_a($GLOBALS['_PEAR_FRONTEND_SINGLETON'], get_class($uiobject))) { - return $GLOBALS['_PEAR_FRONTEND_SINGLETON']; - } - - if (!is_a($uiobject, 'PEAR_Frontend')) { - $err = PEAR::raiseError('not a valid frontend class: (' . - get_class($uiobject) . ')'); - return $err; - } - - $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = &$uiobject; - $GLOBALS['_PEAR_FRONTEND_CLASS'] = get_class($uiobject); - return $uiobject; - } - - /** - * @param string $path relative or absolute include path - * @return boolean - * @static - */ - function isIncludeable($path) - { - if (file_exists($path) && is_readable($path)) { - return true; - } - - $fp = @fopen($path, 'r', true); - if ($fp) { - fclose($fp); - return true; - } - - return false; - } - - /** - * @param PEAR_Config - */ - function setConfig(&$config) - { - } - - /** - * This can be overridden to allow session-based temporary file management - * - * By default, all files are deleted at the end of a session. The web installer - * needs to be able to sustain a list over many sessions in order to support - * user interaction with install scripts - */ - function addTempFile($file) - { - $GLOBALS['_PEAR_Common_tempfiles'][] = $file; - } - - /** - * Log an action - * - * @param string $msg the message to log - * @param boolean $append_crlf - * @return boolean true - * @abstract - */ - function log($msg, $append_crlf = true) - { - } - - /** - * Run a post-installation script - * - * @param array $scripts array of post-install scripts - * @abstract - */ - function runPostinstallScripts(&$scripts) - { - } - - /** - * Display human-friendly output formatted depending on the - * $command parameter. - * - * This should be able to handle basic output data with no command - * @param mixed $data data structure containing the information to display - * @param string $command command from which this method was called - * @abstract - */ - function outputData($data, $command = '_default') - { - } - - /** - * Display a modal form dialog and return the given input - * - * A frontend that requires multiple requests to retrieve and process - * data must take these needs into account, and implement the request - * handling code. - * @param string $command command from which this method was called - * @param array $prompts associative array. keys are the input field names - * and values are the description - * @param array $types array of input field types (text, password, - * etc.) keys have to be the same like in $prompts - * @param array $defaults array of default values. again keys have - * to be the same like in $prompts. Do not depend - * on a default value being set. - * @return array input sent by the user - * @abstract - */ - function userDialog($command, $prompts, $types = array(), $defaults = array()) - { - } } * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: CLI.php,v 1.76 2009/04/04 00:09:14 dufuz Exp $ + * @version CVS: $Id: v1.php 286494 2009-07-29 06:57:11Z dufuz $ * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 + * @since File available since Release 1.4.0a1 */ /** - * base class + * needed for PEAR_VALIDATE_* constants */ -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Frontend.php'; - +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Validate.php'; +require_once 'phar://install-pear-nozlib.phar/' . 'System.php'; +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/v2.php'; /** - * Command-line Frontend for the PEAR Installer + * This class converts a PEAR_PackageFile_v1 object into any output format. + * + * Supported output formats include array, XML string, and a PEAR_PackageFile_v2 + * object, for converting package.xml 1.0 into package.xml 2.0 with no sweat. * @category pear * @package PEAR - * @author Stig Bakken * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 + * @since Class available since Release 1.4.0a1 */ -class PEAR_Frontend_CLI extends PEAR_Frontend +class PEAR_PackageFile_Generator_v1 { /** - * What type of user interface this frontend is for. - * @var string - * @access public + * @var PEAR_PackageFile_v1 */ - var $type = 'CLI'; - var $lp = ''; // line prefix + var $_packagefile; + function PEAR_PackageFile_Generator_v1(&$packagefile) + { + $this->_packagefile = &$packagefile; + } - var $params = array(); - var $term = array( - 'bold' => '', - 'normal' => '', - ); + function getPackagerVersion() + { + return '1.9.0'; + } - function PEAR_Frontend_CLI() + /** + * @param PEAR_Packager + * @param bool if true, a .tgz is written, otherwise a .tar is written + * @param string|null directory in which to save the .tgz + * @return string|PEAR_Error location of package or error object + */ + function toTgz(&$packager, $compress = true, $where = null) { - parent::PEAR(); - $term = getenv('TERM'); //(cox) $_ENV is empty for me in 4.1.1 - if (function_exists('posix_isatty') && !posix_isatty(1)) { - // output is being redirected to a file or through a pipe - } elseif ($term) { - if (preg_match('/^(xterm|vt220|linux)/', $term)) { - $this->term['bold'] = sprintf("%c%c%c%c", 27, 91, 49, 109); - $this->term['normal'] = sprintf("%c%c%c", 27, 91, 109); - } elseif (preg_match('/^vt100/', $term)) { - $this->term['bold'] = sprintf("%c%c%c%c%c%c", 27, 91, 49, 109, 0, 0); - $this->term['normal'] = sprintf("%c%c%c%c%c", 27, 91, 109, 0, 0); + require_once 'phar://install-pear-nozlib.phar/' . 'Archive/Tar.php'; + if ($where === null) { + if (!($where = System::mktemp(array('-d')))) { + return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: mktemp failed'); + } + } elseif (!@System::mkDir(array('-p', $where))) { + return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: "' . $where . '" could' . + ' not be created'); + } + if (file_exists($where . DIRECTORY_SEPARATOR . 'package.xml') && + !is_file($where . DIRECTORY_SEPARATOR . 'package.xml')) { + return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: unable to save package.xml as' . + ' "' . $where . DIRECTORY_SEPARATOR . 'package.xml"'); + } + if (!$this->_packagefile->validate(PEAR_VALIDATE_PACKAGING)) { + return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: invalid package file'); + } + $pkginfo = $this->_packagefile->getArray(); + $ext = $compress ? '.tgz' : '.tar'; + $pkgver = $pkginfo['package'] . '-' . $pkginfo['version']; + $dest_package = getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext; + if (file_exists(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext) && + !is_file(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext)) { + return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: cannot create tgz file "' . + getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext . '"'); + } + if ($pkgfile = $this->_packagefile->getPackageFile()) { + $pkgdir = dirname(realpath($pkgfile)); + $pkgfile = basename($pkgfile); + } else { + return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: package file object must ' . + 'be created from a real file'); + } + // {{{ Create the package file list + $filelist = array(); + $i = 0; + + foreach ($this->_packagefile->getFilelist() as $fname => $atts) { + $file = $pkgdir . DIRECTORY_SEPARATOR . $fname; + if (!file_exists($file)) { + return PEAR::raiseError("File does not exist: $fname"); + } else { + $filelist[$i++] = $file; + if (!isset($atts['md5sum'])) { + $this->_packagefile->setFileAttribute($fname, 'md5sum', md5_file($file)); + } + $packager->log(2, "Adding file $fname"); + } + } + // }}} + $packagexml = $this->toPackageFile($where, PEAR_VALIDATE_PACKAGING, 'package.xml', true); + if ($packagexml) { + $tar =& new Archive_Tar($dest_package, $compress); + $tar->setErrorHandling(PEAR_ERROR_RETURN); // XXX Don't print errors + // ----- Creates with the package.xml file + $ok = $tar->createModify(array($packagexml), '', $where); + if (PEAR::isError($ok)) { + return $ok; + } elseif (!$ok) { + return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: tarball creation failed'); + } + // ----- Add the content of the package + if (!$tar->addModify($filelist, $pkgver, $pkgdir)) { + return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: tarball creation failed'); + } + return $dest_package; + } + } + + /** + * @param string|null directory to place the package.xml in, or null for a temporary dir + * @param int one of the PEAR_VALIDATE_* constants + * @param string name of the generated file + * @param bool if true, then no analysis will be performed on role="php" files + * @return string|PEAR_Error path to the created file on success + */ + function toPackageFile($where = null, $state = PEAR_VALIDATE_NORMAL, $name = 'package.xml', + $nofilechecking = false) + { + if (!$this->_packagefile->validate($state, $nofilechecking)) { + return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: invalid package.xml', + null, null, null, $this->_packagefile->getValidationWarnings()); + } + if ($where === null) { + if (!($where = System::mktemp(array('-d')))) { + return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: mktemp failed'); + } + } elseif (!@System::mkDir(array('-p', $where))) { + return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: "' . $where . '" could' . + ' not be created'); + } + $newpkgfile = $where . DIRECTORY_SEPARATOR . $name; + $np = @fopen($newpkgfile, 'wb'); + if (!$np) { + return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: unable to save ' . + "$name as $newpkgfile"); + } + fwrite($np, $this->toXml($state, true)); + fclose($np); + return $newpkgfile; + } + + /** + * fix both XML encoding to be UTF8, and replace standard XML entities < > " & ' + * + * @param string $string + * @return string + * @access private + */ + function _fixXmlEncoding($string) + { + if (version_compare(phpversion(), '5.0.0', 'lt')) { + $string = utf8_encode($string); + } + return strtr($string, array( + '&' => '&', + '>' => '>', + '<' => '<', + '"' => '"', + '\'' => ''' )); + } + + /** + * Return an XML document based on the package info (as returned + * by the PEAR_Common::infoFrom* methods). + * + * @return string XML data + */ + function toXml($state = PEAR_VALIDATE_NORMAL, $nofilevalidation = false) + { + $this->_packagefile->setDate(date('Y-m-d')); + if (!$this->_packagefile->validate($state, $nofilevalidation)) { + return false; + } + $pkginfo = $this->_packagefile->getArray(); + static $maint_map = array( + "handle" => "user", + "name" => "name", + "email" => "email", + "role" => "role", + ); + $ret = "\n"; + $ret .= "\n"; + $ret .= "\n" . +" $pkginfo[package]"; + if (isset($pkginfo['extends'])) { + $ret .= "\n$pkginfo[extends]"; + } + $ret .= + "\n ".$this->_fixXmlEncoding($pkginfo['summary'])."\n" . +" ".trim($this->_fixXmlEncoding($pkginfo['description']))."\n \n" . +" \n"; + foreach ($pkginfo['maintainers'] as $maint) { + $ret .= " \n"; + foreach ($maint_map as $idx => $elm) { + $ret .= " <$elm>"; + $ret .= $this->_fixXmlEncoding($maint[$idx]); + $ret .= "\n"; + } + $ret .= " \n"; + } + $ret .= " \n"; + $ret .= $this->_makeReleaseXml($pkginfo, false, $state); + if (isset($pkginfo['changelog']) && count($pkginfo['changelog']) > 0) { + $ret .= " \n"; + foreach ($pkginfo['changelog'] as $oldrelease) { + $ret .= $this->_makeReleaseXml($oldrelease, true); + } + $ret .= " \n"; + } + $ret .= "\n"; + return $ret; + } + + // }}} + // {{{ _makeReleaseXml() + + /** + * Generate part of an XML description with release information. + * + * @param array $pkginfo array with release information + * @param bool $changelog whether the result will be in a changelog element + * + * @return string XML data + * + * @access private + */ + function _makeReleaseXml($pkginfo, $changelog = false, $state = PEAR_VALIDATE_NORMAL) + { + // XXX QUOTE ENTITIES IN PCDATA, OR EMBED IN CDATA BLOCKS!! + $indent = $changelog ? " " : ""; + $ret = "$indent \n"; + if (!empty($pkginfo['version'])) { + $ret .= "$indent $pkginfo[version]\n"; + } + if (!empty($pkginfo['release_date'])) { + $ret .= "$indent $pkginfo[release_date]\n"; + } + if (!empty($pkginfo['release_license'])) { + $ret .= "$indent $pkginfo[release_license]\n"; + } + if (!empty($pkginfo['release_state'])) { + $ret .= "$indent $pkginfo[release_state]\n"; + } + if (!empty($pkginfo['release_notes'])) { + $ret .= "$indent ".trim($this->_fixXmlEncoding($pkginfo['release_notes'])) + ."\n$indent \n"; + } + if (!empty($pkginfo['release_warnings'])) { + $ret .= "$indent ".$this->_fixXmlEncoding($pkginfo['release_warnings'])."\n"; + } + if (isset($pkginfo['release_deps']) && sizeof($pkginfo['release_deps']) > 0) { + $ret .= "$indent \n"; + foreach ($pkginfo['release_deps'] as $dep) { + $ret .= "$indent _fixXmlEncoding($c['name']) . "\""; + if (isset($c['default'])) { + $ret .= " default=\"" . $this->_fixXmlEncoding($c['default']) . "\""; + } + $ret .= " prompt=\"" . $this->_fixXmlEncoding($c['prompt']) . "\""; + $ret .= "/>\n"; + } + $ret .= "$indent \n"; + } + if (isset($pkginfo['provides'])) { + foreach ($pkginfo['provides'] as $key => $what) { + $ret .= "$indent recursiveXmlFilelist($pkginfo['filelist']); + } else { + foreach ($pkginfo['filelist'] as $file => $fa) { + if (!isset($fa['role'])) { + $fa['role'] = ''; + } + $ret .= "$indent _fixXmlEncoding($fa['baseinstalldir']) . '"'; + } + if (isset($fa['md5sum'])) { + $ret .= " md5sum=\"$fa[md5sum]\""; + } + if (isset($fa['platform'])) { + $ret .= " platform=\"$fa[platform]\""; + } + if (!empty($fa['install-as'])) { + $ret .= ' install-as="' . + $this->_fixXmlEncoding($fa['install-as']) . '"'; + } + $ret .= ' name="' . $this->_fixXmlEncoding($file) . '"'; + if (empty($fa['replacements'])) { + $ret .= "/>\n"; + } else { + $ret .= ">\n"; + foreach ($fa['replacements'] as $r) { + $ret .= "$indent $v) { + $ret .= " $k=\"" . $this->_fixXmlEncoding($v) .'"'; + } + $ret .= "/>\n"; + } + $ret .= "$indent \n"; + } + } } - } elseif (OS_WINDOWS) { - // XXX add ANSI codes here + $ret .= "$indent \n"; } + $ret .= "$indent \n"; + return $ret; } /** - * @param object PEAR_Error object + * @param array + * @access protected */ - function displayError($e) + function recursiveXmlFilelist($list) { - return $this->_displayLine($e->getMessage()); + $this->_dirs = array(); + foreach ($list as $file => $attributes) { + $this->_addDir($this->_dirs, explode('/', dirname($file)), $file, $attributes); + } + return $this->_formatDir($this->_dirs); } /** - * @param object PEAR_Error object + * @param array + * @param array + * @param string|null + * @param array|null + * @access private */ - function displayFatalError($eobj) + function _addDir(&$dirs, $dir, $file = null, $attributes = null) { - $this->displayError($eobj); - if (class_exists('PEAR_Config')) { - $config = &PEAR_Config::singleton(); - if ($config->get('verbose') > 5) { - if (function_exists('debug_print_backtrace')) { - debug_print_backtrace(); - exit(1); - } + if ($dir == array() || $dir == array('.')) { + $dirs['files'][basename($file)] = $attributes; + return; + } + $curdir = array_shift($dir); + if (!isset($dirs['dirs'][$curdir])) { + $dirs['dirs'][$curdir] = array(); + } + $this->_addDir($dirs['dirs'][$curdir], $dir, $file, $attributes); + } - $raised = false; - foreach (debug_backtrace() as $i => $frame) { - if (!$raised) { - if (isset($frame['class']) - && strtolower($frame['class']) == 'pear' - && strtolower($frame['function']) == 'raiseerror' - ) { - $raised = true; - } else { - continue; - } - } + /** + * @param array + * @param string + * @param string + * @access private + */ + function _formatDir($dirs, $indent = '', $curdir = '') + { + $ret = ''; + if (!count($dirs)) { + return ''; + } + if (isset($dirs['dirs'])) { + uksort($dirs['dirs'], 'strnatcasecmp'); + foreach ($dirs['dirs'] as $dir => $contents) { + $usedir = "$curdir/$dir"; + $ret .= "$indent \n"; + $ret .= $this->_formatDir($contents, "$indent ", $usedir); + $ret .= "$indent \n"; + } + } + if (isset($dirs['files'])) { + uksort($dirs['files'], 'strnatcasecmp'); + foreach ($dirs['files'] as $file => $attribs) { + $ret .= $this->_formatFile($file, $attribs, $indent); + } + } + return $ret; + } - $frame['class'] = !isset($frame['class']) ? '' : $frame['class']; - $frame['type'] = !isset($frame['type']) ? '' : $frame['type']; - $frame['function'] = !isset($frame['function']) ? '' : $frame['function']; - $frame['line'] = !isset($frame['line']) ? '' : $frame['line']; - $this->_displayLine("#$i: $frame[class]$frame[type]$frame[function] $frame[line]"); + /** + * @param string + * @param array + * @param string + * @access private + */ + function _formatFile($file, $attributes, $indent) + { + $ret = "$indent _fixXmlEncoding($attributes['baseinstalldir']) . '"'; + } + if (isset($attributes['md5sum'])) { + $ret .= " md5sum=\"$attributes[md5sum]\""; + } + if (isset($attributes['platform'])) { + $ret .= " platform=\"$attributes[platform]\""; + } + if (!empty($attributes['install-as'])) { + $ret .= ' install-as="' . + $this->_fixXmlEncoding($attributes['install-as']) . '"'; + } + $ret .= ' name="' . $this->_fixXmlEncoding($file) . '"'; + if (empty($attributes['replacements'])) { + $ret .= "/>\n"; + } else { + $ret .= ">\n"; + foreach ($attributes['replacements'] as $r) { + $ret .= "$indent $v) { + $ret .= " $k=\"" . $this->_fixXmlEncoding($v) .'"'; } + $ret .= "/>\n"; } + $ret .= "$indent \n"; } - - exit(1); + return $ret; } + // {{{ _unIndent() + /** - * Instruct the runInstallScript method to skip a paramgroup that matches the - * id value passed in. + * Unindent given string (?) * - * This method is useful for dynamically configuring which sections of a post-install script - * will be run based on the user's setup, which is very useful for making flexible - * post-install scripts without losing the cross-Frontend ability to retrieve user input - * @param string + * @param string $str The string that has to be unindented. + * @return string + * @access private */ - function skipParamgroup($id) + function _unIndent($str) { - $this->_skipSections[$id] = true; + // remove leading newlines + $str = preg_replace('/^[\r\n]+/', '', $str); + // find whitespace at the beginning of the first line + $indent_len = strspn($str, " \t"); + $indent = substr($str, 0, $indent_len); + $data = ''; + // remove the same amount of whitespace from following lines + foreach (explode("\n", $str) as $line) { + if (substr($line, 0, $indent_len) == $indent) { + $data .= substr($line, $indent_len) . "\n"; + } + } + return $data; } - function runPostinstallScripts(&$scripts) + /** + * @return array + */ + function dependenciesToV2() { - foreach ($scripts as $i => $script) { - $this->runInstallScript($scripts[$i]->_params, $scripts[$i]->_obj); - } + $arr = array(); + $this->_convertDependencies2_0($arr); + return $arr['dependencies']; } /** - * @param array $xml contents of postinstallscript tag - * @param object $script post-installation script - * @param string install|upgrade + * Convert a package.xml version 1.0 into version 2.0 + * + * Note that this does a basic conversion, to allow more advanced + * features like bundles and multiple releases + * @param string the classname to instantiate and return. This must be + * PEAR_PackageFile_v2 or a descendant + * @param boolean if true, only valid, deterministic package.xml 1.0 as defined by the + * strictest parameters will be converted + * @return PEAR_PackageFile_v2|PEAR_Error */ - function runInstallScript($xml, &$script) + function &toV2($class = 'PEAR_PackageFile_v2', $strict = false) { - $this->_skipSections = array(); - if (!is_array($xml) || !isset($xml['paramgroup'])) { - $script->run(array(), '_default'); - return; + if ($strict) { + if (!$this->_packagefile->validate()) { + $a = PEAR::raiseError('invalid package.xml version 1.0 cannot be converted' . + ' to version 2.0', null, null, null, + $this->_packagefile->getValidationWarnings(true)); + return $a; + } } - $completedPhases = array(); - if (!isset($xml['paramgroup'][0])) { - $xml['paramgroup'] = array($xml['paramgroup']); + $arr = array( + 'attribs' => array( + 'version' => '2.0', + 'xmlns' => 'http://pear.php.net/dtd/package-2.0', + 'xmlns:tasks' => 'http://pear.php.net/dtd/tasks-1.0', + 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', + 'xsi:schemaLocation' => "http://pear.php.net/dtd/tasks-1.0\n" . +"http://pear.php.net/dtd/tasks-1.0.xsd\n" . +"http://pear.php.net/dtd/package-2.0\n" . +'http://pear.php.net/dtd/package-2.0.xsd', + ), + 'name' => $this->_packagefile->getPackage(), + 'channel' => 'pear.php.net', + ); + $arr['summary'] = $this->_packagefile->getSummary(); + $arr['description'] = $this->_packagefile->getDescription(); + $maintainers = $this->_packagefile->getMaintainers(); + foreach ($maintainers as $maintainer) { + if ($maintainer['role'] != 'lead') { + continue; + } + $new = array( + 'name' => $maintainer['name'], + 'user' => $maintainer['handle'], + 'email' => $maintainer['email'], + 'active' => 'yes', + ); + $arr['lead'][] = $new; } - foreach ($xml['paramgroup'] as $group) { - if (isset($this->_skipSections[$group['id']])) { - // the post-install script chose to skip this section dynamically + if (!isset($arr['lead'])) { // some people... you know? + $arr['lead'] = array( + 'name' => 'unknown', + 'user' => 'unknown', + 'email' => 'noleadmaintainer@example.com', + 'active' => 'no', + ); + } + + if (count($arr['lead']) == 1) { + $arr['lead'] = $arr['lead'][0]; + } + + foreach ($maintainers as $maintainer) { + if ($maintainer['role'] == 'lead') { continue; } + $new = array( + 'name' => $maintainer['name'], + 'user' => $maintainer['handle'], + 'email' => $maintainer['email'], + 'active' => 'yes', + ); + $arr[$maintainer['role']][] = $new; + } - if (isset($group['name'])) { - $paramname = explode('::', $group['name']); - if ($lastgroup['id'] != $paramname[0]) { - continue; + if (isset($arr['developer']) && count($arr['developer']) == 1) { + $arr['developer'] = $arr['developer'][0]; + } + + if (isset($arr['contributor']) && count($arr['contributor']) == 1) { + $arr['contributor'] = $arr['contributor'][0]; + } + + if (isset($arr['helper']) && count($arr['helper']) == 1) { + $arr['helper'] = $arr['helper'][0]; + } + + $arr['date'] = $this->_packagefile->getDate(); + $arr['version'] = + array( + 'release' => $this->_packagefile->getVersion(), + 'api' => $this->_packagefile->getVersion(), + ); + $arr['stability'] = + array( + 'release' => $this->_packagefile->getState(), + 'api' => $this->_packagefile->getState(), + ); + $licensemap = + array( + 'php' => 'http://www.php.net/license', + 'php license' => 'http://www.php.net/license', + 'lgpl' => 'http://www.gnu.org/copyleft/lesser.html', + 'bsd' => 'http://www.opensource.org/licenses/bsd-license.php', + 'bsd style' => 'http://www.opensource.org/licenses/bsd-license.php', + 'bsd-style' => 'http://www.opensource.org/licenses/bsd-license.php', + 'mit' => 'http://www.opensource.org/licenses/mit-license.php', + 'gpl' => 'http://www.gnu.org/copyleft/gpl.html', + 'apache' => 'http://www.opensource.org/licenses/apache2.0.php' + ); + + if (isset($licensemap[strtolower($this->_packagefile->getLicense())])) { + $arr['license'] = array( + 'attribs' => array('uri' => + $licensemap[strtolower($this->_packagefile->getLicense())]), + '_content' => $this->_packagefile->getLicense() + ); + } else { + // don't use bogus uri + $arr['license'] = $this->_packagefile->getLicense(); + } + + $arr['notes'] = $this->_packagefile->getNotes(); + $temp = array(); + $arr['contents'] = $this->_convertFilelist2_0($temp); + $this->_convertDependencies2_0($arr); + $release = ($this->_packagefile->getConfigureOptions() || $this->_isExtension) ? + 'extsrcrelease' : 'phprelease'; + if ($release == 'extsrcrelease') { + $arr['channel'] = 'pecl.php.net'; + $arr['providesextension'] = $arr['name']; // assumption + } + + $arr[$release] = array(); + if ($this->_packagefile->getConfigureOptions()) { + $arr[$release]['configureoption'] = $this->_packagefile->getConfigureOptions(); + foreach ($arr[$release]['configureoption'] as $i => $opt) { + $arr[$release]['configureoption'][$i] = array('attribs' => $opt); + } + if (count($arr[$release]['configureoption']) == 1) { + $arr[$release]['configureoption'] = $arr[$release]['configureoption'][0]; + } + } + + $this->_convertRelease2_0($arr[$release], $temp); + if ($release == 'extsrcrelease' && count($arr[$release]) > 1) { + // multiple extsrcrelease tags added in PEAR 1.4.1 + $arr['dependencies']['required']['pearinstaller']['min'] = '1.4.1'; + } + + if ($cl = $this->_packagefile->getChangelog()) { + foreach ($cl as $release) { + $rel = array(); + $rel['version'] = + array( + 'release' => $release['version'], + 'api' => $release['version'], + ); + if (!isset($release['release_state'])) { + $release['release_state'] = 'stable'; } - $group['name'] = $paramname[1]; - if (!isset($answers)) { - return; + $rel['stability'] = + array( + 'release' => $release['release_state'], + 'api' => $release['release_state'], + ); + if (isset($release['release_date'])) { + $rel['date'] = $release['release_date']; + } else { + $rel['date'] = date('Y-m-d'); } - if (isset($answers[$group['name']])) { - switch ($group['conditiontype']) { - case '=' : - if ($answers[$group['name']] != $group['value']) { - continue 2; - } - break; - case '!=' : - if ($answers[$group['name']] == $group['value']) { - continue 2; - } - break; - case 'preg_match' : - if (!@preg_match('/' . $group['value'] . '/', - $answers[$group['name']])) { - continue 2; - } - break; - default : - return; + if (isset($release['release_license'])) { + if (isset($licensemap[strtolower($release['release_license'])])) { + $uri = $licensemap[strtolower($release['release_license'])]; + } else { + $uri = 'http://www.example.com'; } + $rel['license'] = array( + 'attribs' => array('uri' => $uri), + '_content' => $release['release_license'] + ); + } else { + $rel['license'] = $arr['license']; } - } - $lastgroup = $group; - if (isset($group['instructions'])) { - $this->_display($group['instructions']); - } + if (!isset($release['release_notes'])) { + $release['release_notes'] = 'no release notes'; + } - if (!isset($group['param'][0])) { - $group['param'] = array($group['param']); + $rel['notes'] = $release['release_notes']; + $arr['changelog']['release'][] = $rel; } + } - if (isset($group['param'])) { - if (method_exists($script, 'postProcessPrompts')) { - $prompts = $script->postProcessPrompts($group['param'], $group['id']); - if (!is_array($prompts) || count($prompts) != count($group['param'])) { - $this->outputData('postinstall', 'Error: post-install script did not ' . - 'return proper post-processed prompts'); - $prompts = $group['param']; - } else { - foreach ($prompts as $i => $var) { - if (!is_array($var) || !isset($var['prompt']) || - !isset($var['name']) || - ($var['name'] != $group['param'][$i]['name']) || - ($var['type'] != $group['param'][$i]['type']) - ) { - $this->outputData('postinstall', 'Error: post-install script ' . - 'modified the variables or prompts, severe security risk. ' . - 'Will instead use the defaults from the package.xml'); - $prompts = $group['param']; - } - } - } + $ret = new $class; + $ret->setConfig($this->_packagefile->_config); + if (isset($this->_packagefile->_logger) && is_object($this->_packagefile->_logger)) { + $ret->setLogger($this->_packagefile->_logger); + } - $answers = $this->confirmDialog($prompts); + $ret->fromArray($arr); + return $ret; + } + + /** + * @param array + * @param bool + * @access private + */ + function _convertDependencies2_0(&$release, $internal = false) + { + $peardep = array('pearinstaller' => + array('min' => '1.4.0b1')); // this is a lot safer + $required = $optional = array(); + $release['dependencies'] = array('required' => array()); + if ($this->_packagefile->hasDeps()) { + foreach ($this->_packagefile->getDeps() as $dep) { + if (!isset($dep['optional']) || $dep['optional'] == 'no') { + $required[] = $dep; } else { - $answers = $this->confirmDialog($group['param']); + $optional[] = $dep; } } - - if ((isset($answers) && $answers) || !isset($group['param'])) { - if (!isset($answers)) { - $answers = array(); - } - - array_unshift($completedPhases, $group['id']); - if (!$script->run($answers, $group['id'])) { - $script->run($completedPhases, '_undoOnError'); - return; + foreach (array('required', 'optional') as $arr) { + $deps = array(); + foreach ($$arr as $dep) { + // organize deps by dependency type and name + if (!isset($deps[$dep['type']])) { + $deps[$dep['type']] = array(); + } + if (isset($dep['name'])) { + $deps[$dep['type']][$dep['name']][] = $dep; + } else { + $deps[$dep['type']][] = $dep; + } } - } else { - $script->run($completedPhases, '_undoOnError'); - return; + do { + if (isset($deps['php'])) { + $php = array(); + if (count($deps['php']) > 1) { + $php = $this->_processPhpDeps($deps['php']); + } else { + if (!isset($deps['php'][0])) { + list($key, $blah) = each ($deps['php']); // stupid buggy versions + $deps['php'] = array($blah[0]); + } + $php = $this->_processDep($deps['php'][0]); + if (!$php) { + break; // poor mans throw + } + } + $release['dependencies'][$arr]['php'] = $php; + } + } while (false); + do { + if (isset($deps['pkg'])) { + $pkg = array(); + $pkg = $this->_processMultipleDepsName($deps['pkg']); + if (!$pkg) { + break; // poor mans throw + } + $release['dependencies'][$arr]['package'] = $pkg; + } + } while (false); + do { + if (isset($deps['ext'])) { + $pkg = array(); + $pkg = $this->_processMultipleDepsName($deps['ext']); + $release['dependencies'][$arr]['extension'] = $pkg; + } + } while (false); + // skip sapi - it's not supported so nobody will have used it + // skip os - it's not supported in 1.0 } } + if (isset($release['dependencies']['required'])) { + $release['dependencies']['required'] = + array_merge($peardep, $release['dependencies']['required']); + } else { + $release['dependencies']['required'] = $peardep; + } + if (!isset($release['dependencies']['required']['php'])) { + $release['dependencies']['required']['php'] = + array('min' => '4.0.0'); + } + $order = array(); + $bewm = $release['dependencies']['required']; + $order['php'] = $bewm['php']; + $order['pearinstaller'] = $bewm['pearinstaller']; + isset($bewm['package']) ? $order['package'] = $bewm['package'] :0; + isset($bewm['extension']) ? $order['extension'] = $bewm['extension'] :0; + $release['dependencies']['required'] = $order; } /** - * Ask for user input, confirm the answers and continue until the user is satisfied - * @param array an array of arrays, format array('name' => 'paramname', 'prompt' => - * 'text to display', 'type' => 'string'[, default => 'default value']) - * @return array + * @param array + * @access private */ - function confirmDialog($params) - { - $answers = $prompts = $types = array(); - foreach ($params as $param) { - $prompts[$param['name']] = $param['prompt']; - $types[$param['name']] = $param['type']; - $answers[$param['name']] = isset($param['default']) ? $param['default'] : ''; - } - - $tried = false; - do { - if ($tried) { - $i = 1; - foreach ($answers as $var => $value) { - if (!strlen($value)) { - echo $this->bold("* Enter an answer for #" . $i . ": ({$prompts[$var]})\n"); - } - $i++; - } - } - - $answers = $this->userDialog('', $prompts, $types, $answers); - $tried = true; - } while (is_array($answers) && count(array_filter($answers)) != count($prompts)); - - return $answers; - } - - function userDialog($command, $prompts, $types = array(), $defaults = array(), $screensize = 20) + function _convertFilelist2_0(&$package) { - if (!is_array($prompts)) { - return array(); - } - - $testprompts = array_keys($prompts); - $result = $defaults; - - reset($prompts); - if (count($prompts) === 1) { - foreach ($prompts as $key => $prompt) { - $type = $types[$key]; - $default = @$defaults[$key]; - print "$prompt "; - if ($default) { - print "[$default] "; - } - print ": "; - - $line = fgets(STDIN, 2048); - $result[$key] = ($default && trim($line) == '') ? $default : trim($line); + $ret = array('dir' => + array( + 'attribs' => array('name' => '/'), + 'file' => array() + ) + ); + $package['platform'] = + $package['install-as'] = array(); + $this->_isExtension = false; + foreach ($this->_packagefile->getFilelist() as $name => $file) { + $file['name'] = $name; + if (isset($file['role']) && $file['role'] == 'src') { + $this->_isExtension = true; } - - return $result; - } - - $first_run = true; - while (true) { - $descLength = max(array_map('strlen', $prompts)); - $descFormat = "%-{$descLength}s"; - $last = count($prompts); - - $i = 0; - foreach ($prompts as $n => $var) { - $res = isset($result[$n]) ? $result[$n] : null; - printf("%2d. $descFormat : %s\n", ++$i, $prompts[$n], $res); + if (isset($file['replacements'])) { + $repl = $file['replacements']; + unset($file['replacements']); + } else { + unset($repl); } - print "\n1-$last, 'all', 'abort', or Enter to continue: "; - - $tmp = trim(fgets(STDIN, 1024)); - if (empty($tmp)) { - break; + if (isset($file['install-as'])) { + $package['install-as'][$name] = $file['install-as']; + unset($file['install-as']); } - - if ($tmp == 'abort') { - return false; + if (isset($file['platform'])) { + $package['platform'][$name] = $file['platform']; + unset($file['platform']); } - - if (isset($testprompts[(int)$tmp - 1])) { - $var = $testprompts[(int)$tmp - 1]; - $desc = $prompts[$var]; - $current = @$result[$var]; - print "$desc [$current] : "; - $tmp = trim(fgets(STDIN, 1024)); - if ($tmp !== '') { - $result[$var] = $tmp; + $file = array('attribs' => $file); + if (isset($repl)) { + foreach ($repl as $replace ) { + $file['tasks:replace'][] = array('attribs' => $replace); } - } elseif ($tmp == 'all') { - foreach ($prompts as $var => $desc) { - $current = $result[$var]; - print "$desc [$current] : "; - $tmp = trim(fgets(STDIN, 1024)); - if (trim($tmp) !== '') { - $result[$var] = trim($tmp); - } + if (count($repl) == 1) { + $file['tasks:replace'] = $file['tasks:replace'][0]; } } - - $first_run = false; - } - - return $result; - } - - function userConfirm($prompt, $default = 'yes') - { - trigger_error("PEAR_Frontend_CLI::userConfirm not yet converted", E_USER_ERROR); - static $positives = array('y', 'yes', 'on', '1'); - static $negatives = array('n', 'no', 'off', '0'); - print "$this->lp$prompt [$default] : "; - $fp = fopen("php://stdin", "r"); - $line = fgets($fp, 2048); - fclose($fp); - $answer = strtolower(trim($line)); - if (empty($answer)) { - $answer = $default; - } - if (in_array($answer, $positives)) { - return true; - } - if (in_array($answer, $negatives)) { - return false; - } - if (in_array($default, $positives)) { - return true; + $ret['dir']['file'][] = $file; } - return false; + return $ret; } - function outputData($data, $command = '_default') + /** + * Post-process special files with install-as/platform attributes and + * make the release tag. + * + * This complex method follows this work-flow to create the release tags: + * + *
+     * - if any install-as/platform exist, create a generic release and fill it with
+     *   o  tags for 
+     *   o  tags for 
+     *   o  tags for 
+     *   o  tags for 
+     * - create a release for each platform encountered and fill with
+     *   o  tags for 
+     *   o  tags for 
+     *   o  tags for 
+     *   o  tags for 
+     *   o  tags for 
+     *   o  tags for 
+     *   o  tags for 
+     * 
+ * + * It does this by accessing the $package parameter, which contains an array with + * indices: + * + * - platform: mapping of file => OS the file should be installed on + * - install-as: mapping of file => installed name + * - osmap: mapping of OS => list of files that should be installed + * on that OS + * - notosmap: mapping of OS => list of files that should not be + * installed on that OS + * + * @param array + * @param array + * @access private + */ + function _convertRelease2_0(&$release, $package) { - switch ($command) { - case 'channel-info': - foreach ($data as $type => $section) { - if ($type == 'main') { - $section['data'] = array_values($section['data']); - } - - $this->outputData($section); - } - break; - case 'install': - case 'upgrade': - case 'upgrade-all': - if (isset($data['release_warnings'])) { - $this->_displayLine(''); - $this->_startTable(array( - 'border' => false, - 'caption' => 'Release Warnings' - )); - $this->_tableRow(array($data['release_warnings']), null, array(1 => array('wrap' => 55))); - $this->_endTable(); - $this->_displayLine(''); + //- if any install-as/platform exist, create a generic release and fill it with + if (count($package['platform']) || count($package['install-as'])) { + $generic = array(); + $genericIgnore = array(); + foreach ($package['install-as'] as $file => $as) { + //o tags for + if (!isset($package['platform'][$file])) { + $generic[] = $file; + continue; } - - $this->_displayLine($data['data']); - break; - case 'search': - $this->_startTable($data); - if (isset($data['headline']) && is_array($data['headline'])) { - $this->_tableRow($data['headline'], array('bold' => true), array(1 => array('wrap' => 55))); + //o tags for + if (isset($package['platform'][$file]) && + $package['platform'][$file]{0} == '!') { + $generic[] = $file; + continue; } - - foreach($data['data'] as $category) { - foreach($category as $pkg) { - $this->_tableRow($pkg, null, array(1 => array('wrap' => 55))); - } + //o tags for + if (isset($package['platform'][$file]) && + $package['platform'][$file]{0} != '!') { + $genericIgnore[] = $file; + continue; } - - $this->_endTable(); - break; - case 'list-all': - if (!isset($data['data'])) { - $this->_displayLine('No packages in channel'); - break; + } + foreach ($package['platform'] as $file => $platform) { + if (isset($package['install-as'][$file])) { + continue; } - - $this->_startTable($data); - if (isset($data['headline']) && is_array($data['headline'])) { - $this->_tableRow($data['headline'], array('bold' => true), array(1 => array('wrap' => 55))); + if ($platform{0} != '!') { + //o tags for + $genericIgnore[] = $file; } - - foreach($data['data'] as $category) { - foreach($category as $pkg) { - unset($pkg[4], $pkg[5]); - $this->_tableRow($pkg, null, array(1 => array('wrap' => 55))); + } + if (count($package['platform'])) { + $oses = $notplatform = $platform = array(); + foreach ($package['platform'] as $file => $os) { + // get a list of oses + if ($os{0} == '!') { + if (isset($oses[substr($os, 1)])) { + continue; + } + $oses[substr($os, 1)] = count($oses); + } else { + if (isset($oses[$os])) { + continue; + } + $oses[$os] = count($oses); } } - - $this->_endTable(); - break; - case 'config-show': - $data['border'] = false; - $opts = array( - 0 => array('wrap' => 30), - 1 => array('wrap' => 20), - 2 => array('wrap' => 35) - ); - - $this->_startTable($data); - if (isset($data['headline']) && is_array($data['headline'])) { - $this->_tableRow($data['headline'], array('bold' => true), $opts); - } - - foreach ($data['data'] as $group) { - foreach ($group as $value) { - if ($value[2] == '') { - $value[2] = ""; + //- create a release for each platform encountered and fill with + foreach ($oses as $os => $releaseNum) { + $release[$releaseNum]['installconditions']['os']['name'] = $os; + $release[$releaseNum]['filelist'] = array('install' => array(), + 'ignore' => array()); + foreach ($package['install-as'] as $file => $as) { + //o tags for + if (!isset($package['platform'][$file])) { + $release[$releaseNum]['filelist']['install'][] = + array( + 'attribs' => array( + 'name' => $file, + 'as' => $as, + ), + ); + continue; + } + //o tags for + // + if (isset($package['platform'][$file]) && + $package['platform'][$file] == $os) { + $release[$releaseNum]['filelist']['install'][] = + array( + 'attribs' => array( + 'name' => $file, + 'as' => $as, + ), + ); + continue; + } + //o tags for + // + if (isset($package['platform'][$file]) && + $package['platform'][$file] != "!$os" && + $package['platform'][$file]{0} == '!') { + $release[$releaseNum]['filelist']['install'][] = + array( + 'attribs' => array( + 'name' => $file, + 'as' => $as, + ), + ); + continue; + } + //o tags for + // + if (isset($package['platform'][$file]) && + $package['platform'][$file] == "!$os") { + $release[$releaseNum]['filelist']['ignore'][] = + array( + 'attribs' => array( + 'name' => $file, + ), + ); + continue; + } + //o tags for + // + if (isset($package['platform'][$file]) && + $package['platform'][$file]{0} != '!' && + $package['platform'][$file] != $os) { + $release[$releaseNum]['filelist']['ignore'][] = + array( + 'attribs' => array( + 'name' => $file, + ), + ); + continue; } - - $this->_tableRow($value, null, $opts); + } + foreach ($package['platform'] as $file => $platform) { + if (isset($package['install-as'][$file])) { + continue; + } + //o tags for + if ($platform == "!$os") { + $release[$releaseNum]['filelist']['ignore'][] = + array( + 'attribs' => array( + 'name' => $file, + ), + ); + continue; + } + //o tags for + if ($platform{0} != '!' && $platform != $os) { + $release[$releaseNum]['filelist']['ignore'][] = + array( + 'attribs' => array( + 'name' => $file, + ), + ); + } + } + if (!count($release[$releaseNum]['filelist']['install'])) { + unset($release[$releaseNum]['filelist']['install']); + } + if (!count($release[$releaseNum]['filelist']['ignore'])) { + unset($release[$releaseNum]['filelist']['ignore']); } } - - $this->_endTable(); - break; - case 'remote-info': - $d = $data; - $data = array( - 'caption' => 'Package details:', - 'border' => false, - 'data' => array( - array("Latest", $data['stable']), - array("Installed", $data['installed']), - array("Package", $data['name']), - array("License", $data['license']), - array("Category", $data['category']), - array("Summary", $data['summary']), - array("Description", $data['description']), - ), - ); - - if (isset($d['deprecated']) && $d['deprecated']) { - $conf = &PEAR_Config::singleton(); - $reg = $conf->getRegistry(); - $name = $reg->parsedPackageNameToString($d['deprecated'], true); - $data['data'][] = array('Deprecated! use', $name); - } - default: { - if (is_array($data)) { - $this->_startTable($data); - $count = count($data['data'][0]); - if ($count == 2) { - $opts = array(0 => array('wrap' => 25), - 1 => array('wrap' => 48) - ); - } elseif ($count == 3) { - $opts = array(0 => array('wrap' => 30), - 1 => array('wrap' => 20), - 2 => array('wrap' => 35) - ); - } else { - $opts = null; + if (count($generic) || count($genericIgnore)) { + $release[count($oses)] = array(); + if (count($generic)) { + foreach ($generic as $file) { + if (isset($package['install-as'][$file])) { + $installas = $package['install-as'][$file]; + } else { + $installas = $file; + } + $release[count($oses)]['filelist']['install'][] = + array( + 'attribs' => array( + 'name' => $file, + 'as' => $installas, + ) + ); + } } - if (isset($data['headline']) && is_array($data['headline'])) { - $this->_tableRow($data['headline'], - array('bold' => true), - $opts); + if (count($genericIgnore)) { + foreach ($genericIgnore as $file) { + $release[count($oses)]['filelist']['ignore'][] = + array( + 'attribs' => array( + 'name' => $file, + ) + ); + } } - - foreach($data['data'] as $row) { - $this->_tableRow($row, null, $opts); + } + // cleanup + foreach ($release as $i => $rel) { + if (isset($rel['filelist']['install']) && + count($rel['filelist']['install']) == 1) { + $release[$i]['filelist']['install'] = + $release[$i]['filelist']['install'][0]; } - $this->_endTable(); - } else { - $this->_displayLine($data); + if (isset($rel['filelist']['ignore']) && + count($rel['filelist']['ignore']) == 1) { + $release[$i]['filelist']['ignore'] = + $release[$i]['filelist']['ignore'][0]; + } + } + if (count($release) == 1) { + $release = $release[0]; + } + } else { + // no platform atts, but some install-as atts + foreach ($package['install-as'] as $file => $value) { + $release['filelist']['install'][] = + array( + 'attribs' => array( + 'name' => $file, + 'as' => $value + ) + ); + } + if (count($release['filelist']['install']) == 1) { + $release['filelist']['install'] = $release['filelist']['install'][0]; } } } } - function log($text, $append_crlf = true) + /** + * @param array + * @return array + * @access private + */ + function _processDep($dep) { - if ($append_crlf) { - return $this->_displayLine($text); + if ($dep['type'] == 'php') { + if ($dep['rel'] == 'has') { + // come on - everyone has php! + return false; + } } - - return $this->_display($text); - } - - function bold($text) - { - if (empty($this->term['bold'])) { - return strtoupper($text); + $php = array(); + if ($dep['type'] != 'php') { + $php['name'] = $dep['name']; + if ($dep['type'] == 'pkg') { + $php['channel'] = 'pear.php.net'; + } } - - return $this->term['bold'] . $text . $this->term['normal']; - } - - function _displayHeading($title) - { - print $this->lp.$this->bold($title)."\n"; - print $this->lp.str_repeat("=", strlen($title))."\n"; - } - - function _startTable($params = array()) - { - $params['table_data'] = array(); - $params['widest'] = array(); // indexed by column - $params['highest'] = array(); // indexed by row - $params['ncols'] = 0; - $this->params = $params; + switch ($dep['rel']) { + case 'gt' : + $php['min'] = $dep['version']; + $php['exclude'] = $dep['version']; + break; + case 'ge' : + if (!isset($dep['version'])) { + if ($dep['type'] == 'php') { + if (isset($dep['name'])) { + $dep['version'] = $dep['name']; + } + } + } + $php['min'] = $dep['version']; + break; + case 'lt' : + $php['max'] = $dep['version']; + $php['exclude'] = $dep['version']; + break; + case 'le' : + $php['max'] = $dep['version']; + break; + case 'eq' : + $php['min'] = $dep['version']; + $php['max'] = $dep['version']; + break; + case 'ne' : + $php['exclude'] = $dep['version']; + break; + case 'not' : + $php['conflicts'] = 'yes'; + break; + } + return $php; } - function _tableRow($columns, $rowparams = array(), $colparams = array()) + /** + * @param array + * @return array + */ + function _processPhpDeps($deps) { - $highest = 1; - for ($i = 0; $i < count($columns); $i++) { - $col = &$columns[$i]; - if (isset($colparams[$i]) && !empty($colparams[$i]['wrap'])) { - $col = wordwrap($col, $colparams[$i]['wrap']); - } - - if (strpos($col, "\n") !== false) { - $multiline = explode("\n", $col); - $w = 0; - foreach ($multiline as $n => $line) { - $len = strlen($line); - if ($len > $w) { - $w = $len; - } - } - $lines = count($multiline); - } else { - $w = strlen($col); + $test = array(); + foreach ($deps as $dep) { + $test[] = $this->_processDep($dep); + } + $min = array(); + $max = array(); + foreach ($test as $dep) { + if (!$dep) { + continue; } - - if (isset($this->params['widest'][$i])) { - if ($w > $this->params['widest'][$i]) { - $this->params['widest'][$i] = $w; - } - } else { - $this->params['widest'][$i] = $w; + if (isset($dep['min'])) { + $min[$dep['min']] = count($min); } - - $tmp = count_chars($columns[$i], 1); - // handle unix, mac and windows formats - $lines = (isset($tmp[10]) ? $tmp[10] : (isset($tmp[13]) ? $tmp[13] : 0)) + 1; - if ($lines > $highest) { - $highest = $lines; + if (isset($dep['max'])) { + $max[$dep['max']] = count($max); } } - - if (count($columns) > $this->params['ncols']) { - $this->params['ncols'] = count($columns); - } - - $new_row = array( - 'data' => $columns, - 'height' => $highest, - 'rowparams' => $rowparams, - 'colparams' => $colparams, - ); - $this->params['table_data'][] = $new_row; - } - - function _endTable() - { - extract($this->params); - if (!empty($caption)) { - $this->_displayHeading($caption); + if (count($min) > 0) { + uksort($min, 'version_compare'); } - - if (count($table_data) === 0) { - return; + if (count($max) > 0) { + uksort($max, 'version_compare'); } - - if (!isset($width)) { - $width = $widest; + if (count($min)) { + // get the highest minimum + $min = array_pop($a = array_flip($min)); } else { - for ($i = 0; $i < $ncols; $i++) { - if (!isset($width[$i])) { - $width[$i] = $widest[$i]; - } - } + $min = false; } - - $border = false; - if (empty($border)) { - $cellstart = ''; - $cellend = ' '; - $rowend = ''; - $padrowend = false; - $borderline = ''; + if (count($max)) { + // get the lowest maximum + $max = array_shift($a = array_flip($max)); } else { - $cellstart = '| '; - $cellend = ' '; - $rowend = '|'; - $padrowend = true; - $borderline = '+'; - foreach ($width as $w) { - $borderline .= str_repeat('-', $w + strlen($cellstart) + strlen($cellend) - 1); - $borderline .= '+'; - } + $max = false; } - - if ($borderline) { - $this->_displayLine($borderline); + if ($min) { + $php['min'] = $min; } - - for ($i = 0; $i < count($table_data); $i++) { - extract($table_data[$i]); - if (!is_array($rowparams)) { - $rowparams = array(); + if ($max) { + $php['max'] = $max; + } + $exclude = array(); + foreach ($test as $dep) { + if (!isset($dep['exclude'])) { + continue; } + $exclude[] = $dep['exclude']; + } + if (count($exclude)) { + $php['exclude'] = $exclude; + } + return $php; + } - if (!is_array($colparams)) { - $colparams = array(); + /** + * process multiple dependencies that have a name, like package deps + * @param array + * @return array + * @access private + */ + function _processMultipleDepsName($deps) + { + $ret = $tests = array(); + foreach ($deps as $name => $dep) { + foreach ($dep as $d) { + $tests[$name][] = $this->_processDep($d); } + } - $rowlines = array(); - if ($height > 1) { - for ($c = 0; $c < count($data); $c++) { - $rowlines[$c] = preg_split('/(\r?\n|\r)/', $data[$c]); - if (count($rowlines[$c]) < $height) { - $rowlines[$c] = array_pad($rowlines[$c], $height, ''); - } + foreach ($tests as $name => $test) { + $max = $min = $php = array(); + $php['name'] = $name; + foreach ($test as $dep) { + if (!$dep) { + continue; } - } else { - for ($c = 0; $c < count($data); $c++) { - $rowlines[$c] = array($data[$c]); + if (isset($dep['channel'])) { + $php['channel'] = 'pear.php.net'; } - } - - for ($r = 0; $r < $height; $r++) { - $rowtext = ''; - for ($c = 0; $c < count($data); $c++) { - if (isset($colparams[$c])) { - $attribs = array_merge($rowparams, $colparams); - } else { - $attribs = $rowparams; - } - - $w = isset($width[$c]) ? $width[$c] : 0; - //$cell = $data[$c]; - $cell = $rowlines[$c][$r]; - $l = strlen($cell); - if ($l > $w) { - $cell = substr($cell, 0, $w); - } - - if (isset($attribs['bold'])) { - $cell = $this->bold($cell); - } - - if ($l < $w) { - // not using str_pad here because we may - // add bold escape characters to $cell - $cell .= str_repeat(' ', $w - $l); - } - - $rowtext .= $cellstart . $cell . $cellend; + if (isset($dep['conflicts']) && $dep['conflicts'] == 'yes') { + $php['conflicts'] = 'yes'; } - - if (!$border) { - $rowtext = rtrim($rowtext); + if (isset($dep['min'])) { + $min[$dep['min']] = count($min); + } + if (isset($dep['max'])) { + $max[$dep['max']] = count($max); } - - $rowtext .= $rowend; - $this->_displayLine($rowtext); } + if (count($min) > 0) { + uksort($min, 'version_compare'); + } + if (count($max) > 0) { + uksort($max, 'version_compare'); + } + if (count($min)) { + // get the highest minimum + $min = array_pop($a = array_flip($min)); + } else { + $min = false; + } + if (count($max)) { + // get the lowest maximum + $max = array_shift($a = array_flip($max)); + } else { + $max = false; + } + if ($min) { + $php['min'] = $min; + } + if ($max) { + $php['max'] = $max; + } + $exclude = array(); + foreach ($test as $dep) { + if (!isset($dep['exclude'])) { + continue; + } + $exclude[] = $dep['exclude']; + } + if (count($exclude)) { + $php['exclude'] = $exclude; + } + $ret[] = $php; } - - if ($borderline) { - $this->_displayLine($borderline); - } - } - - function _displayLine($text) - { - print "$this->lp$text\n"; - } - - function _display($text) - { - print $text; + return $ret; } -} - * @author Tomas V.V. Cox - * @author Martin Jansen * @author Greg Beaver + * @author Stephan Schmidt (original XML_Serializer code) * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Installer.php,v 1.259 2009/04/09 00:55:07 dufuz Exp $ + * @version CVS: $Id: v2.php 278907 2009-04-17 21:10:04Z dufuz $ * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 + * @since File available since Release 1.4.0a1 */ - /** - * Used for installation groups in package.xml 2.0 and platform exceptions + * file/dir manipulation routines */ -require_once 'phar://install-pear-nozlib.phar/' . 'OS/Guess.php'; -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Downloader.php'; +require_once 'phar://install-pear-nozlib.phar/' . 'System.php'; +require_once 'phar://install-pear-nozlib.phar/' . 'XML/Util.php'; -define('PEAR_INSTALLER_NOBINARY', -240); /** - * Administration class used to install PEAR packages and maintain the - * installed package database. + * This class converts a PEAR_PackageFile_v2 object into any output format. * + * Supported output formats include array, XML string (using S. Schmidt's + * XML_Serializer, slightly customized) * @category pear * @package PEAR - * @author Stig Bakken - * @author Tomas V.V. Cox - * @author Martin Jansen * @author Greg Beaver + * @author Stephan Schmidt (original XML_Serializer code) * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR - * @since Class available since Release 0.1 + * @since Class available since Release 1.4.0a1 */ -class PEAR_Installer extends PEAR_Downloader +class PEAR_PackageFile_Generator_v2 { - // {{{ 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(); + /** + * default options for the serialization + * @access private + * @var array $_defaultOptions + */ + var $_defaultOptions = array( + 'indent' => ' ', // string used for indentation + 'linebreak' => "\n", // string used for newlines + 'typeHints' => false, // automatically add type hin attributes + 'addDecl' => true, // add an XML declaration + 'defaultTagName' => 'XML_Serializer_Tag', // tag used for indexed arrays or invalid names + 'classAsTagName' => false, // use classname for objects in indexed arrays + 'keyAttribute' => '_originalKey', // attribute where original key is stored + 'typeAttribute' => '_type', // attribute for type (only if typeHints => true) + 'classAttribute' => '_class', // attribute for class of objects (only if typeHints => true) + 'scalarAsAttributes' => false, // scalar values (strings, ints,..) will be serialized as attribute + 'prependAttributes' => '', // prepend string for attributes + 'indentAttributes' => false, // indent the attributes, if set to '_auto', it will indent attributes so they all start at the same column + 'mode' => 'simplexml', // use 'simplexml' to use parent name as tagname if transforming an indexed array + 'addDoctype' => false, // add a doctype declaration + 'doctype' => null, // supply a string or an array with id and uri ({@see XML_Util::getDoctypeDeclaration()} + 'rootName' => 'package', // name of the root tag + 'rootAttributes' => array( + 'version' => '2.0', + 'xmlns' => 'http://pear.php.net/dtd/package-2.0', + 'xmlns:tasks' => 'http://pear.php.net/dtd/tasks-1.0', + 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', + 'xsi:schemaLocation' => 'http://pear.php.net/dtd/tasks-1.0 +http://pear.php.net/dtd/tasks-1.0.xsd +http://pear.php.net/dtd/package-2.0 +http://pear.php.net/dtd/package-2.0.xsd', + ), // attributes of the root tag + 'attributesArray' => 'attribs', // all values in this key will be treated as attributes + 'contentName' => '_content', // this value will be used directly as content, instead of creating a new tag, may only be used in conjuction with attributesArray + 'beautifyFilelist' => false, + 'encoding' => 'UTF-8', + ); - // }}} + /** + * options for the serialization + * @access private + * @var array $options + */ + var $options = array(); - // {{{ constructor + /** + * current tag depth + * @var integer $_tagDepth + */ + var $_tagDepth = 0; + /** + * serilialized representation of the data + * @var string $_serializedData + */ + var $_serializedData = null; /** - * PEAR_Installer constructor. - * - * @param object $ui user interface object (instance of PEAR_Frontend_*) - * - * @access public - */ - function PEAR_Installer(&$ui) - { - parent::PEAR_Common(); - $this->setFrontendObject($ui); - $this->debug = $this->config->get('verbose'); - } - - function setOptions($options) - { - $this->_options = $options; - } - - function setConfig(&$config) + * @var PEAR_PackageFile_v2 + */ + var $_packagefile; + /** + * @param PEAR_PackageFile_v2 + */ + function PEAR_PackageFile_Generator_v2(&$packagefile) { - $this->config = &$config; - $this->_registry = &$config->getRegistry(); + $this->_packagefile = &$packagefile; + if (isset($this->_packagefile->encoding)) { + $this->_defaultOptions['encoding'] = $this->_packagefile->encoding; + } } - // }}} - - function _removeBackups($files) + /** + * @return string + */ + function getPackagerVersion() { - foreach ($files as $path) { - $this->addFileOperation('removebackup', array($path)); - } + return '1.9.0'; } - // {{{ _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 + * @param PEAR_Packager + * @param bool generate a .tgz or a .tar + * @param string|null temporary directory to package in */ - function _deletePackageFiles($package, $channel = false, $backup = false) + function toTgz(&$packager, $compress = true, $where = null) { - 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 'phar://install-pear-nozlib.phar/' . 'PEAR/Task/Common.php'; - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Task/Replace.php'; - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Task/Unixeol.php'; - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Task/Windowseol.php'; - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/v1.php'; - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/v2.php'; - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/Generator/v1.php'; - require_once 'phar://install-pear-nozlib.phar/' . '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; + $a = null; + return $this->toTgz2($packager, $a, $compress, $where); } - // }}} - // {{{ _installFile() - /** - * @param string filename - * @param array attributes from tag in package.xml - * @param string path to install the file in - * @param array options from command-line - * @access private + * Package up both a package.xml and package2.xml for the same release + * @param PEAR_Packager + * @param PEAR_PackageFile_v1 + * @param bool generate a .tgz or a .tar + * @param string|null temporary directory to package in */ - function _installFile($file, $atts, $tmp_path, $options) + function toTgz2(&$packager, &$pf1, $compress = true, $where = null) { - // {{{ return if this file is meant for another platform - static $os; - if (!isset($this->_registry)) { - $this->_registry = &$this->config->getRegistry(); + require_once 'phar://install-pear-nozlib.phar/' . 'Archive/Tar.php'; + if (!$this->_packagefile->isEquivalent($pf1)) { + return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: "' . + basename($pf1->getPackageFile()) . + '" is not equivalent to "' . basename($this->_packagefile->getPackageFile()) + . '"'); } - 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; + if ($where === null) { + if (!($where = System::mktemp(array('-d')))) { + return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: mktemp failed'); } - } - // }}} - - $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"); + } elseif (!@System::mkDir(array('-p', $where))) { + return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: "' . $where . '" could' . + ' not be created'); } - $save_destdir = $dest_dir; - if (!empty($atts['baseinstalldir'])) { - $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir']; + $file = $where . DIRECTORY_SEPARATOR . 'package.xml'; + if (file_exists($file) && !is_file($file)) { + return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: unable to save package.xml as' . + ' "' . $file .'"'); } - if (dirname($file) != '.' && empty($atts['install-as'])) { - $dest_dir .= DIRECTORY_SEPARATOR . dirname($file); + if (!$this->_packagefile->validate(PEAR_VALIDATE_PACKAGING)) { + return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: invalid package.xml'); } - if (empty($atts['install-as'])) { - $dest_file = $dest_dir . DIRECTORY_SEPARATOR . basename($file); - } else { - $dest_file = $dest_dir . DIRECTORY_SEPARATOR . $atts['install-as']; + $ext = $compress ? '.tgz' : '.tar'; + $pkgver = $this->_packagefile->getPackage() . '-' . $this->_packagefile->getVersion(); + $dest_package = getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext; + if (file_exists($dest_package) && !is_file($dest_package)) { + return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: cannot create tgz file "' . + $dest_package . '"'); } - $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); + $pkgfile = $this->_packagefile->getPackageFile(); + if (!$pkgfile) { + return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: package file object must ' . + 'be created from a real 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); - } - // }}} + $pkgdir = dirname(realpath($pkgfile)); + $pkgfile = basename($pkgfile); - 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); + // {{{ Create the package file list + $filelist = array(); + $i = 0; + $this->_packagefile->flattenFilelist(); + $contents = $this->_packagefile->getContents(); + if (isset($contents['bundledpackage'])) { // bundles of packages + $contents = $contents['bundledpackage']; + if (!isset($contents[0])) { + $contents = array($contents); } - $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); + $packageDir = $where; + foreach ($contents as $i => $package) { + $fname = $package; + $file = $pkgdir . DIRECTORY_SEPARATOR . $fname; + if (!file_exists($file)) { + return $packager->raiseError("File does not exist: $fname"); } - $contents = file_get_contents($orig_file); - if ($contents === false) { - $contents = ''; - } + $tfile = $packageDir . DIRECTORY_SEPARATOR . $fname; + System::mkdir(array('-p', dirname($tfile))); + copy($file, $tfile); + $filelist[$i++] = $tfile; + $packager->log(2, "Adding package $fname"); + } + } else { // normal packages + $contents = $contents['dir']['file']; + if (!isset($contents[0])) { + $contents = array($contents); + } - if (isset($atts['md5sum'])) { - $md5sum = md5($contents); + $packageDir = $where; + foreach ($contents as $i => $file) { + $fname = $file['attribs']['name']; + $atts = $file['attribs']; + $orig = $file; + $file = $pkgdir . DIRECTORY_SEPARATOR . $fname; + if (!file_exists($file)) { + return $packager->raiseError("File does not exist: $fname"); } - $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; + $origperms = fileperms($file); + $tfile = $packageDir . DIRECTORY_SEPARATOR . $fname; + unset($orig['attribs']); + if (count($orig)) { // file with tasks + // run any package-time tasks + $contents = file_get_contents($file); + foreach ($orig as $tag => $raw) { + $tag = str_replace( + array($this->_packagefile->getTasksNs() . ':', '-'), + array('', '_'), $tag); + $task = "PEAR_Task_$tag"; + $task = &new $task($this->_packagefile->_config, + $this->_packagefile->_logger, + PEAR_TASK_PACKAGE); + $task->init($raw, $atts, null); + $res = $task->startSession($this->_packagefile, $contents, $tfile); + if (!$res) { + continue; // skip this task } - } - 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); - } + if (PEAR::isError($res)) { + return $res; + } - $wp = @fopen($dest_file, "wb"); - if (!is_resource($wp)) { - return $this->raiseError("failed to create $dest_file: $php_errormsg", - PEAR_INSTALLER_FAILED); + $contents = $res; // save changes + System::mkdir(array('-p', dirname($tfile))); + $wp = fopen($tfile, "wb"); + fwrite($wp, $contents); + fclose($wp); + } } - if (@fwrite($wp, $contents) === false) { - return $this->raiseError("failed writing to $dest_file: $php_errormsg", - PEAR_INSTALLER_FAILED); + if (!file_exists($tfile)) { + System::mkdir(array('-p', dirname($tfile))); + copy($file, $tfile); } - fclose($wp); - // }}} + chmod($tfile, $origperms); + $filelist[$i++] = $tfile; + $this->_packagefile->setFileAttribute($fname, 'md5sum', md5_file($tfile), $i - 1); + $packager->log(2, "Adding file $fname"); } + } + // }}} - // {{{ 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); - } + $name = $pf1 !== null ? 'package2.xml' : 'package.xml'; + $packagexml = $this->toPackageFile($where, PEAR_VALIDATE_PACKAGING, $name); + if ($packagexml) { + $tar =& new Archive_Tar($dest_package, $compress); + $tar->setErrorHandling(PEAR_ERROR_RETURN); // XXX Don't print errors + // ----- Creates with the package.xml file + $ok = $tar->createModify(array($packagexml), '', $where); + if (PEAR::isError($ok)) { + return $packager->raiseError($ok); + } elseif (!$ok) { + return $packager->raiseError('PEAR_Packagefile_v2::toTgz(): adding ' . $name . + ' failed'); + } - 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"); - } - } - } + // ----- Add the content of the package + if (!$tar->addModify($filelist, $pkgver, $where)) { + return $packager->raiseError( + 'PEAR_Packagefile_v2::toTgz(): tarball creation failed'); } - // }}} - // {{{ 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"); - } - } + // add the package.xml version 1.0 + if ($pf1 !== null) { + $pfgen = &$pf1->getDefaultGenerator(); + $packagexml1 = $pfgen->toPackageFile($where, PEAR_VALIDATE_PACKAGING, 'package.xml', true); + if (!$tar->addModify(array($packagexml1), '', $where)) { + return $packager->raiseError( + 'PEAR_Packagefile_v2::toTgz(): adding package.xml failed'); } } - // }}} - 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')); - } + return $dest_package; } + } - // 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'); + function toPackageFile($where = null, $state = PEAR_VALIDATE_NORMAL, $name = 'package.xml') + { + if (!$this->_packagefile->validate($state)) { + return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: invalid package.xml', + null, null, null, $this->_packagefile->getValidationWarnings()); } - if ($atts['role'] != 'src') { - $this->addFileOperation("installed_as", array($file, $installed_as, - $loc, - dirname(substr($installedas_dest_file, strlen($loc))))); + if ($where === null) { + if (!($where = System::mktemp(array('-d')))) { + return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: mktemp failed'); + } + } elseif (!@System::mkDir(array('-p', $where))) { + return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: "' . $where . '" could' . + ' not be created'); } - //$this->log(2, "installed: $dest_file"); - return PEAR_INSTALLER_OK; + $newpkgfile = $where . DIRECTORY_SEPARATOR . $name; + $np = @fopen($newpkgfile, 'wb'); + if (!$np) { + return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: unable to save ' . + "$name as $newpkgfile"); + } + fwrite($np, $this->toXml($state)); + fclose($np); + return $newpkgfile; } - // }}} - // {{{ _installFile2() + function &toV2() + { + return $this->_packagefile; + } /** - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @param string filename - * @param array attributes from tag in package.xml - * @param string path to install the file in - * @param array options from command-line - * @access private + * Return an XML document based on the package info (as returned + * by the PEAR_Common::infoFrom* methods). + * + * @return string XML data */ - function _installFile2(&$pkg, $file, &$real_atts, $tmp_path, $options) + function toXml($state = PEAR_VALIDATE_NORMAL, $options = array()) { - $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; + $this->_packagefile->setDate(date('Y-m-d')); + $this->_packagefile->setTime(date('H:i:s')); + if (!$this->_packagefile->validate($state)) { + return false; } - if (!$role->isInstallable()) { - return; + if (is_array($options)) { + $this->options = array_merge($this->_defaultOptions, $options); + } else { + $this->options = $this->_defaultOptions; } - $info = $role->processInstallation($pkg, $atts['attribs'], $file, $tmp_path); - if (PEAR::isError($info)) { - return $info; + $arr = $this->_packagefile->getArray(); + if (isset($arr['filelist'])) { + unset($arr['filelist']); } - 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); + if (isset($arr['_lastversion'])) { + unset($arr['_lastversion']); } - $final_dest_file = $installed_as = $dest_file; - if (isset($this->_options['packagingroot'])) { - $final_dest_file = $this->_prependPath($final_dest_file, - $this->_options['packagingroot']); + // Fix the notes a little bit + if (isset($arr['notes'])) { + // This trims out the indenting, needs fixing + $arr['notes'] = "\n" . trim($arr['notes']) . "\n"; } - $dest_dir = dirname($final_dest_file); - $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); - // }}} + if (isset($arr['changelog']) && !empty($arr['changelog'])) { + // Fix for inconsistency how the array is filled depending on the changelog release amount + if (!isset($arr['changelog']['release'][0])) { + $release = $arr['changelog']['release']; + unset($arr['changelog']['release']); - 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"); + $arr['changelog']['release'] = array(); + $arr['changelog']['release'][0] = $release; } - } - - $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); + foreach (array_keys($arr['changelog']['release']) as $key) { + $c =& $arr['changelog']['release'][$key]; + if (isset($c['notes'])) { + // This trims out the indenting, needs fixing + $c['notes'] = "\n" . trim($c['notes']) . "\n"; } + } + } - $contents = file_get_contents($orig_file); - if ($contents === false) { - $contents = ''; - } + if ($state ^ PEAR_VALIDATE_PACKAGING && !isset($arr['bundle'])) { + $use = $this->_recursiveXmlFilelist($arr['contents']['dir']['file']); + unset($arr['contents']['dir']['file']); + if (isset($use['dir'])) { + $arr['contents']['dir']['dir'] = $use['dir']; + } + if (isset($use['file'])) { + $arr['contents']['dir']['file'] = $use['file']; + } + $this->options['beautifyFilelist'] = true; + } - if (isset($attribs['md5sum'])) { - $md5sum = md5($contents); - } + $arr['attribs']['packagerversion'] = '1.9.0'; + if ($this->serialize($arr, $options)) { + return $this->_serializedData . "\n"; + } - 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 - } + return false; + } - if (PEAR::isError($res)) { - return $res; - } - $contents = $res; // save changes - } + function _recursiveXmlFilelist($list) + { + $dirs = array(); + if (isset($list['attribs'])) { + $file = $list['attribs']['name']; + unset($list['attribs']['name']); + $attributes = $list['attribs']; + $this->_addDir($dirs, explode('/', dirname($file)), $file, $attributes); + } else { + foreach ($list as $a) { + $file = $a['attribs']['name']; + $attributes = $a['attribs']; + unset($a['attribs']); + $this->_addDir($dirs, explode('/', dirname($file)), $file, $attributes, $a); + } + } + $this->_formatDir($dirs); + $this->_deFormat($dirs); + return $dirs; + } - $wp = @fopen($dest_file, "wb"); - if (!is_resource($wp)) { - return $this->raiseError("failed to create $dest_file: $php_errormsg", - PEAR_INSTALLER_FAILED); - } + function _addDir(&$dirs, $dir, $file = null, $attributes = null, $tasks = null) + { + if (!$tasks) { + $tasks = array(); + } + if ($dir == array() || $dir == array('.')) { + $dirs['file'][basename($file)] = $tasks; + $attributes['name'] = basename($file); + $dirs['file'][basename($file)]['attribs'] = $attributes; + return; + } + $curdir = array_shift($dir); + if (!isset($dirs['dir'][$curdir])) { + $dirs['dir'][$curdir] = array(); + } + $this->_addDir($dirs['dir'][$curdir], $dir, $file, $attributes, $tasks); + } - if (fwrite($wp, $contents) === false) { - return $this->raiseError("failed writing to $dest_file: $php_errormsg", - PEAR_INSTALLER_FAILED); - } + function _formatDir(&$dirs) + { + if (!count($dirs)) { + return array(); + } + $newdirs = array(); + if (isset($dirs['dir'])) { + $newdirs['dir'] = $dirs['dir']; + } + if (isset($dirs['file'])) { + $newdirs['file'] = $dirs['file']; + } + $dirs = $newdirs; + if (isset($dirs['dir'])) { + uksort($dirs['dir'], 'strnatcasecmp'); + foreach ($dirs['dir'] as $dir => $contents) { + $this->_formatDir($dirs['dir'][$dir]); + } + } + if (isset($dirs['file'])) { + uksort($dirs['file'], 'strnatcasecmp'); + }; + } - fclose($wp); + function _deFormat(&$dirs) + { + if (!count($dirs)) { + return array(); + } + $newdirs = array(); + if (isset($dirs['dir'])) { + foreach ($dirs['dir'] as $dir => $contents) { + $newdir = array(); + $newdir['attribs']['name'] = $dir; + $this->_deFormat($contents); + foreach ($contents as $tag => $val) { + $newdir[$tag] = $val; } + $newdirs['dir'][] = $newdir; + } + if (count($newdirs['dir']) == 1) { + $newdirs['dir'] = $newdirs['dir'][0]; + } + } + if (isset($dirs['file'])) { + foreach ($dirs['file'] as $name => $file) { + $newdirs['file'][] = $file; + } + if (count($newdirs['file']) == 1) { + $newdirs['file'] = $newdirs['file'][0]; } + } + $dirs = $newdirs; + } - // {{{ check the md5 - if (isset($md5sum)) { - // Make sure the original md5 sum matches with expected - if (strtolower($md5sum) === strtolower($attribs['md5sum'])) { - $this->log(2, "md5sum ok: $final_dest_file"); + /** + * reset all options to default options + * + * @access public + * @see setOption(), XML_Unserializer() + */ + function resetOptions() + { + $this->options = $this->_defaultOptions; + } - if (isset($contents)) { - // set md5 sum based on $content in case any tasks were run. - $real_atts['attribs']['md5sum'] = md5($contents); - } - } else { - if (empty($options['force'])) { - // delete the file - if (file_exists($dest_file)) { - unlink($dest_file); - } + /** + * set an option + * + * You can use this method if you do not want to set all options in the constructor + * + * @access public + * @see resetOption(), XML_Serializer() + */ + function setOption($name, $value) + { + $this->options[$name] = $value; + } - if (!isset($options['ignore-errors'])) { - return $this->raiseError("bad md5sum for file $final_dest_file", - PEAR_INSTALLER_FAILED); - } + /** + * sets several options at once + * + * You can use this method if you do not want to set all options in the constructor + * + * @access public + * @see resetOption(), XML_Unserializer(), setOption() + */ + function setOptions($options) + { + $this->options = array_merge($this->options, $options); + } - 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"); - } - } - } + /** + * serialize data + * + * @access public + * @param mixed $data data to serialize + * @return boolean true on success, pear error on failure + */ + function serialize($data, $options = null) + { + // if options have been specified, use them instead + // of the previously defined ones + if (is_array($options)) { + $optionsBak = $this->options; + if (isset($options['overrideOptions']) && $options['overrideOptions'] == true) { + $this->options = array_merge($this->_defaultOptions, $options); } else { - $real_atts['attribs']['md5sum'] = md5_file($dest_file); + $this->options = array_merge($this->options, $options); } + } else { + $optionsBak = null; + } - // }}} - // {{{ 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')); - } + // start depth is zero + $this->_tagDepth = 0; + $this->_serializedData = ''; + // serialize an array + if (is_array($data)) { + $tagName = isset($this->options['rootName']) ? $this->options['rootName'] : 'array'; + $this->_serializedData .= $this->_serializeArray($data, $tagName, $this->options['rootAttributes']); + } - 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"); - } - } - } - } - // }}} + // add doctype declaration + if ($this->options['addDoctype'] === true) { + $this->_serializedData = XML_Util::getDoctypeDeclaration($tagName, $this->options['doctype']) + . $this->options['linebreak'] + . $this->_serializedData; + } - 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())); - } + // build xml declaration + if ($this->options['addDecl']) { + $atts = array(); + $encoding = isset($this->options['encoding']) ? $this->options['encoding'] : null; + $this->_serializedData = XML_Util::getXMLDeclaration('1.0', $encoding) + . $this->options['linebreak'] + . $this->_serializedData; } - // 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))))); + + if ($optionsBak !== null) { + $this->options = $optionsBak; } - //$this->log(2, "installed: $dest_file"); - return PEAR_INSTALLER_OK; + return true; } - // }}} - // {{{ 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) + /** + * get the result of the serialization + * + * @access public + * @return string serialized XML + */ + function getSerializedData() { - 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)); + if ($this->_serializedData === null) { + return $this->raiseError('No serialized data available. Use XML_Serializer::serialize() first.', XML_SERIALIZER_ERROR_NO_SERIALIZATION); } - $this->file_operations[] = array($type, $data); + return $this->_serializedData; } - // }}} - // {{{ startFileTransaction() - - function startFileTransaction($rollback_in_case = false) + /** + * serialize any value + * + * This method checks for the type of the value and calls the appropriate method + * + * @access private + * @param mixed $value + * @param string $tagName + * @param array $attributes + * @return string + */ + function _serializeValue($value, $tagName = null, $attributes = array()) { - if (count($this->file_operations) && $rollback_in_case) { - $this->rollbackFileTransaction(); + if (is_array($value)) { + $xml = $this->_serializeArray($value, $tagName, $attributes); + } elseif (is_object($value)) { + $xml = $this->_serializeObject($value, $tagName); + } else { + $tag = array( + 'qname' => $tagName, + 'attributes' => $attributes, + 'content' => $value + ); + $xml = $this->_createXMLTag($tag); } - $this->file_operations = array(); + return $xml; } - // }}} - // {{{ commitFileTransaction() - - function commitFileTransaction() + /** + * serialize an array + * + * @access private + * @param array $array array to serialize + * @param string $tagName name of the root tag + * @param array $attributes attributes for the root tag + * @return string $string serialized data + * @uses XML_Util::isValidName() to check, whether key has to be substituted + */ + function _serializeArray(&$array, $tagName = null, $attributes = array()) { - $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"; - } + $_content = null; - // 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]); - } + /** + * check for special attributes + */ + if ($this->options['attributesArray'] !== null) { + if (isset($array[$this->options['attributesArray']])) { + $attributes = $array[$this->options['attributesArray']]; + unset($array[$this->options['attributesArray']]); + } + /** + * check for special content + */ + if ($this->options['contentName'] !== null) { + if (isset($array[$this->options['contentName']])) { + $_content = $array[$this->options['contentName']]; + unset($array[$this->options['contentName']]); + } + } + } + + /* + * if mode is set to simpleXML, check whether + * the array is associative or indexed + */ + if (is_array($array) && $this->options['mode'] == 'simplexml') { + $indexed = true; + if (!count($array)) { + $indexed = false; + } + foreach ($array as $key => $val) { + if (!is_int($key)) { + $indexed = false; break; - case 'delete': - if (!file_exists($data[0])) { - $this->log(2, "warning: file $data[0] doesn't exist, can't be deleted"); + } + } + + if ($indexed && $this->options['mode'] == 'simplexml') { + $string = ''; + foreach ($array as $key => $val) { + if ($this->options['beautifyFilelist'] && $tagName == 'dir') { + if (!isset($this->_curdir)) { + $this->_curdir = ''; + } + $savedir = $this->_curdir; + if (isset($val['attribs'])) { + if ($val['attribs']['name'] == '/') { + $this->_curdir = '/'; + } else { + if ($this->_curdir == '/') { + $this->_curdir = ''; + } + $this->_curdir .= '/' . $val['attribs']['name']; + } + } } - // check that directory is writable - if (file_exists($data[0])) { - if (!is_writable(dirname($data[0]))) { - $errors[] = "permission denied ($type): $data[0]"; + $string .= $this->_serializeValue( $val, $tagName, $attributes); + if ($this->options['beautifyFilelist'] && $tagName == 'dir') { + $string .= ' '; + if (empty($savedir)) { + unset($this->_curdir); } 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); - } + $this->_curdir = $savedir; } } - break; - } - } - // }}} - $m = count($errors); - if ($m > 0) { - foreach ($errors as $error) { - if (!isset($this->_options['soft'])) { - $this->log(1, $error); + $string .= $this->options['linebreak']; + // do indentation + if ($this->options['indent'] !== null && $this->_tagDepth > 0) { + $string .= str_repeat($this->options['indent'], $this->_tagDepth); + } } - } - - if (!isset($this->_options['ignore-errors'])) { - return false; + return rtrim($string); } } - $this->_dirtree = array(); - // {{{ really commit the transaction - foreach ($this->file_operations as $i => $tr) { - if (!$tr) { - // support removal of non-existing backups - continue; + if ($this->options['scalarAsAttributes'] === true) { + foreach ($array as $key => $value) { + if (is_scalar($value) && (XML_Util::isValidName($key) === true)) { + unset($array[$key]); + $attributes[$this->options['prependAttributes'].$key] = $value; + } } + } - 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': - $test = file_exists($data[1]) ? @unlink($data[1]) : null; - if (!$test && file_exists($data[1])) { - if ($data[2]) { - $extra = ', this extension must be installed manually. Rename to "' . - basename($data[1]) . '"'; - } else { - $extra = ''; - } + // check for empty array => create empty tag + if (empty($array)) { + $tag = array( + 'qname' => $tagName, + 'content' => $_content, + 'attributes' => $attributes + ); - if (!isset($this->_options['soft'])) { - $this->log(1, 'Could not delete ' . $data[1] . ', cannot rename ' . - $data[0] . $extra); - } + } else { + $this->_tagDepth++; + $tmp = $this->options['linebreak']; + foreach ($array as $key => $value) { + // do indentation + if ($this->options['indent'] !== null && $this->_tagDepth > 0) { + $tmp .= str_repeat($this->options['indent'], $this->_tagDepth); + } - if (!isset($this->_options['ignore-errors'])) { - return false; - } + // copy key + $origKey = $key; + // key cannot be used as tagname => use default tag + $valid = XML_Util::isValidName($key); + if (PEAR::isError($valid)) { + if ($this->options['classAsTagName'] && is_object($value)) { + $key = get_class($value); + } else { + $key = $this->options['defaultTagName']; } - - // 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; + } + $atts = array(); + if ($this->options['typeHints'] === true) { + $atts[$this->options['typeAttribute']] = gettype($value); + if ($key !== $origKey) { + $atts[$this->options['keyAttribute']] = (string)$origKey; } - // 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; + } + if ($this->options['beautifyFilelist'] && $key == 'dir') { + if (!isset($this->_curdir)) { + $this->_curdir = ''; } - - $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; + $savedir = $this->_curdir; + if (isset($value['attribs'])) { + if ($value['attribs']['name'] == '/') { + $this->_curdir = '/'; + } else { + $this->_curdir .= '/' . $value['attribs']['name']; } - $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]); + if (is_string($value) && $value && ($value{strlen($value) - 1} == "\n")) { + $value .= str_repeat($this->options['indent'], $this->_tagDepth); + } + $tmp .= $this->_createXMLTag(array( + 'qname' => $key, + 'attributes' => $atts, + 'content' => $value ) + ); + if ($this->options['beautifyFilelist'] && $key == 'dir') { + if (isset($value['attribs'])) { + $tmp .= ' '; + if (empty($savedir)) { + unset($this->_curdir); + } else { + $this->_curdir = $savedir; } } - break; + } + $tmp .= $this->options['linebreak']; } - } - // }}} - $this->log(2, "successfully committed $n file operations"); - $this->file_operations = array(); - return true; - } - // }}} - // {{{ rollbackFileTransaction() + $this->_tagDepth--; + if ($this->options['indent']!==null && $this->_tagDepth>0) { + $tmp .= str_repeat($this->options['indent'], $this->_tagDepth); + } - 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; + if (trim($tmp) === '') { + $tmp = null; } - } - $this->pkginfo->resetDirtree(); - $this->file_operations = array(); - } - // }}} - // {{{ mkDirHier($dir) + $tag = array( + 'qname' => $tagName, + 'content' => $tmp, + 'attributes' => $attributes + ); + } + if ($this->options['typeHints'] === true) { + if (!isset($tag['attributes'][$this->options['typeAttribute']])) { + $tag['attributes'][$this->options['typeAttribute']] = 'array'; + } + } - function mkDirHier($dir) - { - $this->addFileOperation('mkdir', array($dir)); - return parent::mkDirHier($dir); + $string = $this->_createXMLTag($tag, false); + return $string; } - // }}} - // {{{ 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: - * - * - * array('pkg' => 'package_name', 'file' => '/path/to/local/file', - * 'info' => array() // parsed package.xml - * ); - * - * @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) + /** + * create a tag from an array + * this method awaits an array in the following format + * array( + * 'qname' => $tagName, + * 'attributes' => array(), + * 'content' => $content, // optional + * 'namespace' => $namespace // optional + * 'namespaceUri' => $namespaceUri // optional + * ) + * + * @access private + * @param array $tag tag definition + * @param boolean $replaceEntities whether to replace XML entities in content or not + * @return string $string XML tag + */ + function _createXMLTag($tag, $replaceEntities = true) { - // 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; - } + if ($this->options['indentAttributes'] !== false) { + $multiline = true; + $indent = str_repeat($this->options['indent'], $this->_tagDepth); - // }}} - // {{{ _parsePackageXml() + if ($this->options['indentAttributes'] == '_auto') { + $indent .= str_repeat(' ', (strlen($tag['qname'])+2)); - function _parsePackageXml(&$descfile, &$tmpdir) - { - if (substr($descfile, -4) == '.xml') { - $tmpdir = false; + } else { + $indent .= $this->options['indentAttributes']; + } } else { - // {{{ Decompress pack in tmp dir ------------------------------------- - - // To allow relative package file names - $descfile = realpath($descfile); + $indent = $multiline = false; + } - if (PEAR::isError($tmpdir = System::mktemp('-d'))) { - return $tmpdir; + if (is_array($tag['content'])) { + if (empty($tag['content'])) { + $tag['content'] = ''; } - $this->log(3, '+ tmp dir created at ' . $tmpdir); - // }}} + } elseif(is_scalar($tag['content']) && (string)$tag['content'] == '') { + $tag['content'] = ''; } - // 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']); - } - } + if (is_scalar($tag['content']) || is_null($tag['content'])) { + if ($this->options['encoding'] == 'UTF-8' && + version_compare(phpversion(), '5.0.0', 'lt') + ) { + $tag['content'] = utf8_encode($tag['content']); } - return $this->raiseError('Installation failed: invalid package file'); - } - $descfile = $p->getPackageFile(); - return $p; - } + if ($replaceEntities === true) { + $replaceEntities = XML_UTIL_ENTITIES_XML; + } - // }}} - /** - * 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; + $tag = XML_Util::createTagFromArray($tag, $replaceEntities, $multiline, $indent, $this->options['linebreak']); + } elseif (is_array($tag['content'])) { + $tag = $this->_serializeArray($tag['content'], $tag['qname'], $tag['attributes']); + } elseif (is_object($tag['content'])) { + $tag = $this->_serializeObject($tag['content'], $tag['qname'], $tag['attributes']); + } elseif (is_resource($tag['content'])) { + settype($tag['content'], 'string'); + $tag = XML_Util::createTagFromArray($tag, $replaceEntities); } - $this->_downloadedPackages = &$pkgs; + return $tag; } - +} + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: v1.php 276385 2009-02-24 23:46:03Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/** + * package.xml abstraction class + */ +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/v1.php'; +/** + * Parser for package.xml version 1.0 + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_PackageFile_Parser_v1 +{ + var $_registry; + var $_config; + var $_logger; /** - * Set the list of PEAR_Downloader_Package objects to allow more sane - * dependency validation - * @param array + * BC hack to allow PEAR_Common::infoFromString() to sort of + * work with the version 2.0 format - there's no filelist though + * @param PEAR_PackageFile_v2 */ - function setUninstallPackages(&$pkgs) + function fromV2($packagefile) { - $this->_downloadedPackages = &$pkgs; + $info = $packagefile->getArray(true); + $ret = new PEAR_PackageFile_v1; + $ret->fromArray($info['old']); } - function getInstallPackages() + function setConfig(&$c) { - return $this->_downloadedPackages; + $this->_config = &$c; + $this->_registry = &$c->getRegistry(); } - // {{{ install() + function setLogger(&$l) + { + $this->_logger = &$l; + } /** - * 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 + * @param string contents of package.xml file, version 1.0 + * @return bool success of parsing */ - - function install($pkgfile, $options = array()) + function &parse($data, $file, $archive = false) { - $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 = ''; - $pkg = &$this->_parsePackageXml($descfile, $tmpdir); - if (PEAR::isError($pkg)) { - return $pkg; - } + if (!extension_loaded('xml')) { + return PEAR::raiseError('Cannot create xml parser for parsing package.xml, no xml extension'); + } + $xp = xml_parser_create(); + if (!$xp) { + $a = &PEAR::raiseError('Cannot create xml parser for parsing package.xml'); + return $a; } + xml_set_object($xp, $this); + xml_set_element_handler($xp, '_element_start_1_0', '_element_end_1_0'); + xml_set_character_data_handler($xp, '_pkginfo_cdata_1_0'); + xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, false); - if (realpath($descfile) != realpath($pkgfile)) { - $tar = new Archive_Tar($pkgfile); - if (!$tar->extract($tmpdir)) { - return $this->raiseError("unable to unpack $pkgfile"); - } + $this->element_stack = array(); + $this->_packageInfo = array('provides' => array()); + $this->current_element = false; + unset($this->dir_install); + $this->_packageInfo['filelist'] = array(); + $this->filelist =& $this->_packageInfo['filelist']; + $this->dir_names = array(); + $this->in_changelog = false; + $this->d_i = 0; + $this->cdata = ''; + $this->_isValid = true; + + if (!xml_parse($xp, $data, 1)) { + $code = xml_get_error_code($xp); + $line = xml_get_current_line_number($xp); + xml_parser_free($xp); + $a = &PEAR::raiseError(sprintf("XML error: %s at line %d", + $str = xml_error_string($code), $line), 2); + return $a; } - $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']); + xml_parser_free($xp); - $packrootphp_dir = $this->_prependPath( - $this->config->get('php_dir', null, $channel), - $this->_options['packagingroot']); + $pf = new PEAR_PackageFile_v1; + $pf->setConfig($this->_config); + if (isset($this->_logger)) { + $pf->setLogger($this->_logger); } + $pf->setPackagefile($file, $archive); + $pf->fromArray($this->_packageInfo); + return $pf; + } + // {{{ _unIndent() - 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); + /** + * Unindent given string + * + * @param string $str The string that has to be unindented. + * @return string + * @access private + */ + function _unIndent($str) + { + // remove leading newlines + $str = preg_replace('/^[\r\n]+/', '', $str); + // find whitespace at the beginning of the first line + $indent_len = strspn($str, " \t"); + $indent = substr($str, 0, $indent_len); + $data = ''; + // remove the same amount of whitespace from following lines + foreach (explode("\n", $str) as $line) { + if (substr($line, 0, $indent_len) == $indent) { + $data .= substr($line, $indent_len) . "\n"; + } elseif (trim(substr($line, 0, $indent_len))) { + $data .= ltrim($line); } - $this->installroot = ''; } + return $data; + } - // {{{ 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; - } + // Support for package DTD v1.0: + // {{{ _element_start_1_0() - if (sizeof($test)) { - $pkgs = $this->getInstallPackages(); - $found = false; - foreach ($pkgs as $param) { - if ($pkg->isSubpackageOf($param)) { - $found = true; - break; - } + /** + * XML parser callback for ending elements. Used for version 1.0 + * packages. + * + * @param resource $xp XML parser resource + * @param string $name name of ending element + * + * @return void + * + * @access private + */ + function _element_start_1_0($xp, $name, $attribs) + { + array_push($this->element_stack, $name); + $this->current_element = $name; + $spos = sizeof($this->element_stack) - 2; + $this->prev_element = ($spos >= 0) ? $this->element_stack[$spos] : ''; + $this->current_attributes = $attribs; + $this->cdata = ''; + switch ($name) { + case 'dir': + if ($this->in_changelog) { + break; } - - if ($found) { - // subpackages can conflict with earlier versions of parent packages - $parentreg = $installregistry->packageInfo($param->getPackage(), null, $param->getChannel()); - $tmp = $test; - foreach ($tmp as $file => $info) { - if (is_array($info)) { - if (strtolower($info[1]) == strtolower($param->getPackage()) && - strtolower($info[0]) == strtolower($param->getChannel()) - ) { - if (isset($parentreg['filelist'][$file])) { - unset($parentreg['filelist'][$file]); - } else{ - $pos = strpos($file, '/'); - $basedir = substr($file, 0, $pos); - $file2 = substr($file, $pos + 1); - if (isset($parentreg['filelist'][$file2]['baseinstalldir']) - && $parentreg['filelist'][$file2]['baseinstalldir'] === $basedir - ) { - unset($parentreg['filelist'][$file2]); - } - } - - unset($test[$file]); - } - } else { - if (strtolower($param->getChannel()) != 'pear.php.net') { - continue; - } - - if (strtolower($info) == strtolower($param->getPackage())) { - if (isset($parentreg['filelist'][$file])) { - unset($parentreg['filelist'][$file]); - } else{ - $pos = strpos($file, '/'); - $basedir = substr($file, 0, $pos); - $file2 = substr($file, $pos + 1); - if (isset($parentreg['filelist'][$file2]['baseinstalldir']) - && $parentreg['filelist'][$file2]['baseinstalldir'] === $basedir - ) { - unset($parentreg['filelist'][$file2]); - } - } - - unset($test[$file]); - } - } + if (array_key_exists('name', $attribs) && $attribs['name'] != '/') { + $attribs['name'] = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), + $attribs['name']); + if (strrpos($attribs['name'], '/') === strlen($attribs['name']) - 1) { + $attribs['name'] = substr($attribs['name'], 0, + strlen($attribs['name']) - 1); } - - $pfk = &new PEAR_PackageFile($this->config); - $parentpkg = &$pfk->fromArray($parentreg); - $installregistry->updatePackage2($parentpkg); - } - - if ($param->getChannel() == 'pecl.php.net' && isset($options['upgrade'])) { - $tmp = $test; - foreach ($tmp as $file => $info) { - if (is_string($info)) { - // pear.php.net packages are always stored as strings - if (strtolower($info) == strtolower($param->getPackage())) { - // upgrading existing package - unset($test[$file]); - } - } + if (strpos($attribs['name'], '/') === 0) { + $attribs['name'] = substr($attribs['name'], 1); } + $this->dir_names[] = $attribs['name']; } - - if (count($test)) { - $msg = "$channel/$pkgname: conflicting files found:\n"; - $longest = max(array_map("strlen", array_keys($test))); - $fmt = "%${longest}s (%s)\n"; - foreach ($test as $file => $info) { - if (!is_array($info)) { - $info = array('pear.php.net', $info); + if (isset($attribs['baseinstalldir'])) { + $this->dir_install = $attribs['baseinstalldir']; + } + if (isset($attribs['role'])) { + $this->dir_role = $attribs['role']; + } + break; + case 'file': + if ($this->in_changelog) { + break; + } + if (isset($attribs['name'])) { + $path = ''; + if (count($this->dir_names)) { + foreach ($this->dir_names as $dir) { + $path .= $dir . '/'; } - $info = $info[0] . '/' . $info[1]; - $msg .= sprintf($fmt, $file, $info); } - - if (!isset($options['ignore-errors'])) { - return $this->raiseError($msg); + $path .= preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), + $attribs['name']); + unset($attribs['name']); + $this->current_path = $path; + $this->filelist[$path] = $attribs; + // Set the baseinstalldir only if the file don't have this attrib + if (!isset($this->filelist[$path]['baseinstalldir']) && + isset($this->dir_install)) + { + $this->filelist[$path]['baseinstalldir'] = $this->dir_install; } - - if (!isset($options['soft'])) { - $this->log(0, "WARNING: $msg"); + // Set the Role + if (!isset($this->filelist[$path]['role']) && isset($this->dir_role)) { + $this->filelist[$path]['role'] = $this->dir_role; } } - } + break; + case 'replace': + if (!$this->in_changelog) { + $this->filelist[$this->current_path]['replacements'][] = $attribs; + } + break; + case 'maintainers': + $this->_packageInfo['maintainers'] = array(); + $this->m_i = 0; // maintainers array index + break; + case 'maintainer': + // compatibility check + if (!isset($this->_packageInfo['maintainers'])) { + $this->_packageInfo['maintainers'] = array(); + $this->m_i = 0; + } + $this->_packageInfo['maintainers'][$this->m_i] = array(); + $this->current_maintainer =& $this->_packageInfo['maintainers'][$this->m_i]; + break; + case 'changelog': + $this->_packageInfo['changelog'] = array(); + $this->c_i = 0; // changelog array index + $this->in_changelog = true; + break; + case 'release': + if ($this->in_changelog) { + $this->_packageInfo['changelog'][$this->c_i] = array(); + $this->current_release = &$this->_packageInfo['changelog'][$this->c_i]; + } else { + $this->current_release = &$this->_packageInfo; + } + break; + case 'deps': + if (!$this->in_changelog) { + $this->_packageInfo['release_deps'] = array(); + } + break; + case 'dep': + // dependencies array index + if (!$this->in_changelog) { + $this->d_i++; + isset($attribs['type']) ? ($attribs['type'] = strtolower($attribs['type'])) : false; + $this->_packageInfo['release_deps'][$this->d_i] = $attribs; + } + break; + case 'configureoptions': + if (!$this->in_changelog) { + $this->_packageInfo['configure_options'] = array(); + } + break; + case 'configureoption': + if (!$this->in_changelog) { + $this->_packageInfo['configure_options'][] = $attribs; + } + break; + case 'provides': + if (empty($attribs['type']) || empty($attribs['name'])) { + break; + } + $attribs['explicit'] = true; + $this->_packageInfo['provides']["$attribs[type];$attribs[name]"] = $attribs; + break; + case 'package' : + if (isset($attribs['version'])) { + $this->_packageInfo['xsdversion'] = trim($attribs['version']); + } else { + $this->_packageInfo['xsdversion'] = '1.0'; + } + if (isset($attribs['packagerversion'])) { + $this->_packageInfo['packagerversion'] = $attribs['packagerversion']; + } + break; } - // }}} + } - $this->startFileTransaction(); + // }}} + // {{{ _element_end_1_0() - if (empty($options['upgrade']) && empty($options['soft'])) { - // checks to do only when installing new packages - if ($channel == 'pecl.php.net') { - $test = $installregistry->packageExists($pkgname, $channel); - if (!$test) { - $test = $installregistry->packageExists($pkgname, 'pear.php.net'); + /** + * XML parser callback for ending elements. Used for version 1.0 + * packages. + * + * @param resource $xp XML parser resource + * @param string $name name of ending element + * + * @return void + * + * @access private + */ + function _element_end_1_0($xp, $name) + { + $data = trim($this->cdata); + switch ($name) { + case 'name': + switch ($this->prev_element) { + case 'package': + $this->_packageInfo['package'] = $data; + break; + case 'maintainer': + $this->current_maintainer['name'] = $data; + break; } - } else { - $test = $installregistry->packageExists($pkgname, $channel); - } - - if (empty($options['force']) && $test) { - return $this->raiseError("$channel/$pkgname is already installed"); - } - } else { - $usechannel = $channel; - if ($channel == 'pecl.php.net') { - $test = $installregistry->packageExists($pkgname, $channel); - if (!$test) { - $test = $installregistry->packageExists($pkgname, 'pear.php.net'); - $usechannel = 'pear.php.net'; + break; + case 'extends' : + $this->_packageInfo['extends'] = $data; + break; + case 'summary': + $this->_packageInfo['summary'] = $data; + break; + case 'description': + $data = $this->_unIndent($this->cdata); + $this->_packageInfo['description'] = $data; + break; + case 'user': + $this->current_maintainer['handle'] = $data; + break; + case 'email': + $this->current_maintainer['email'] = $data; + break; + case 'role': + $this->current_maintainer['role'] = $data; + break; + case 'version': + if ($this->in_changelog) { + $this->current_release['version'] = $data; + } else { + $this->_packageInfo['version'] = $data; } - } else { - $test = $installregistry->packageExists($pkgname, $channel); - } - - if ($test) { - $v1 = $installregistry->packageInfo($pkgname, 'version', $usechannel); - $v2 = $pkg->getVersion(); - $cmp = version_compare("$v1", "$v2", 'gt'); - if (empty($options['force']) && !version_compare("$v2", "$v1", 'gt')) { - return $this->raiseError("upgrade to a newer version ($v2 is not newer than $v1)"); + break; + case 'date': + if ($this->in_changelog) { + $this->current_release['release_date'] = $data; + } else { + $this->_packageInfo['release_date'] = $data; + } + break; + case 'notes': + // try to "de-indent" release notes in case someone + // has been over-indenting their xml ;-) + // Trim only on the right side + $data = rtrim($this->_unIndent($this->cdata)); + if ($this->in_changelog) { + $this->current_release['release_notes'] = $data; + } else { + $this->_packageInfo['release_notes'] = $data; + } + break; + case 'warnings': + if ($this->in_changelog) { + $this->current_release['release_warnings'] = $data; + } else { + $this->_packageInfo['release_warnings'] = $data; + } + break; + case 'state': + if ($this->in_changelog) { + $this->current_release['release_state'] = $data; + } else { + $this->_packageInfo['release_state'] = $data; } + break; + case 'license': + if ($this->in_changelog) { + $this->current_release['release_license'] = $data; + } else { + $this->_packageInfo['release_license'] = $data; + } + break; + case 'dep': + if ($data && !$this->in_changelog) { + $this->_packageInfo['release_deps'][$this->d_i]['name'] = $data; + } + break; + case 'dir': + if ($this->in_changelog) { + break; + } + array_pop($this->dir_names); + break; + case 'file': + if ($this->in_changelog) { + break; + } + if ($data) { + $path = ''; + if (count($this->dir_names)) { + foreach ($this->dir_names as $dir) { + $path .= $dir . '/'; + } + } + $path .= $data; + $this->filelist[$path] = $this->current_attributes; + // Set the baseinstalldir only if the file don't have this attrib + if (!isset($this->filelist[$path]['baseinstalldir']) && + isset($this->dir_install)) + { + $this->filelist[$path]['baseinstalldir'] = $this->dir_install; + } + // Set the Role + if (!isset($this->filelist[$path]['role']) && isset($this->dir_role)) { + $this->filelist[$path]['role'] = $this->dir_role; + } + } + break; + case 'maintainer': + if (empty($this->_packageInfo['maintainers'][$this->m_i]['role'])) { + $this->_packageInfo['maintainers'][$this->m_i]['role'] = 'lead'; + } + $this->m_i++; + break; + case 'release': + if ($this->in_changelog) { + $this->c_i++; + } + break; + case 'changelog': + $this->in_changelog = false; + break; + } + array_pop($this->element_stack); + $spos = sizeof($this->element_stack) - 1; + $this->current_element = ($spos > 0) ? $this->element_stack[$spos] : ''; + $this->cdata = ''; + } - if (empty($options['register-only'])) { - // when upgrading, remove old release's files first: - if (PEAR::isError($err = $this->_deletePackageFiles($pkgname, $usechannel, - true))) { - if (!isset($options['ignore-errors'])) { - return $this->raiseError($err); - } + // }}} + // {{{ _pkginfo_cdata_1_0() - if (!isset($options['soft'])) { - $this->log(0, 'WARNING: ' . $err->getMessage()); - } - } else { - $backedup = $err; - } - } - } + /** + * XML parser callback for character data. Used for version 1.0 + * packages. + * + * @param resource $xp XML parser resource + * @param string $name character data + * + * @return void + * + * @access private + */ + function _pkginfo_cdata_1_0($xp, $data) + { + if (isset($this->cdata)) { + $this->cdata .= $data; } + } - // {{{ Copy files to dest dir --------------------------------------- + // }}} +} +?> + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: v2.php 276385 2009-02-24 23:46:03Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/** + * base xml parser class + */ +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/XMLParser.php'; +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/v2.php'; +/** + * Parser for package.xml version 2.0 + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_PackageFile_Parser_v2 extends PEAR_XMLParser +{ + var $_config; + var $_logger; + var $_registry; - // info from the package it self we want to access from _installFile - $this->pkginfo = &$pkg; - // used to determine whether we should build any C code - $this->source_files = 0; + function setConfig(&$c) + { + $this->_config = &$c; + $this->_registry = &$c->getRegistry(); + } - $savechannel = $this->config->get('default_channel'); - if (empty($options['register-only']) && !is_dir($php_dir)) { - if (PEAR::isError(System::mkdir(array('-p'), $php_dir))) { - return $this->raiseError("no installation destination directory '$php_dir'\n"); + function setLogger(&$l) + { + $this->_logger = &$l; + } + /** + * Unindent given string + * + * @param string $str The string that has to be unindented. + * @return string + * @access private + */ + function _unIndent($str) + { + // remove leading newlines + $str = preg_replace('/^[\r\n]+/', '', $str); + // find whitespace at the beginning of the first line + $indent_len = strspn($str, " \t"); + $indent = substr($str, 0, $indent_len); + $data = ''; + // remove the same amount of whitespace from following lines + foreach (explode("\n", $str) as $line) { + if (substr($line, 0, $indent_len) == $indent) { + $data .= substr($line, $indent_len) . "\n"; + } else { + $data .= $line . "\n"; } } + return $data; + } - $tmp_path = dirname($descfile); - if (substr($pkgfile, -4) != '.xml') { - $tmp_path .= DIRECTORY_SEPARATOR . $pkgname . '-' . $pkg->getVersion(); + /** + * post-process data + * + * @param string $data + * @param string $element element name + */ + function postProcess($data, $element) + { + if ($element == 'notes') { + return trim($this->_unIndent($data)); } + return trim($data); + } - $this->configSet('default_channel', $channel); - // {{{ install files - - $ver = $pkg->getPackagexmlVersion(); - if (version_compare($ver, '2.0', '>=')) { - $filelist = $pkg->getInstallationFilelist(); - } else { - $filelist = $pkg->getFileList(); + /** + * @param string + * @param string file name of the package.xml + * @param string|false name of the archive this package.xml came from, if any + * @param string class name to instantiate and return. This must be PEAR_PackageFile_v2 or + * a subclass + * @return PEAR_PackageFile_v2 + */ + function &parse($data, $file, $archive = false, $class = 'PEAR_PackageFile_v2') + { + if (PEAR::isError($err = parent::parse($data, $file))) { + return $err; } - if (PEAR::isError($filelist)) { - return $filelist; + $ret = new $class; + $ret->encoding = $this->encoding; + $ret->setConfig($this->_config); + if (isset($this->_logger)) { + $ret->setLogger($this->_logger); } - $p = &$installregistry->getPackage($pkgname, $channel); - if (empty($options['register-only']) && $p) { - $dirtree = $p->getDirTree(); - } else { - $dirtree = false; - } + $ret->fromArray($this->_unserializedData); + $ret->setPackagefile($file, $archive); + return $ret; + } +} + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: v1.php 276383 2009-02-24 23:39:37Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/** + * For error handling + */ +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/ErrorStack.php'; - $pkg->resetFilelist(); - $pkg->setLastInstalledVersion($installregistry->packageInfo($pkg->getPackage(), - 'version', $pkg->getChannel())); - foreach ($filelist as $file => $atts) { - $this->expectError(PEAR_INSTALLER_FAILED); - if ($pkg->getPackagexmlVersion() == '1.0') { - $res = $this->_installFile($file, $atts, $tmp_path, $options); - } else { - $res = $this->_installFile2($pkg, $file, $atts, $tmp_path, $options); - } - $this->popExpect(); +/** + * Error code if parsing is attempted with no xml extension + */ +define('PEAR_PACKAGEFILE_ERROR_NO_XML_EXT', 3); - if (PEAR::isError($res)) { - if (empty($options['ignore-errors'])) { - $this->rollbackFileTransaction(); - if ($res->getMessage() == "file does not exist") { - $this->raiseError("file $file in package.xml does not exist"); - } +/** + * Error code if creating the xml parser resource fails + */ +define('PEAR_PACKAGEFILE_ERROR_CANT_MAKE_PARSER', 4); - return $this->raiseError($res); - } +/** + * Error code used for all sax xml parsing errors + */ +define('PEAR_PACKAGEFILE_ERROR_PARSER_ERROR', 5); - if (!isset($options['soft'])) { - $this->log(0, "Warning: " . $res->getMessage()); - } - } +/** + * Error code used when there is no name + */ +define('PEAR_PACKAGEFILE_ERROR_NO_NAME', 6); - $real = isset($atts['attribs']) ? $atts['attribs'] : $atts; - if ($res == PEAR_INSTALLER_OK && $real['role'] != 'src') { - // Register files that were installed - $pkg->installedFile($file, $atts); - } - } - // }}} +/** + * Error code when a package name is not valid + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_NAME', 7); - // {{{ compile and install source files - if ($this->source_files > 0 && empty($options['nobuild'])) { - if (PEAR::isError($err = - $this->_compileSourceFiles($savechannel, $pkg))) { - return $err; - } - } - // }}} +/** + * Error code used when no summary is parsed + */ +define('PEAR_PACKAGEFILE_ERROR_NO_SUMMARY', 8); - if (isset($backedup)) { - $this->_removeBackups($backedup); - } +/** + * Error code for summaries that are more than 1 line + */ +define('PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY', 9); - if (!$this->commitFileTransaction()) { - $this->rollbackFileTransaction(); - $this->configSet('default_channel', $savechannel); - return $this->raiseError("commit failed", PEAR_INSTALLER_FAILED); - } - // }}} +/** + * Error code used when no description is present + */ +define('PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION', 10); - $ret = false; - $installphase = 'install'; - $oldversion = false; - // {{{ Register that the package is installed ----------------------- - if (empty($options['upgrade'])) { - // if 'force' is used, replace the info in registry - $usechannel = $channel; - if ($channel == 'pecl.php.net') { - $test = $installregistry->packageExists($pkgname, $channel); - if (!$test) { - $test = $installregistry->packageExists($pkgname, 'pear.php.net'); - $usechannel = 'pear.php.net'; - } - } else { - $test = $installregistry->packageExists($pkgname, $channel); - } +/** + * Error code used when no license is present + */ +define('PEAR_PACKAGEFILE_ERROR_NO_LICENSE', 11); - if (!empty($options['force']) && $test) { - $oldversion = $installregistry->packageInfo($pkgname, 'version', $usechannel); - $installregistry->deletePackage($pkgname, $usechannel); - } - $ret = $installregistry->addPackage2($pkg); - } else { - if ($dirtree) { - $this->startFileTransaction(); - // attempt to delete empty directories - uksort($dirtree, array($this, '_sortDirs')); - foreach($dirtree as $dir => $notused) { - $this->addFileOperation('rmdir', array($dir)); - } - $this->commitFileTransaction(); - } +/** + * Error code used when a version number is not present + */ +define('PEAR_PACKAGEFILE_ERROR_NO_VERSION', 12); - $usechannel = $channel; - if ($channel == 'pecl.php.net') { - $test = $installregistry->packageExists($pkgname, $channel); - if (!$test) { - $test = $installregistry->packageExists($pkgname, 'pear.php.net'); - $usechannel = 'pear.php.net'; - } - } else { - $test = $installregistry->packageExists($pkgname, $channel); - } +/** + * Error code used when a version number is invalid + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_VERSION', 13); - // new: upgrade installs a package if it isn't installed - if (!$test) { - $ret = $installregistry->addPackage2($pkg); - } else { - if ($usechannel != $channel) { - $installregistry->deletePackage($pkgname, $usechannel); - $ret = $installregistry->addPackage2($pkg); - } else { - $ret = $installregistry->updatePackage2($pkg); - } - $installphase = 'upgrade'; - } - } +/** + * Error code when release state is missing + */ +define('PEAR_PACKAGEFILE_ERROR_NO_STATE', 14); - if (!$ret) { - $this->configSet('default_channel', $savechannel); - return $this->raiseError("Adding package $channel/$pkgname to registry failed"); - } - // }}} +/** + * Error code when release state is invalid + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_STATE', 15); - $this->configSet('default_channel', $savechannel); - if (class_exists('PEAR_Task_Common')) { // this is auto-included if any tasks exist - if (PEAR_Task_Common::hasPostinstallTasks()) { - PEAR_Task_Common::runPostinstallTasks($installphase); - } - } +/** + * Error code when release state is missing + */ +define('PEAR_PACKAGEFILE_ERROR_NO_DATE', 16); - return $pkg->toArray(true); - } +/** + * Error code when release state is invalid + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_DATE', 17); - // }}} +/** + * Error code when no release notes are found + */ +define('PEAR_PACKAGEFILE_ERROR_NO_NOTES', 18); - // {{{ _compileSourceFiles() - /** - * @param string - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - */ - function _compileSourceFiles($savechannel, &$filelist) - { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Builder.php'; - $this->log(1, "$this->source_files source files, building"); - $bob = &new PEAR_Builder($this->ui); - $bob->debug = $this->debug; - $built = $bob->build($filelist, array(&$this, '_buildCallback')); - if (PEAR::isError($built)) { - $this->rollbackFileTransaction(); - $this->configSet('default_channel', $savechannel); - return $built; - } +/** + * Error code when no maintainers are found + */ +define('PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS', 19); - $this->log(1, "\nBuild process completed successfully"); - foreach ($built as $ext) { - $bn = basename($ext['file']); - list($_ext_name, $_ext_suff) = explode('.', $bn); - if ($_ext_suff == '.so' || $_ext_suff == '.dll') { - if (extension_loaded($_ext_name)) { - $this->raiseError("Extension '$_ext_name' already loaded. " . - 'Please unload it in your php.ini file ' . - 'prior to install or upgrade'); - } - $role = 'ext'; - } else { - $role = 'src'; - } +/** + * Error code when a maintainer has no handle + */ +define('PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE', 20); - $dest = $ext['dest']; - $packagingroot = ''; - if (isset($this->_options['packagingroot'])) { - $packagingroot = $this->_options['packagingroot']; - } +/** + * Error code when a maintainer has no handle + */ +define('PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE', 21); - $copyto = $this->_prependPath($dest, $packagingroot); - if ($copyto != $dest) { - $this->log(1, "Installing '$dest' as '$copyto'"); - } else { - $this->log(1, "Installing '$dest'"); - } +/** + * Error code when a maintainer has no name + */ +define('PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME', 22); - $copydir = dirname($copyto); - // pretty much nothing happens if we are only registering the install - if (empty($this->_options['register-only'])) { - if (!file_exists($copydir) || !is_dir($copydir)) { - if (!$this->mkDirHier($copydir)) { - return $this->raiseError("failed to mkdir $copydir", - PEAR_INSTALLER_FAILED); - } +/** + * Error code when a maintainer has no email + */ +define('PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL', 23); - $this->log(3, "+ mkdir $copydir"); - } +/** + * Error code when a maintainer has no handle + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_MAINTROLE', 24); - if (!@copy($ext['file'], $copyto)) { - return $this->raiseError("failed to write $copyto ($php_errormsg)", PEAR_INSTALLER_FAILED); - } +/** + * Error code when a dependency is not a PHP dependency, but has no name + */ +define('PEAR_PACKAGEFILE_ERROR_NO_DEPNAME', 25); - $this->log(3, "+ cp $ext[file] $copyto"); - $this->addFileOperation('rename', array($ext['file'], $copyto)); - if (!OS_WINDOWS) { - $mode = 0666 & ~(int)octdec($this->config->get('umask')); - $this->addFileOperation('chmod', array($mode, $copyto)); - if (!@chmod($copyto, $mode)) { - $this->log(0, "failed to change mode of $copyto ($php_errormsg)"); - } - } - } +/** + * Error code when a dependency has no type (pkg, php, etc.) + */ +define('PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE', 26); - if ($filelist->getPackageXmlVersion() == '1.0') { - $filelist->installedFile($bn, array( - 'role' => $role, - 'name' => $bn, - 'installed_as' => $dest, - 'php_api' => $ext['php_api'], - 'zend_mod_api' => $ext['zend_mod_api'], - 'zend_ext_api' => $ext['zend_ext_api'], - )); - } else { - $filelist->installedFile($bn, array('attribs' => array( - 'role' => $role, - 'name' => $bn, - 'installed_as' => $dest, - 'php_api' => $ext['php_api'], - 'zend_mod_api' => $ext['zend_mod_api'], - 'zend_ext_api' => $ext['zend_ext_api'], - ))); - } - } - } +/** + * Error code when a dependency has no relation (lt, ge, has, etc.) + */ +define('PEAR_PACKAGEFILE_ERROR_NO_DEPREL', 27); - // }}} - function &getUninstallPackages() - { - return $this->_downloadedPackages; - } - // {{{ uninstall() +/** + * Error code when a dependency is not a 'has' relation, but has no version + */ +define('PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION', 28); - /** - * Uninstall a package - * - * This method removes all files installed by the application, and then - * removes any empty directories. - * @param string package name - * @param array Command-line options. Possibilities include: - * - * - installroot: base installation dir, if not the default - * - register-only : update registry but don't remove files - * - nodeps: do not process dependencies of other packages to ensure - * uninstallation does not break things - */ - function uninstall($package, $options = array()) - { - if (isset($options['installroot'])) { - $this->config->setInstallRoot($options['installroot']); - } else { - $this->config->setInstallRoot(''); - } +/** + * Error code when a dependency has an invalid relation + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPREL', 29); - $this->installroot = ''; - $this->_registry = &$this->config->getRegistry(); - if (is_object($package)) { - $channel = $package->getChannel(); - $pkg = $package; - $package = $pkg->getPackage(); - } else { - $pkg = false; - $info = $this->_registry->parsePackageName($package, - $this->config->get('default_channel')); - $channel = $info['channel']; - $package = $info['package']; - } +/** + * Error code when a dependency has an invalid type + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPTYPE', 30); - $savechannel = $this->config->get('default_channel'); - $this->configSet('default_channel', $channel); - if (!is_object($pkg)) { - $pkg = $this->_registry->getPackage($package, $channel); - } +/** + * Error code when a dependency has an invalid optional option + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL', 31); - if (!$pkg) { - $this->configSet('default_channel', $savechannel); - return $this->raiseError($this->_registry->parsedPackageNameToString( - array( - 'channel' => $channel, - 'package' => $package - ), true) . ' not installed'); - } +/** + * Error code when a dependency is a pkg dependency, and has an invalid package name + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPNAME', 32); - if ($pkg->getInstalledBinary()) { - // this is just an alias for a binary package - return $this->_registry->deletePackage($package, $channel); - } +/** + * Error code when a dependency has a channel="foo" attribute, and foo is not a registered channel + */ +define('PEAR_PACKAGEFILE_ERROR_UNKNOWN_DEPCHANNEL', 33); - $filelist = $pkg->getFilelist(); - PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); - if (!class_exists('PEAR_Dependency2')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Dependency2.php'; - } +/** + * Error code when rel="has" and version attribute is present. + */ +define('PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED', 34); - $depchecker = &new PEAR_Dependency2($this->config, $options, - array('channel' => $channel, 'package' => $package), - PEAR_VALIDATE_UNINSTALLING); - $e = $depchecker->validatePackageUninstall($this); - PEAR::staticPopErrorHandling(); - if (PEAR::isError($e)) { - if (!isset($options['ignore-errors'])) { - return $this->raiseError($e); - } +/** + * Error code when type="php" and dependency name is present + */ +define('PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED', 35); - if (!isset($options['soft'])) { - $this->log(0, 'WARNING: ' . $e->getMessage()); - } - } elseif (is_array($e)) { - if (!isset($options['soft'])) { - $this->log(0, $e[0]); - } - } +/** + * Error code when a configure option has no name + */ +define('PEAR_PACKAGEFILE_ERROR_NO_CONFNAME', 36); + +/** + * Error code when a configure option has no name + */ +define('PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT', 37); + +/** + * Error code when a file in the filelist has an invalid role + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE', 38); - $this->pkginfo = &$pkg; - // pretty much nothing happens if we are only registering the uninstall - if (empty($options['register-only'])) { - // {{{ Delete the files - $this->startFileTransaction(); - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - if (PEAR::isError($err = $this->_deletePackageFiles($package, $channel))) { - PEAR::popErrorHandling(); - $this->rollbackFileTransaction(); - $this->configSet('default_channel', $savechannel); - if (!isset($options['ignore-errors'])) { - return $this->raiseError($err); - } +/** + * Error code when a file in the filelist has no role + */ +define('PEAR_PACKAGEFILE_ERROR_NO_FILEROLE', 39); - if (!isset($options['soft'])) { - $this->log(0, 'WARNING: ' . $err->getMessage()); - } - } else { - PEAR::popErrorHandling(); - } +/** + * Error code when analyzing a php source file that has parse errors + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE', 40); - if (!$this->commitFileTransaction()) { - $this->rollbackFileTransaction(); - if (!isset($options['ignore-errors'])) { - return $this->raiseError("uninstall failed"); - } +/** + * Error code when analyzing a php source file reveals a source element + * without a package name prefix + */ +define('PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX', 41); - if (!isset($options['soft'])) { - $this->log(0, 'WARNING: uninstall failed'); - } - } else { - $this->startFileTransaction(); - if ($dirtree = $pkg->getDirTree()) { - // attempt to delete empty directories - uksort($dirtree, array($this, '_sortDirs')); - foreach($dirtree as $dir => $notused) { - $this->addFileOperation('rmdir', array($dir)); - } - } else { - $this->configSet('default_channel', $savechannel); - return $this->_registry->deletePackage($package, $channel); - } +/** + * Error code when an unknown channel is specified + */ +define('PEAR_PACKAGEFILE_ERROR_UNKNOWN_CHANNEL', 42); - if (!$this->commitFileTransaction()) { - $this->rollbackFileTransaction(); - if (!isset($options['ignore-errors'])) { - return $this->raiseError("uninstall failed"); - } +/** + * Error code when no files are found in the filelist + */ +define('PEAR_PACKAGEFILE_ERROR_NO_FILES', 43); - if (!isset($options['soft'])) { - $this->log(0, 'WARNING: uninstall failed'); - } - } - } - // }}} - } +/** + * Error code when a file is not valid php according to _analyzeSourceCode() + */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_FILE', 44); - $this->configSet('default_channel', $savechannel); - // Register that the package is no longer installed - return $this->_registry->deletePackage($package, $channel); - } +/** + * Error code when the channel validator returns an error or warning + */ +define('PEAR_PACKAGEFILE_ERROR_CHANNELVAL', 45); - /** - * Sort a list of arrays of array(downloaded packagefilename) by dependency. - * - * It also removes duplicate dependencies - * @param array an array of PEAR_PackageFile_v[1/2] objects - * @return array|PEAR_Error array of array(packagefilename, package.xml contents) - */ - function sortPackagesForUninstall(&$packages) - { - $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->config); - if (PEAR::isError($this->_dependencyDB)) { - return $this->_dependencyDB; - } - usort($packages, array(&$this, '_sortUninstall')); - } +/** + * Error code when a php5 package is packaged in php4 (analysis doesn't work) + */ +define('PEAR_PACKAGEFILE_ERROR_PHP5', 46); - function _sortUninstall($a, $b) - { - if (!$a->getDeps() && !$b->getDeps()) { - return 0; // neither package has dependencies, order is insignificant - } - if ($a->getDeps() && !$b->getDeps()) { - return -1; // $a must be installed after $b because $a has dependencies - } - if (!$a->getDeps() && $b->getDeps()) { - return 1; // $b must be installed after $a because $b has dependencies - } - // both packages have dependencies - if ($this->_dependencyDB->dependsOn($a, $b)) { - return -1; - } - if ($this->_dependencyDB->dependsOn($b, $a)) { - return 1; - } - return 0; - } +/** + * Error code when a file is listed in package.xml but does not exist + */ +define('PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND', 47); - // }}} - // {{{ _sortDirs() - function _sortDirs($a, $b) - { - if (strnatcmp($a, $b) == -1) return 1; - if (strnatcmp($a, $b) == 1) return -1; - return 0; - } +/** + * Error code when a debug > 1) || - ($what == 'output' && $this->debug > 0)) { - $this->ui->outputData(rtrim($data), 'build'); - } - } +/** + * Error code when a package has no lead developer + */ +define('PEAR_PACKAGEFILE_ERROR_NO_LEAD', 51); - // }}} -} - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Role.php,v 1.22 2009/04/10 19:42:49 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * base class for installer roles - */ -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Installer/Role/Common.php'; -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/XMLParser.php'; -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Installer_Role -{ - /** - * Set up any additional configuration variables that file roles require - * - * Never call this directly, it is called by the PEAR_Config constructor - * @param PEAR_Config - * @access private - * @static - */ - function initializeConfig(&$config) - { - if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { - PEAR_Installer_Role::registerRoles(); - } - - foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $class => $info) { - if (!$info['config_vars']) { - continue; - } - - $config->_addConfigVars($class, $info['config_vars']); - } - } - - /** - * @param PEAR_PackageFile_v2 - * @param string role name - * @param PEAR_Config - * @return PEAR_Installer_Role_Common - * @static - */ - function &factory($pkg, $role, &$config) - { - if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { - PEAR_Installer_Role::registerRoles(); - } - - if (!in_array($role, PEAR_Installer_Role::getValidRoles($pkg->getPackageType()))) { - $a = false; - return $a; - } - - $a = 'PEAR_Installer_Role_' . ucfirst($role); - if (!class_exists($a)) { - require_once 'phar://install-pear-nozlib.phar/' . str_replace('_', '/', $a) . '.php'; - } - - $b = new $a($config); - return $b; - } - - /** - * Get a list of file roles that are valid for the particular release type. - * - * For instance, src files serve no purpose in regular php releases. - * @param string - * @param bool clear cache - * @return array - * @static - */ - function getValidRoles($release, $clear = false) - { - if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { - PEAR_Installer_Role::registerRoles(); - } - - static $ret = array(); - if ($clear) { - $ret = array(); - } - - if (isset($ret[$release])) { - return $ret[$release]; - } - - $ret[$release] = array(); - foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) { - if (in_array($release, $okreleases['releasetypes'])) { - $ret[$release][] = strtolower(str_replace('PEAR_Installer_Role_', '', $role)); - } - } - - return $ret[$release]; - } - - /** - * Get a list of roles that require their files to be installed - * - * Most roles must be installed, but src and package roles, for instance - * are pseudo-roles. src files are compiled into a new extension. Package - * roles are actually fully bundled releases of a package - * @param bool clear cache - * @return array - * @static - */ - function getInstallableRoles($clear = false) - { - if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { - PEAR_Installer_Role::registerRoles(); - } - - static $ret; - if ($clear) { - unset($ret); - } - - if (isset($ret)) { - return $ret; - } - - $ret = array(); - foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) { - if ($okreleases['installable']) { - $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role)); - } - } - - return $ret; - } - - /** - * Return an array of roles that are affected by the baseinstalldir attribute - * - * Most roles ignore this attribute, and instead install directly into: - * PackageName/filepath - * so a tests file tests/file.phpt is installed into PackageName/tests/filepath.php - * @param bool clear cache - * @return array - * @static - */ - function getBaseinstallRoles($clear = false) - { - if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { - PEAR_Installer_Role::registerRoles(); - } - - static $ret; - if ($clear) { - unset($ret); - } - - if (isset($ret)) { - return $ret; - } - - $ret = array(); - foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) { - if ($okreleases['honorsbaseinstall']) { - $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role)); - } - } - - return $ret; - } - - /** - * Return an array of file roles that should be analyzed for PHP content at package time, - * like the "php" role. - * @param bool clear cache - * @return array - * @static - */ - function getPhpRoles($clear = false) - { - if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) { - PEAR_Installer_Role::registerRoles(); - } - - static $ret; - if ($clear) { - unset($ret); - } - - if (isset($ret)) { - return $ret; - } - - $ret = array(); - foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) { - if ($okreleases['phpfile']) { - $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role)); - } - } - - return $ret; - } - - /** - * Scan through the Command directory looking for classes - * and see what commands they implement. - * @param string which directory to look for classes, defaults to - * the Installer/Roles subdirectory of - * the directory from where this file (__FILE__) is - * included. - * - * @return bool TRUE on success, a PEAR error on failure - * @access public - * @static - */ - function registerRoles($dir = null) - { - $GLOBALS['_PEAR_INSTALLER_ROLES'] = array(); - $parser = new PEAR_XMLParser; - if ($dir === null) { - $dir = dirname(__FILE__) . '/Role'; - } - - if (!file_exists($dir) || !is_dir($dir)) { - return PEAR::raiseError("registerRoles: opendir($dir) failed: does not exist/is not directory"); - } - - $dp = @opendir($dir); - if (empty($dp)) { - return PEAR::raiseError("registerRoles: opendir($dir) failed: $php_errmsg"); - } - - while ($entry = readdir($dp)) { - if ($entry{0} == '.' || substr($entry, -4) != '.xml') { - continue; - } - - $class = "PEAR_Installer_Role_".substr($entry, 0, -4); - // List of roles - if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'][$class])) { - $file = "$dir/$entry"; - $parser->parse(file_get_contents($file)); - $data = $parser->getData(); - if (!is_array($data['releasetypes'])) { - $data['releasetypes'] = array($data['releasetypes']); - } - - $GLOBALS['_PEAR_INSTALLER_ROLES'][$class] = $data; - } - } - - closedir($dp); - ksort($GLOBALS['_PEAR_INSTALLER_ROLES']); - PEAR_Installer_Role::getBaseinstallRoles(true); - PEAR_Installer_Role::getInstallableRoles(true); - PEAR_Installer_Role::getPhpRoles(true); - PEAR_Installer_Role::getValidRoles('****', true); - return true; - } -} - * @copyright 1997-2006 The PHP Group - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Common.php,v 1.13 2009/02/24 23:39:37 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 + * Error code when a filename begins with "." */ +define('PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME', 52); /** - * Base class for all installation roles. - * - * This class allows extensibility of file roles. Packages with complex - * customization can now provide custom file roles along with the possibility of - * adding configuration values to match. + * package.xml encapsulator * @category pear * @package PEAR * @author Greg Beaver - * @copyright 1997-2006 The PHP Group + * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 1.4.0a1 */ -class PEAR_Installer_Role_Common +class PEAR_PackageFile_v1 { /** - * @var PEAR_Config - * @access protected + * @access private + * @var PEAR_ErrorStack + * @access private */ - var $config; + var $_stack; /** - * @param PEAR_Config + * A registry object, used to access the package name validation regex for non-standard channels + * @var PEAR_Registry + * @access private */ - function PEAR_Installer_Role_Common(&$config) - { - $this->config = $config; - } + var $_registry; /** - * Retrieve configuration information about a file role from its XML info + * An object that contains a log method that matches PEAR_Common::log's signature + * @var object + * @access private + */ + var $_logger; + + /** + * Parsed package information + * @var array + * @access private + */ + var $_packageInfo; + + /** + * path to package.xml + * @var string + * @access private + */ + var $_packageFile; + + /** + * path to package .tgz or false if this is a local/extracted package.xml + * @var string + * @access private + */ + var $_archiveFile; + + /** + * @var int + * @access private + */ + var $_isValid = 0; + + /** + * Determines whether this packagefile was initialized only with partial package info * - * @param string $role Role Classname, as in "PEAR_Installer_Role_Data" - * @return array + * If this package file was constructed via parsing REST, it will only contain + * + * - package name + * - channel name + * - dependencies + * @var boolean + * @access private */ - function getInfo($role) + var $_incomplete = true; + + /** + * @param bool determines whether to return a PEAR_Error object, or use the PEAR_ErrorStack + * @param string Name of Error Stack class to use. + */ + function PEAR_PackageFile_v1() { - if (empty($GLOBALS['_PEAR_INSTALLER_ROLES'][$role])) { - return PEAR::raiseError('Unknown Role class: "' . $role . '"'); - } - return $GLOBALS['_PEAR_INSTALLER_ROLES'][$role]; + $this->_stack = &new PEAR_ErrorStack('PEAR_PackageFile_v1'); + $this->_stack->setErrorMessageTemplate($this->_getErrorMessage()); + $this->_isValid = 0; + } + + function installBinary($installer) + { + return false; + } + + function isExtension($name) + { + return false; + } + + function setConfig(&$config) + { + $this->_config = &$config; + $this->_registry = &$config->getRegistry(); + } + + function setRequestedGroup() + { + // placeholder } /** - * This is called for each file to set up the directories and files - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @param array attributes from the tag - * @param string file name - * @return array an array consisting of: + * For saving in the registry. * - * 1 the original, pre-baseinstalldir installation directory - * 2 the final installation directory - * 3 the full path to the final location of the file - * 4 the location of the pre-installation file + * Set the last version that was installed + * @param string */ - function processInstallation($pkg, $atts, $file, $tmp_path, $layer = null) + function setLastInstalledVersion($version) { - $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . - ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this))))); - if (PEAR::isError($roleInfo)) { - return $roleInfo; - } - if (!$roleInfo['locationconfig']) { - return false; - } - if ($roleInfo['honorsbaseinstall']) { - $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'], $layer, - $pkg->getChannel()); - if (!empty($atts['baseinstalldir'])) { - $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir']; - } - } elseif ($roleInfo['unusualbaseinstall']) { - $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'], - $layer, $pkg->getChannel()) . DIRECTORY_SEPARATOR . $pkg->getPackage(); - if (!empty($atts['baseinstalldir'])) { - $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir']; - } - } else { - $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'], - $layer, $pkg->getChannel()) . DIRECTORY_SEPARATOR . $pkg->getPackage(); - } - 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_dir, $dest_file, $orig_file) = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"), - array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR, - DIRECTORY_SEPARATOR), - array($dest_dir, $dest_file, $orig_file)); - return array($save_destdir, $dest_dir, $dest_file, $orig_file); + $this->_packageInfo['_lastversion'] = $version; } /** - * Get the name of the configuration variable that specifies the location of this file * @return string|false */ - function getLocationConfig() + function getLastInstalledVersion() { - $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . - ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this))))); - if (PEAR::isError($roleInfo)) { - return $roleInfo; + if (isset($this->_packageInfo['_lastversion'])) { + return $this->_packageInfo['_lastversion']; } - return $roleInfo['locationconfig']; + return false; } - /** - * Do any unusual setup here - * @param PEAR_Installer - * @param PEAR_PackageFile_v2 - * @param array file attributes - * @param string file name - */ - function setup(&$installer, $pkg, $atts, $file) + function getInstalledBinary() { + return false; } - function isExecutable() + function listPostinstallScripts() { - $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . - ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this))))); - if (PEAR::isError($roleInfo)) { - return $roleInfo; - } - return $roleInfo['executable']; + return false; } - function isInstallable() + function initPostinstallScripts() { - $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . - ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this))))); - if (PEAR::isError($roleInfo)) { - return $roleInfo; - } - return $roleInfo['installable']; + return false; } - function isExtension() + function setLogger(&$logger) { - $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' . - ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this))))); - if (PEAR::isError($roleInfo)) { - return $roleInfo; + if ($logger && (!is_object($logger) || !method_exists($logger, 'log'))) { + return PEAR::raiseError('Logger must be compatible with PEAR_Common::log'); } - return $roleInfo['phpextension']; + $this->_logger = &$logger; } -} -?> - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Data.php,v 1.8 2009/02/24 23:39:37 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Installer_Role_Data extends PEAR_Installer_Role_Common {} -?> - php - extsrc - extbin - zendextsrc - zendextbin - 1 - data_dir - - - - - - - - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Doc.php,v 1.8 2009/02/24 23:39:37 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Installer_Role_Doc extends PEAR_Installer_Role_Common {} -?> - php - extsrc - extbin - zendextsrc - zendextbin - 1 - doc_dir - - - - - - - - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Php.php,v 1.9 2009/02/24 23:39:37 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Installer_Role_Php extends PEAR_Installer_Role_Common {} -?> - php - extsrc - extbin - zendextsrc - zendextbin - 1 - php_dir - 1 - - 1 - - - - - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Script.php,v 1.8 2009/02/24 23:39:37 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Installer_Role_Script extends PEAR_Installer_Role_Common {} -?> - php - extsrc - extbin - zendextsrc - zendextbin - 1 - bin_dir - 1 - - - 1 - - - - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Test.php,v 1.8 2009/02/24 23:39:37 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ - -/** - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Installer_Role_Test extends PEAR_Installer_Role_Common {} -?> - php - extsrc - extbin - zendextsrc - zendextbin - 1 - test_dir - - - - - - - - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: PackageFile.php,v 1.48 2009/04/09 22:16:26 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * needed for PEAR_VALIDATE_* constants - */ -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Validate.php'; -/** - * Error code if the package.xml tag does not contain a valid version - */ -define('PEAR_PACKAGEFILE_ERROR_NO_PACKAGEVERSION', 1); -/** - * Error code if the package.xml tag version is not supported (version 1.0 and 1.1 are the only supported versions, - * currently - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_PACKAGEVERSION', 2); -/** - * Abstraction for the package.xml package description file - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_PackageFile -{ - /** - * @var PEAR_Config - */ - var $_config; - var $_debug; - /** - * Temp directory for uncompressing tgz files. - * @var string|false - */ - var $_tmpdir; - var $_logger = false; - /** - * @var boolean - */ - var $_rawReturn = false; + function setPackagefile($file, $archive = false) + { + $this->_packageFile = $file; + $this->_archiveFile = $archive ? $archive : $file; + } + + function getPackageFile() + { + return isset($this->_packageFile) ? $this->_packageFile : false; + } - /** - * - * @param PEAR_Config $config - * @param ? $debug - * @param string @tmpdir Optional temporary directory for uncompressing - * files - */ - function PEAR_PackageFile(&$config, $debug = false, $tmpdir = false) + function getPackageType() { - $this->_config = $config; - $this->_debug = $debug; - $this->_tmpdir = $tmpdir; + return 'php'; } - /** - * Turn off validation - return a parsed package.xml without checking it - * - * This is used by the package-validate command - */ - function rawReturn() + function getArchiveFile() { - $this->_rawReturn = true; + return $this->_archiveFile; } - function setLogger(&$l) + function packageInfo($field) { - $this->_logger = &$l; + if (!is_string($field) || empty($field) || + !isset($this->_packageInfo[$field])) { + return false; + } + return $this->_packageInfo[$field]; } - /** - * Create a PEAR_PackageFile_Parser_v* of a given version. - * @param int $version - * @return PEAR_PackageFile_Parser_v1|PEAR_PackageFile_Parser_v1 - */ - function &parserFactory($version) + function setDirtree($path) { - if (!in_array($version{0}, array('1', '2'))) { - $a = false; - return $a; + if (!isset($this->_packageInfo['dirtree'])) { + $this->_packageInfo['dirtree'] = array(); } + $this->_packageInfo['dirtree'][$path] = true; + } - include_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/Parser/v' . $version{0} . '.php'; - $version = $version{0}; - $class = "PEAR_PackageFile_Parser_v$version"; - $a = new $class; - return $a; + function getDirtree() + { + if (isset($this->_packageInfo['dirtree']) && count($this->_packageInfo['dirtree'])) { + return $this->_packageInfo['dirtree']; + } + return false; } - /** - * For simpler unit-testing - * @return string - */ - function getClassPrefix() + function resetDirtree() { - return 'PEAR_PackageFile_v'; + unset($this->_packageInfo['dirtree']); } - /** - * Create a PEAR_PackageFile_v* of a given version. - * @param int $version - * @return PEAR_PackageFile_v1|PEAR_PackageFile_v1 - */ - function &factory($version) + function fromArray($pinfo) { - if (!in_array($version{0}, array('1', '2'))) { - $a = false; - return $a; - } + $this->_incomplete = false; + $this->_packageInfo = $pinfo; + } - include_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/v' . $version{0} . '.php'; - $version = $version{0}; - $class = $this->getClassPrefix() . $version; - $a = new $class; - return $a; + function isIncomplete() + { + return $this->_incomplete; } - /** - * Create a PEAR_PackageFile_v* from its toArray() method - * - * WARNING: no validation is performed, the array is assumed to be valid, - * always parse from xml if you want validation. - * @param array $arr - * @return PEAR_PackageFileManager_v1|PEAR_PackageFileManager_v2 - * @uses factory() to construct the returned object. - */ - function &fromArray($arr) + function getChannel() { - if (isset($arr['xsdversion'])) { - $obj = &$this->factory($arr['xsdversion']); - if ($this->_logger) { - $obj->setLogger($this->_logger); - } + return 'pear.php.net'; + } - $obj->setConfig($this->_config); - $obj->fromArray($arr); - return $obj; - } + function getUri() + { + return false; + } - if (isset($arr['package']['attribs']['version'])) { - $obj = &$this->factory($arr['package']['attribs']['version']); - } else { - $obj = &$this->factory('1.0'); - } + function getTime() + { + return false; + } - if ($this->_logger) { - $obj->setLogger($this->_logger); + function getExtends() + { + if (isset($this->_packageInfo['extends'])) { + return $this->_packageInfo['extends']; } - - $obj->setConfig($this->_config); - $obj->fromArray($arr); - return $obj; + return false; } /** - * Create a PEAR_PackageFile_v* from an XML string. - * @access public - * @param string $data contents of package.xml file - * @param int $state package state (one of PEAR_VALIDATE_* constants) - * @param string $file full path to the package.xml file (and the files - * it references) - * @param string $archive optional name of the archive that the XML was - * extracted from, if any - * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @uses parserFactory() to construct a parser to load the package. + * @return array */ - function &fromXmlString($data, $state, $file, $archive = false) + function toArray() { - if (preg_match('/]+version="([0-9]+\.[0-9]+)"/', $data, $packageversion)) { - if (!in_array($packageversion[1], array('1.0', '2.0', '2.1'))) { - return PEAR::raiseError('package.xml version "' . $packageversion[1] . - '" is not supported, only 1.0, 2.0, and 2.1 are supported.'); - } - - $object = &$this->parserFactory($packageversion[1]); - if ($this->_logger) { - $object->setLogger($this->_logger); - } + if (!$this->validate(PEAR_VALIDATE_NORMAL)) { + return false; + } + return $this->getArray(); + } - $object->setConfig($this->_config); - $pf = $object->parse($data, $file, $archive); - if (PEAR::isError($pf)) { - return $pf; - } + function getArray() + { + return $this->_packageInfo; + } - if ($this->_rawReturn) { - return $pf; - } + function getName() + { + return $this->getPackage(); + } - if (!$pf->validate($state)) { - if ($this->_config->get('verbose') > 0 - && $this->_logger && $pf->getValidationWarnings(false)) { - foreach ($pf->getValidationWarnings(false) as $warning) { - $this->_logger->log(0, 'ERROR: ' . $warning['message']); - } - } + function getPackage() + { + if (isset($this->_packageInfo['package'])) { + return $this->_packageInfo['package']; + } + return false; + } - $a = PEAR::raiseError('Parsing of package.xml from file "' . $file . '" failed', - 2, null, null, $pf->getValidationWarnings()); - return $a; - } + /** + * WARNING - don't use this unless you know what you are doing + */ + function setRawPackage($package) + { + $this->_packageInfo['package'] = $package; + } - if ($this->_logger && $pf->getValidationWarnings(false)) { - foreach ($pf->getValidationWarnings() as $warning) { - $this->_logger->log(0, 'WARNING: ' . $warning['message']); - } - } + function setPackage($package) + { + $this->_packageInfo['package'] = $package; + $this->_isValid = false; + } - if (method_exists($pf, 'flattenFilelist')) { - $pf->flattenFilelist(); // for v2 - } + function getVersion() + { + if (isset($this->_packageInfo['version'])) { + return $this->_packageInfo['version']; + } + return false; + } - return $pf; - } elseif (preg_match('/]+version="([^"]+)"/', $data, $packageversion)) { - $a = PEAR::raiseError('package.xml file "' . $file . - '" has unsupported package.xml version "' . $packageversion[1] . '"'); - return $a; - } else { - if (!class_exists('PEAR_ErrorStack')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/ErrorStack.php'; - } + function setVersion($version) + { + $this->_packageInfo['version'] = $version; + $this->_isValid = false; + } - PEAR_ErrorStack::staticPush('PEAR_PackageFile', - PEAR_PACKAGEFILE_ERROR_NO_PACKAGEVERSION, - 'warning', array('xml' => $data), 'package.xml "' . $file . - '" has no package.xml version'); - $object = &$this->parserFactory('1.0'); - $object->setConfig($this->_config); - $pf = $object->parse($data, $file, $archive); - if (PEAR::isError($pf)) { - return $pf; - } + function clearMaintainers() + { + unset($this->_packageInfo['maintainers']); + } - if ($this->_rawReturn) { - return $pf; - } + function getMaintainers() + { + if (isset($this->_packageInfo['maintainers'])) { + return $this->_packageInfo['maintainers']; + } + return false; + } - if (!$pf->validate($state)) { - $a = PEAR::raiseError('Parsing of package.xml from file "' . $file . '" failed', - 2, null, null, $pf->getValidationWarnings()); - return $a; - } + /** + * Adds a new maintainer - no checking of duplicates is performed, use + * updatemaintainer for that purpose. + */ + function addMaintainer($role, $handle, $name, $email) + { + $this->_packageInfo['maintainers'][] = + array('handle' => $handle, 'role' => $role, 'email' => $email, 'name' => $name); + $this->_isValid = false; + } - if ($this->_logger && $pf->getValidationWarnings(false)) { - foreach ($pf->getValidationWarnings() as $warning) { - $this->_logger->log(0, 'WARNING: ' . $warning['message']); - } + function updateMaintainer($role, $handle, $name, $email) + { + $found = false; + if (!isset($this->_packageInfo['maintainers']) || + !is_array($this->_packageInfo['maintainers'])) { + return $this->addMaintainer($role, $handle, $name, $email); + } + foreach ($this->_packageInfo['maintainers'] as $i => $maintainer) { + if ($maintainer['handle'] == $handle) { + $found = $i; + break; } + } + if ($found !== false) { + unset($this->_packageInfo['maintainers'][$found]); + $this->_packageInfo['maintainers'] = + array_values($this->_packageInfo['maintainers']); + } + $this->addMaintainer($role, $handle, $name, $email); + } - if (method_exists($pf, 'flattenFilelist')) { - $pf->flattenFilelist(); // for v2 + function deleteMaintainer($handle) + { + $found = false; + foreach ($this->_packageInfo['maintainers'] as $i => $maintainer) { + if ($maintainer['handle'] == $handle) { + $found = $i; + break; } + } + if ($found !== false) { + unset($this->_packageInfo['maintainers'][$found]); + $this->_packageInfo['maintainers'] = + array_values($this->_packageInfo['maintainers']); + return true; + } + return false; + } - return $pf; + function getState() + { + if (isset($this->_packageInfo['release_state'])) { + return $this->_packageInfo['release_state']; } + return false; } - /** - * Register a temporary file or directory. When the destructor is - * executed, all registered temporary files and directories are - * removed. - * - * @param string $file name of file or directory - * @return void - */ - function addTempFile($file) + function setRawState($state) { - $GLOBALS['_PEAR_Common_tempfiles'][] = $file; + $this->_packageInfo['release_state'] = $state; } - /** - * Create a PEAR_PackageFile_v* from a compresed Tar or Tgz file. - * @access public - * @param string contents of package.xml file - * @param int package state (one of PEAR_VALIDATE_* constants) - * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @using Archive_Tar to extract the files - * @using fromPackageFile() to load the package after the package.xml - * file is extracted. - */ - function &fromTgzFile($file, $state) + function setState($state) { - if (!class_exists('Archive_Tar')) { - require_once 'phar://install-pear-nozlib.phar/' . 'Archive/Tar.php'; - } + $this->_packageInfo['release_state'] = $state; + $this->_isValid = false; + } - $tar = new Archive_Tar($file); - if ($this->_debug <= 1) { - $tar->pushErrorHandling(PEAR_ERROR_RETURN); + function getDate() + { + if (isset($this->_packageInfo['release_date'])) { + return $this->_packageInfo['release_date']; } + return false; + } - $content = $tar->listContent(); - if ($this->_debug <= 1) { - $tar->popErrorHandling(); + function setDate($date) + { + $this->_packageInfo['release_date'] = $date; + $this->_isValid = false; + } + + function getLicense() + { + if (isset($this->_packageInfo['release_license'])) { + return $this->_packageInfo['release_license']; } + return false; + } - if (!is_array($content)) { - if (is_string($file) && strlen($file < 255) && - (!file_exists($file) || !@is_file($file))) { - $ret = PEAR::raiseError("could not open file \"$file\""); - return $ret; - } + function setLicense($date) + { + $this->_packageInfo['release_license'] = $date; + $this->_isValid = false; + } - $file = realpath($file); - $ret = PEAR::raiseError("Could not get contents of package \"$file\"". - '. Invalid tgz file.'); - return $ret; - } else { - if (!count($content) && !@is_file($file)) { - $ret = PEAR::raiseError("could not open file \"$file\""); - return $ret; - } + function getSummary() + { + if (isset($this->_packageInfo['summary'])) { + return $this->_packageInfo['summary']; } + return false; + } - $xml = null; - $origfile = $file; - foreach ($content as $file) { - $name = $file['filename']; - if ($name == 'package2.xml') { // allow a .tgz to distribute both versions - $xml = $name; - break; - } + function setSummary($summary) + { + $this->_packageInfo['summary'] = $summary; + $this->_isValid = false; + } - if ($name == 'package.xml') { - $xml = $name; - break; - } elseif (preg_match('/package.xml$/', $name, $match)) { - $xml = $name; - break; - } + function getDescription() + { + if (isset($this->_packageInfo['description'])) { + return $this->_packageInfo['description']; } + return false; + } - if ($this->_tmpdir) { - $tmpdir = $this->_tmpdir; - } else { - $tmpdir = System::mkTemp(array('-t', $this->_config->get('temp_dir'), '-d', 'pear')); - if ($tmpdir === false) { - $ret = PEAR::raiseError("there was a problem with getting the configured temp directory"); - return $ret; - } + function setDescription($desc) + { + $this->_packageInfo['description'] = $desc; + $this->_isValid = false; + } - PEAR_PackageFile::addTempFile($tmpdir); + function getNotes() + { + if (isset($this->_packageInfo['release_notes'])) { + return $this->_packageInfo['release_notes']; } + return false; + } - $this->_extractErrors(); - PEAR::staticPushErrorHandling(PEAR_ERROR_CALLBACK, array($this, '_extractErrors')); - if (!$xml || !$tar->extractList(array($xml), $tmpdir)) { - $extra = implode("\n", $this->_extractErrors()); - if ($extra) { - $extra = ' ' . $extra; - } + function setNotes($notes) + { + $this->_packageInfo['release_notes'] = $notes; + $this->_isValid = false; + } - PEAR::staticPopErrorHandling(); - $ret = PEAR::raiseError('could not extract the package.xml file from "' . - $origfile . '"' . $extra); - return $ret; + function getDeps() + { + if (isset($this->_packageInfo['release_deps'])) { + return $this->_packageInfo['release_deps']; } - - PEAR::staticPopErrorHandling(); - $ret = &PEAR_PackageFile::fromPackageFile("$tmpdir/$xml", $state, $origfile); - return $ret; + return false; } /** - * helper for extracting Archive_Tar errors - * @var array - * @access private + * Reset dependencies prior to adding new ones */ - var $_extractErrors = array(); + function clearDeps() + { + unset($this->_packageInfo['release_deps']); + } - /** - * helper callback for extracting Archive_Tar errors - * - * @param PEAR_Error|null $err - * @return array - * @access private - */ - function _extractErrors($err = null) + function addPhpDep($version, $rel) { - static $errors = array(); - if ($err === null) { - $e = $errors; - $errors = array(); - return $e; + $this->_isValid = false; + $this->_packageInfo['release_deps'][] = + array('type' => 'php', + 'rel' => $rel, + 'version' => $version); + } + + function addPackageDep($name, $version, $rel, $optional = 'no') + { + $this->_isValid = false; + $dep = + array('type' => 'pkg', + 'name' => $name, + 'rel' => $rel, + 'optional' => $optional); + if ($rel != 'has' && $rel != 'not') { + $dep['version'] = $version; } - $errors[] = $err->getMessage(); + $this->_packageInfo['release_deps'][] = $dep; + } + + function addExtensionDep($name, $version, $rel, $optional = 'no') + { + $this->_isValid = false; + $this->_packageInfo['release_deps'][] = + array('type' => 'ext', + 'name' => $name, + 'rel' => $rel, + 'version' => $version, + 'optional' => $optional); } /** - * Create a PEAR_PackageFile_v* from a package.xml file. - * - * @access public - * @param string $descfile name of package xml file - * @param int $state package state (one of PEAR_VALIDATE_* constants) - * @param string|false $archive name of the archive this package.xml came - * from, if any - * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @uses PEAR_PackageFile::fromXmlString to create the oject after the - * XML is loaded from the package.xml file. + * WARNING - do not use this function directly unless you know what you're doing */ - function &fromPackageFile($descfile, $state, $archive = false) + function setDeps($deps) { - $fp = false; - if (is_string($descfile) && strlen($descfile) < 255 && - ( - !file_exists($descfile) || !is_file($descfile) || !is_readable($descfile) - || (!$fp = @fopen($descfile, 'r')) - ) - ) { - $a = PEAR::raiseError("Unable to open $descfile"); - return $a; - } + $this->_packageInfo['release_deps'] = $deps; + } - // read the whole thing so we only get one cdata callback - // for each block of cdata - fclose($fp); - $data = file_get_contents($descfile); - $ret = &PEAR_PackageFile::fromXmlString($data, $state, $descfile, $archive); - return $ret; + function hasDeps() + { + return isset($this->_packageInfo['release_deps']) && + count($this->_packageInfo['release_deps']); } + function getDependencyGroup($group) + { + return false; + } - /** - * Create a PEAR_PackageFile_v* from a .tgz archive or package.xml file. - * - * This method is able to extract information about a package from a .tgz - * archive or from a XML package definition file. - * - * @access public - * @param string $info file name - * @param int $state package state (one of PEAR_VALIDATE_* constants) - * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @uses fromPackageFile() if the file appears to be XML - * @uses fromTgzFile() to load all non-XML files - */ - function &fromAnyFile($info, $state) + function isCompatible($pf) { - if (is_dir($info)) { - $dir_name = realpath($info); - if (file_exists($dir_name . '/package.xml')) { - $info = PEAR_PackageFile::fromPackageFile($dir_name . '/package.xml', $state); - } elseif (file_exists($dir_name . '/package2.xml')) { - $info = PEAR_PackageFile::fromPackageFile($dir_name . '/package2.xml', $state); - } else { - $info = PEAR::raiseError("No package definition found in '$info' directory"); - } + return false; + } + + function isSubpackageOf($p) + { + return $p->isSubpackage($this); + } + + function isSubpackage($p) + { + return false; + } - return $info; + function dependsOn($package, $channel) + { + if (strtolower($channel) != 'pear.php.net') { + return false; } - - $fp = false; - if (is_string($info) && strlen($info) < 255 && - (file_exists($info) || ($fp = @fopen($info, 'r'))) - ) { - - if ($fp) { - fclose($fp); + if (!($deps = $this->getDeps())) { + return false; + } + foreach ($deps as $dep) { + if ($dep['type'] != 'pkg') { + continue; } - - $tmp = substr($info, -4); - if ($tmp == '.xml') { - $info = &PEAR_PackageFile::fromPackageFile($info, $state); - } elseif ($tmp == '.tar' || $tmp == '.tgz') { - $info = &PEAR_PackageFile::fromTgzFile($info, $state); - } else { - $fp = fopen($info, 'r'); - $test = fread($fp, 5); - fclose($fp); - if ($test == '_packageInfo['configure_options'])) { + return $this->_packageInfo['configure_options']; } + return false; + } - $info = PEAR::raiseError("Cannot open '$info' for parsing"); - return $info; + function hasConfigureOptions() + { + return isset($this->_packageInfo['configure_options']) && + count($this->_packageInfo['configure_options']); } -} - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: v1.php,v 1.76 2009/02/24 23:45:26 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * needed for PEAR_VALIDATE_* constants - */ -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Validate.php'; -require_once 'phar://install-pear-nozlib.phar/' . 'System.php'; -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/v2.php'; -/** - * This class converts a PEAR_PackageFile_v1 object into any output format. - * - * Supported output formats include array, XML string, and a PEAR_PackageFile_v2 - * object, for converting package.xml 1.0 into package.xml 2.0 with no sweat. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_PackageFile_Generator_v1 -{ - /** - * @var PEAR_PackageFile_v1 - */ - var $_packagefile; - function PEAR_PackageFile_Generator_v1(&$packagefile) + + function addConfigureOption($name, $prompt, $default = false) { - $this->_packagefile = &$packagefile; + $o = array('name' => $name, 'prompt' => $prompt); + if ($default !== false) { + $o['default'] = $default; + } + if (!isset($this->_packageInfo['configure_options'])) { + $this->_packageInfo['configure_options'] = array(); + } + $this->_packageInfo['configure_options'][] = $o; } - function getPackagerVersion() + function clearConfigureOptions() { - return '1.8.0'; + unset($this->_packageInfo['configure_options']); } - /** - * @param PEAR_Packager - * @param bool if true, a .tgz is written, otherwise a .tar is written - * @param string|null directory in which to save the .tgz - * @return string|PEAR_Error location of package or error object - */ - function toTgz(&$packager, $compress = true, $where = null) + function getProvides() { - require_once 'phar://install-pear-nozlib.phar/' . 'Archive/Tar.php'; - if ($where === null) { - if (!($where = System::mktemp(array('-d')))) { - return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: mktemp failed'); - } - } elseif (!@System::mkDir(array('-p', $where))) { - return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: "' . $where . '" could' . - ' not be created'); + if (isset($this->_packageInfo['provides'])) { + return $this->_packageInfo['provides']; } - if (file_exists($where . DIRECTORY_SEPARATOR . 'package.xml') && - !is_file($where . DIRECTORY_SEPARATOR . 'package.xml')) { - return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: unable to save package.xml as' . - ' "' . $where . DIRECTORY_SEPARATOR . 'package.xml"'); + return false; + } + + function getProvidesExtension() + { + return false; + } + + function addFile($dir, $file, $attrs) + { + $dir = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), $dir); + if ($dir == '/' || $dir == '') { + $dir = ''; + } else { + $dir .= '/'; } - if (!$this->_packagefile->validate(PEAR_VALIDATE_PACKAGING)) { - return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: invalid package file'); + $file = $dir . $file; + $file = preg_replace('![\\/]+!', '/', $file); + $this->_packageInfo['filelist'][$file] = $attrs; + } + + function getInstallationFilelist() + { + return $this->getFilelist(); + } + + function getFilelist() + { + if (isset($this->_packageInfo['filelist'])) { + return $this->_packageInfo['filelist']; } - $pkginfo = $this->_packagefile->getArray(); - $ext = $compress ? '.tgz' : '.tar'; - $pkgver = $pkginfo['package'] . '-' . $pkginfo['version']; - $dest_package = getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext; - if (file_exists(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext) && - !is_file(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext)) { - return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: cannot create tgz file "' . - getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext . '"'); + return false; + } + + function setFileAttribute($file, $attr, $value) + { + $this->_packageInfo['filelist'][$file][$attr] = $value; + } + + function resetFilelist() + { + $this->_packageInfo['filelist'] = array(); + } + + function setInstalledAs($file, $path) + { + if ($path) { + return $this->_packageInfo['filelist'][$file]['installed_as'] = $path; } - if ($pkgfile = $this->_packagefile->getPackageFile()) { - $pkgdir = dirname(realpath($pkgfile)); - $pkgfile = basename($pkgfile); + unset($this->_packageInfo['filelist'][$file]['installed_as']); + } + + function installedFile($file, $atts) + { + if (isset($this->_packageInfo['filelist'][$file])) { + $this->_packageInfo['filelist'][$file] = + array_merge($this->_packageInfo['filelist'][$file], $atts); } else { - return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: package file object must ' . - 'be created from a real file'); + $this->_packageInfo['filelist'][$file] = $atts; } - // {{{ Create the package file list - $filelist = array(); - $i = 0; + } - foreach ($this->_packagefile->getFilelist() as $fname => $atts) { - $file = $pkgdir . DIRECTORY_SEPARATOR . $fname; - if (!file_exists($file)) { - return PEAR::raiseError("File does not exist: $fname"); - } else { - $filelist[$i++] = $file; - if (!isset($atts['md5sum'])) { - $this->_packagefile->setFileAttribute($fname, 'md5sum', md5_file($file)); - } - $packager->log(2, "Adding file $fname"); - } - } - // }}} - $packagexml = $this->toPackageFile($where, PEAR_VALIDATE_PACKAGING, 'package.xml', true); - if ($packagexml) { - $tar =& new Archive_Tar($dest_package, $compress); - $tar->setErrorHandling(PEAR_ERROR_RETURN); // XXX Don't print errors - // ----- Creates with the package.xml file - $ok = $tar->createModify(array($packagexml), '', $where); - if (PEAR::isError($ok)) { - return $ok; - } elseif (!$ok) { - return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: tarball creation failed'); - } - // ----- Add the content of the package - if (!$tar->addModify($filelist, $pkgver, $pkgdir)) { - return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: tarball creation failed'); - } - return $dest_package; + function getChangelog() + { + if (isset($this->_packageInfo['changelog'])) { + return $this->_packageInfo['changelog']; } + return false; + } + + function getPackagexmlVersion() + { + return '1.0'; } /** - * @param string|null directory to place the package.xml in, or null for a temporary dir - * @param int one of the PEAR_VALIDATE_* constants - * @param string name of the generated file - * @param bool if true, then no analysis will be performed on role="php" files - * @return string|PEAR_Error path to the created file on success + * Wrapper to {@link PEAR_ErrorStack::getErrors()} + * @param boolean determines whether to purge the error stack after retrieving + * @return array */ - function toPackageFile($where = null, $state = PEAR_VALIDATE_NORMAL, $name = 'package.xml', - $nofilechecking = false) + function getValidationWarnings($purge = true) { - if (!$this->_packagefile->validate($state, $nofilechecking)) { - return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: invalid package.xml', - null, null, null, $this->_packagefile->getValidationWarnings()); - } - if ($where === null) { - if (!($where = System::mktemp(array('-d')))) { - return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: mktemp failed'); - } - } elseif (!@System::mkDir(array('-p', $where))) { - return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: "' . $where . '" could' . - ' not be created'); - } - $newpkgfile = $where . DIRECTORY_SEPARATOR . $name; - $np = @fopen($newpkgfile, 'wb'); - if (!$np) { - return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: unable to save ' . - "$name as $newpkgfile"); - } - fwrite($np, $this->toXml($state, true)); - fclose($np); - return $newpkgfile; + return $this->_stack->getErrors($purge); } + // }}} /** - * fix both XML encoding to be UTF8, and replace standard XML entities < > " & ' - * - * @param string $string - * @return string + * Validation error. Also marks the object contents as invalid + * @param error code + * @param array error information * @access private */ - function _fixXmlEncoding($string) + function _validateError($code, $params = array()) { - if (version_compare(phpversion(), '5.0.0', 'lt')) { - $string = utf8_encode($string); - } - return strtr($string, array( - '&' => '&', - '>' => '>', - '<' => '<', - '"' => '"', - '\'' => ''' )); + $this->_stack->push($code, 'error', $params, false, false, debug_backtrace()); + $this->_isValid = false; } /** - * Return an XML document based on the package info (as returned - * by the PEAR_Common::infoFrom* methods). - * - * @return string XML data + * Validation warning. Does not mark the object contents invalid. + * @param error code + * @param array error information + * @access private */ - function toXml($state = PEAR_VALIDATE_NORMAL, $nofilevalidation = false) + function _validateWarning($code, $params = array()) { - $this->_packagefile->setDate(date('Y-m-d')); - if (!$this->_packagefile->validate($state, $nofilevalidation)) { - return false; - } - $pkginfo = $this->_packagefile->getArray(); - static $maint_map = array( - "handle" => "user", - "name" => "name", - "email" => "email", - "role" => "role", - ); - $ret = "\n"; - $ret .= "\n"; - $ret .= "\n" . -" $pkginfo[package]"; - if (isset($pkginfo['extends'])) { - $ret .= "\n$pkginfo[extends]"; - } - $ret .= - "\n ".$this->_fixXmlEncoding($pkginfo['summary'])."\n" . -" ".trim($this->_fixXmlEncoding($pkginfo['description']))."\n \n" . -" \n"; - foreach ($pkginfo['maintainers'] as $maint) { - $ret .= " \n"; - foreach ($maint_map as $idx => $elm) { - $ret .= " <$elm>"; - $ret .= $this->_fixXmlEncoding($maint[$idx]); - $ret .= "\n"; - } - $ret .= " \n"; - } - $ret .= " \n"; - $ret .= $this->_makeReleaseXml($pkginfo, false, $state); - if (isset($pkginfo['changelog']) && count($pkginfo['changelog']) > 0) { - $ret .= " \n"; - foreach ($pkginfo['changelog'] as $oldrelease) { - $ret .= $this->_makeReleaseXml($oldrelease, true); - } - $ret .= " \n"; - } - $ret .= "\n"; - return $ret; + $this->_stack->push($code, 'warning', $params, false, false, debug_backtrace()); } - // }}} - // {{{ _makeReleaseXml() + /** + * @param integer error code + * @access protected + */ + function _getErrorMessage() + { + return array( + PEAR_PACKAGEFILE_ERROR_NO_NAME => + 'Missing Package Name', + PEAR_PACKAGEFILE_ERROR_NO_SUMMARY => + 'No summary found', + PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY => + 'Summary should be on one line', + PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION => + 'Missing description', + PEAR_PACKAGEFILE_ERROR_NO_LICENSE => + 'Missing license', + PEAR_PACKAGEFILE_ERROR_NO_VERSION => + 'No release version found', + PEAR_PACKAGEFILE_ERROR_NO_STATE => + 'No release state found', + PEAR_PACKAGEFILE_ERROR_NO_DATE => + 'No release date found', + PEAR_PACKAGEFILE_ERROR_NO_NOTES => + 'No release notes found', + PEAR_PACKAGEFILE_ERROR_NO_LEAD => + 'Package must have at least one lead maintainer', + PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS => + 'No maintainers found, at least one must be defined', + PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE => + 'Maintainer %index% has no handle (user ID at channel server)', + PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE => + 'Maintainer %index% has no role', + PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME => + 'Maintainer %index% has no name', + PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL => + 'Maintainer %index% has no email', + PEAR_PACKAGEFILE_ERROR_NO_DEPNAME => + 'Dependency %index% is not a php dependency, and has no name', + PEAR_PACKAGEFILE_ERROR_NO_DEPREL => + 'Dependency %index% has no relation (rel)', + PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE => + 'Dependency %index% has no type', + PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED => + 'PHP Dependency %index% has a name attribute of "%name%" which will be' . + ' ignored!', + PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION => + 'Dependency %index% is not a rel="has" or rel="not" dependency, ' . + 'and has no version', + PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION => + 'Dependency %index% is a type="php" dependency, ' . + 'and has no version', + PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED => + 'Dependency %index% is a rel="%rel%" dependency, versioning is ignored', + PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL => + 'Dependency %index% has invalid optional value "%opt%", should be yes or no', + PEAR_PACKAGEFILE_PHP_NO_NOT => + 'Dependency %index%: php dependencies cannot use "not" rel, use "ne"' . + ' to exclude specific versions', + PEAR_PACKAGEFILE_ERROR_NO_CONFNAME => + 'Configure Option %index% has no name', + PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT => + 'Configure Option %index% has no prompt', + PEAR_PACKAGEFILE_ERROR_NO_FILES => + 'No files in section of package.xml', + PEAR_PACKAGEFILE_ERROR_NO_FILEROLE => + 'File "%file%" has no role, expecting one of "%roles%"', + PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE => + 'File "%file%" has invalid role "%role%", expecting one of "%roles%"', + PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME => + 'File "%file%" cannot start with ".", cannot package or install', + PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE => + 'Parser error: invalid PHP found in file "%file%"', + PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX => + 'in %file%: %type% "%name%" not prefixed with package name "%package%"', + PEAR_PACKAGEFILE_ERROR_INVALID_FILE => + 'Parser error: invalid PHP file "%file%"', + PEAR_PACKAGEFILE_ERROR_CHANNELVAL => + 'Channel validator error: field "%field%" - %reason%', + PEAR_PACKAGEFILE_ERROR_PHP5 => + 'Error, PHP5 token encountered in %file%, analysis should be in PHP5', + PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND => + 'File "%file%" in package.xml does not exist', + PEAR_PACKAGEFILE_ERROR_NON_ISO_CHARS => + 'Package.xml contains non-ISO-8859-1 characters, and may not validate', + ); + } /** - * Generate part of an XML description with release information. - * - * @param array $pkginfo array with release information - * @param bool $changelog whether the result will be in a changelog element - * - * @return string XML data + * Validate XML package definition file. * - * @access private + * @access public + * @return boolean */ - function _makeReleaseXml($pkginfo, $changelog = false, $state = PEAR_VALIDATE_NORMAL) + function validate($state = PEAR_VALIDATE_NORMAL, $nofilechecking = false) { - // XXX QUOTE ENTITIES IN PCDATA, OR EMBED IN CDATA BLOCKS!! - $indent = $changelog ? " " : ""; - $ret = "$indent \n"; - if (!empty($pkginfo['version'])) { - $ret .= "$indent $pkginfo[version]\n"; + if (($this->_isValid & $state) == $state) { + return true; } - if (!empty($pkginfo['release_date'])) { - $ret .= "$indent $pkginfo[release_date]\n"; + $this->_isValid = true; + $info = $this->_packageInfo; + if (empty($info['package'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_NAME); + $this->_packageName = $pn = 'unknown'; + } else { + $this->_packageName = $pn = $info['package']; } - if (!empty($pkginfo['release_license'])) { - $ret .= "$indent $pkginfo[release_license]\n"; + + if (empty($info['summary'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_SUMMARY); + } elseif (strpos(trim($info['summary']), "\n") !== false) { + $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY, + array('summary' => $info['summary'])); } - if (!empty($pkginfo['release_state'])) { - $ret .= "$indent $pkginfo[release_state]\n"; + if (empty($info['description'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION); } - if (!empty($pkginfo['release_notes'])) { - $ret .= "$indent ".trim($this->_fixXmlEncoding($pkginfo['release_notes'])) - ."\n$indent \n"; + if (empty($info['release_license'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_LICENSE); } - if (!empty($pkginfo['release_warnings'])) { - $ret .= "$indent ".$this->_fixXmlEncoding($pkginfo['release_warnings'])."\n"; + if (empty($info['version'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_VERSION); } - if (isset($pkginfo['release_deps']) && sizeof($pkginfo['release_deps']) > 0) { - $ret .= "$indent \n"; - foreach ($pkginfo['release_deps'] as $dep) { - $ret .= "$indent _validateError(PEAR_PACKAGEFILE_ERROR_NO_STATE); + } + if (empty($info['release_date'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DATE); + } + if (empty($info['release_notes'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_NOTES); + } + if (empty($info['maintainers'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS); + } else { + $haslead = false; + $i = 1; + foreach ($info['maintainers'] as $m) { + if (empty($m['handle'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE, + array('index' => $i)); } - if (isset($dep['optional'])) { - $ret .= " optional=\"$dep[optional]\""; + if (empty($m['role'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE, + array('index' => $i, 'roles' => PEAR_Common::getUserRoles())); + } elseif ($m['role'] == 'lead') { + $haslead = true; } - if (isset($dep['name'])) { - $ret .= ">$dep[name]\n"; - } else { - $ret .= "/>\n"; + if (empty($m['name'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME, + array('index' => $i)); } - } - $ret .= "$indent \n"; - } - if (isset($pkginfo['configure_options'])) { - $ret .= "$indent \n"; - foreach ($pkginfo['configure_options'] as $c) { - $ret .= "$indent _fixXmlEncoding($c['name']) . "\""; - if (isset($c['default'])) { - $ret .= " default=\"" . $this->_fixXmlEncoding($c['default']) . "\""; + if (empty($m['email'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL, + array('index' => $i)); } - $ret .= " prompt=\"" . $this->_fixXmlEncoding($c['prompt']) . "\""; - $ret .= "/>\n"; + $i++; + } + if (!$haslead) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_LEAD); } - $ret .= "$indent \n"; } - if (isset($pkginfo['provides'])) { - foreach ($pkginfo['provides'] as $key => $what) { - $ret .= "$indent _validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE, + array('index' => $i, 'types' => PEAR_Common::getDependencyTypes())); + continue; + } + if (!isset($d['rel']) || empty($d['rel'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPREL, + array('index' => $i, 'rels' => PEAR_Common::getDependencyRelations())); + continue; + } + if (!empty($d['optional'])) { + if (!in_array($d['optional'], array('yes', 'no'))) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL, + array('index' => $i, 'opt' => $d['optional'])); + } + } + if ($d['rel'] != 'has' && $d['rel'] != 'not' && empty($d['version'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION, + array('index' => $i)); + } elseif (($d['rel'] == 'has' || $d['rel'] == 'not') && !empty($d['version'])) { + $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED, + array('index' => $i, 'rel' => $d['rel'])); + } + if ($d['type'] == 'php' && !empty($d['name'])) { + $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED, + array('index' => $i, 'name' => $d['name'])); + } elseif ($d['type'] != 'php' && empty($d['name'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPNAME, + array('index' => $i)); + } + if ($d['type'] == 'php' && empty($d['version'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION, + array('index' => $i)); + } + if (($d['rel'] == 'not') && ($d['type'] == 'php')) { + $this->_validateError(PEAR_PACKAGEFILE_PHP_NO_NOT, + array('index' => $i)); + } + $i++; + } + } + if (!empty($info['configure_options'])) { + $i = 1; + foreach ($info['configure_options'] as $c) { + if (empty($c['name'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_CONFNAME, + array('index' => $i)); + } + if (empty($c['prompt'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT, + array('index' => $i)); + } + $i++; + } + } + if (empty($info['filelist'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_FILES); + $errors[] = 'no files'; + } else { + foreach ($info['filelist'] as $file => $fa) { + if (empty($fa['role'])) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_FILEROLE, + array('file' => $file, 'roles' => PEAR_Common::getFileRoles())); + continue; + } elseif (!in_array($fa['role'], PEAR_Common::getFileRoles())) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE, + array('file' => $file, 'role' => $fa['role'], 'roles' => PEAR_Common::getFileRoles())); + } + if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~', str_replace('\\', '/', $file))) { + // file contains .. parent directory or . cur directory references + $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME, + array('file' => $file)); + } + if (isset($fa['install-as']) && + preg_match('~/\.\.?(/|\\z)|^\.\.?/~', + str_replace('\\', '/', $fa['install-as']))) { + // install-as contains .. parent directory or . cur directory references + $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME, + array('file' => $file . ' [installed as ' . $fa['install-as'] . ']')); + } + if (isset($fa['baseinstalldir']) && + preg_match('~/\.\.?(/|\\z)|^\.\.?/~', + str_replace('\\', '/', $fa['baseinstalldir']))) { + // install-as contains .. parent directory or . cur directory references + $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME, + array('file' => $file . ' [baseinstalldir ' . $fa['baseinstalldir'] . ']')); } - $ret .= "/>\n"; } } - if (isset($pkginfo['filelist'])) { - $ret .= "$indent \n"; - if ($state ^ PEAR_VALIDATE_PACKAGING) { - $ret .= $this->recursiveXmlFilelist($pkginfo['filelist']); - } else { - foreach ($pkginfo['filelist'] as $file => $fa) { - if (!isset($fa['role'])) { - $fa['role'] = ''; - } - $ret .= "$indent _fixXmlEncoding($fa['baseinstalldir']) . '"'; - } - if (isset($fa['md5sum'])) { - $ret .= " md5sum=\"$fa[md5sum]\""; - } - if (isset($fa['platform'])) { - $ret .= " platform=\"$fa[platform]\""; - } - if (!empty($fa['install-as'])) { - $ret .= ' install-as="' . - $this->_fixXmlEncoding($fa['install-as']) . '"'; - } - $ret .= ' name="' . $this->_fixXmlEncoding($file) . '"'; - if (empty($fa['replacements'])) { - $ret .= "/>\n"; - } else { - $ret .= ">\n"; - foreach ($fa['replacements'] as $r) { - $ret .= "$indent $v) { - $ret .= " $k=\"" . $this->_fixXmlEncoding($v) .'"'; - } - $ret .= "/>\n"; - } - $ret .= "$indent \n"; - } - } + if (isset($this->_registry) && $this->_isValid) { + $chan = $this->_registry->getChannel('pear.php.net'); + if (PEAR::isError($chan)) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $chan->getMessage()); + return $this->_isValid = 0; + } + $validator = $chan->getValidationObject(); + $validator->setPackageFile($this); + $validator->validate($state); + $failures = $validator->getFailures(); + foreach ($failures['errors'] as $error) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $error); + } + foreach ($failures['warnings'] as $warning) { + $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $warning); + } + } + if ($this->_isValid && $state == PEAR_VALIDATE_PACKAGING && !$nofilechecking) { + if ($this->_analyzePhpFiles()) { + $this->_isValid = true; } - $ret .= "$indent \n"; } - $ret .= "$indent \n"; - return $ret; - } - - /** - * @param array - * @access protected - */ - function recursiveXmlFilelist($list) - { - $this->_dirs = array(); - foreach ($list as $file => $attributes) { - $this->_addDir($this->_dirs, explode('/', dirname($file)), $file, $attributes); + if ($this->_isValid) { + return $this->_isValid = $state; } - return $this->_formatDir($this->_dirs); + return $this->_isValid = 0; } - /** - * @param array - * @param array - * @param string|null - * @param array|null - * @access private - */ - function _addDir(&$dirs, $dir, $file = null, $attributes = null) + function _analyzePhpFiles() { - if ($dir == array() || $dir == array('.')) { - $dirs['files'][basename($file)] = $attributes; - return; - } - $curdir = array_shift($dir); - if (!isset($dirs['dirs'][$curdir])) { - $dirs['dirs'][$curdir] = array(); + if (!$this->_isValid) { + return false; } - $this->_addDir($dirs['dirs'][$curdir], $dir, $file, $attributes); - } - - /** - * @param array - * @param string - * @param string - * @access private - */ - function _formatDir($dirs, $indent = '', $curdir = '') - { - $ret = ''; - if (!count($dirs)) { - return ''; + if (!isset($this->_packageFile)) { + return false; } - if (isset($dirs['dirs'])) { - uksort($dirs['dirs'], 'strnatcasecmp'); - foreach ($dirs['dirs'] as $dir => $contents) { - $usedir = "$curdir/$dir"; - $ret .= "$indent \n"; - $ret .= $this->_formatDir($contents, "$indent ", $usedir); - $ret .= "$indent \n"; + $dir_prefix = dirname($this->_packageFile); + $common = new PEAR_Common; + $log = isset($this->_logger) ? array(&$this->_logger, 'log') : + array($common, 'log'); + $info = $this->getFilelist(); + foreach ($info as $file => $fa) { + if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $file)) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND, + array('file' => realpath($dir_prefix) . DIRECTORY_SEPARATOR . $file)); + continue; + } + if ($fa['role'] == 'php' && $dir_prefix) { + call_user_func_array($log, array(1, "Analyzing $file")); + $srcinfo = $this->_analyzeSourceCode($dir_prefix . DIRECTORY_SEPARATOR . $file); + if ($srcinfo) { + $this->_buildProvidesArray($srcinfo); + } } } - if (isset($dirs['files'])) { - uksort($dirs['files'], 'strnatcasecmp'); - foreach ($dirs['files'] as $file => $attribs) { - $ret .= $this->_formatFile($file, $attribs, $indent); + $this->_packageName = $pn = $this->getPackage(); + $pnl = strlen($pn); + if (isset($this->_packageInfo['provides'])) { + foreach ((array) $this->_packageInfo['provides'] as $key => $what) { + if (isset($what['explicit'])) { + // skip conformance checks if the provides entry is + // specified in the package.xml file + continue; + } + extract($what); + if ($type == 'class') { + if (!strncasecmp($name, $pn, $pnl)) { + continue; + } + $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX, + array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn)); + } elseif ($type == 'function') { + if (strstr($name, '::') || !strncasecmp($name, $pn, $pnl)) { + continue; + } + $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX, + array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn)); + } } } - return $ret; + return $this->_isValid; } /** - * @param string - * @param array - * @param string - * @access private + * Get the default xml generator object + * + * @return PEAR_PackageFile_Generator_v1 */ - function _formatFile($file, $attributes, $indent) + function &getDefaultGenerator() { - $ret = "$indent _fixXmlEncoding($attributes['baseinstalldir']) . '"'; - } - if (isset($attributes['md5sum'])) { - $ret .= " md5sum=\"$attributes[md5sum]\""; - } - if (isset($attributes['platform'])) { - $ret .= " platform=\"$attributes[platform]\""; - } - if (!empty($attributes['install-as'])) { - $ret .= ' install-as="' . - $this->_fixXmlEncoding($attributes['install-as']) . '"'; - } - $ret .= ' name="' . $this->_fixXmlEncoding($file) . '"'; - if (empty($attributes['replacements'])) { - $ret .= "/>\n"; - } else { - $ret .= ">\n"; - foreach ($attributes['replacements'] as $r) { - $ret .= "$indent $v) { - $ret .= " $k=\"" . $this->_fixXmlEncoding($v) .'"'; - } - $ret .= "/>\n"; - } - $ret .= "$indent \n"; + if (!class_exists('PEAR_PackageFile_Generator_v1')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/Generator/v1.php'; } - return $ret; + $a = &new PEAR_PackageFile_Generator_v1($this); + return $a; } - // {{{ _unIndent() - /** - * Unindent given string (?) - * - * @param string $str The string that has to be unindented. + * Get the contents of a file listed within the package.xml + * @param string * @return string - * @access private */ - function _unIndent($str) + function getFileContents($file) { - // remove leading newlines - $str = preg_replace('/^[\r\n]+/', '', $str); - // find whitespace at the beginning of the first line - $indent_len = strspn($str, " \t"); - $indent = substr($str, 0, $indent_len); - $data = ''; - // remove the same amount of whitespace from following lines - foreach (explode("\n", $str) as $line) { - if (substr($line, 0, $indent_len) == $indent) { - $data .= substr($line, $indent_len) . "\n"; + if ($this->_archiveFile == $this->_packageFile) { // unpacked + $dir = dirname($this->_packageFile); + $file = $dir . DIRECTORY_SEPARATOR . $file; + $file = str_replace(array('/', '\\'), + array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), $file); + if (file_exists($file) && is_readable($file)) { + return implode('', file($file)); + } + } else { // tgz + if (!class_exists('Archive_Tar')) { + require_once 'phar://install-pear-nozlib.phar/' . 'Archive/Tar.php'; + } + $tar = &new Archive_Tar($this->_archiveFile); + $tar->pushErrorHandling(PEAR_ERROR_RETURN); + if ($file != 'package.xml' && $file != 'package2.xml') { + $file = $this->getPackage() . '-' . $this->getVersion() . '/' . $file; + } + $file = $tar->extractInString($file); + $tar->popErrorHandling(); + if (PEAR::isError($file)) { + return PEAR::raiseError("Cannot locate file '$file' in archive"); } + return $file; } - return $data; } + // {{{ analyzeSourceCode() /** - * @return array + * Analyze the source code of the given PHP file + * + * @param string Filename of the PHP file + * @return mixed + * @access private */ - function dependenciesToV2() + function _analyzeSourceCode($file) { - $arr = array(); - $this->_convertDependencies2_0($arr); - return $arr['dependencies']; + if (!function_exists("token_get_all")) { + return false; + } + if (!defined('T_DOC_COMMENT')) { + define('T_DOC_COMMENT', T_COMMENT); + } + if (!defined('T_INTERFACE')) { + define('T_INTERFACE', -1); + } + if (!defined('T_IMPLEMENTS')) { + define('T_IMPLEMENTS', -1); + } + if (!$fp = @fopen($file, "r")) { + return false; + } + fclose($fp); + $contents = file_get_contents($file); + $tokens = token_get_all($contents); +/* + for ($i = 0; $i < sizeof($tokens); $i++) { + @list($token, $data) = $tokens[$i]; + if (is_string($token)) { + var_dump($token); + } else { + print token_name($token) . ' '; + var_dump(rtrim($data)); + } + } +*/ + $look_for = 0; + $paren_level = 0; + $bracket_level = 0; + $brace_level = 0; + $lastphpdoc = ''; + $current_class = ''; + $current_interface = ''; + $current_class_level = -1; + $current_function = ''; + $current_function_level = -1; + $declared_classes = array(); + $declared_interfaces = array(); + $declared_functions = array(); + $declared_methods = array(); + $used_classes = array(); + $used_functions = array(); + $extends = array(); + $implements = array(); + $nodeps = array(); + $inquote = false; + $interface = false; + for ($i = 0; $i < sizeof($tokens); $i++) { + if (is_array($tokens[$i])) { + list($token, $data) = $tokens[$i]; + } else { + $token = $tokens[$i]; + $data = ''; + } + if ($inquote) { + if ($token != '"' && $token != T_END_HEREDOC) { + continue; + } else { + $inquote = false; + continue; + } + } + switch ($token) { + case T_WHITESPACE : + continue; + case ';': + if ($interface) { + $current_function = ''; + $current_function_level = -1; + } + break; + case '"': + case T_START_HEREDOC: + $inquote = true; + break; + case T_CURLY_OPEN: + case T_DOLLAR_OPEN_CURLY_BRACES: + case '{': $brace_level++; continue 2; + case '}': + $brace_level--; + if ($current_class_level == $brace_level) { + $current_class = ''; + $current_class_level = -1; + } + if ($current_function_level == $brace_level) { + $current_function = ''; + $current_function_level = -1; + } + continue 2; + case '[': $bracket_level++; continue 2; + case ']': $bracket_level--; continue 2; + case '(': $paren_level++; continue 2; + case ')': $paren_level--; continue 2; + case T_INTERFACE: + $interface = true; + case T_CLASS: + if (($current_class_level != -1) || ($current_function_level != -1)) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE, + array('file' => $file)); + return false; + } + case T_FUNCTION: + case T_NEW: + case T_EXTENDS: + case T_IMPLEMENTS: + $look_for = $token; + continue 2; + case T_STRING: + if (version_compare(zend_version(), '2.0', '<')) { + if (in_array(strtolower($data), + array('public', 'private', 'protected', 'abstract', + 'interface', 'implements', 'throw') + )) { + $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_PHP5, + array($file)); + } + } + if ($look_for == T_CLASS) { + $current_class = $data; + $current_class_level = $brace_level; + $declared_classes[] = $current_class; + } elseif ($look_for == T_INTERFACE) { + $current_interface = $data; + $current_class_level = $brace_level; + $declared_interfaces[] = $current_interface; + } elseif ($look_for == T_IMPLEMENTS) { + $implements[$current_class] = $data; + } elseif ($look_for == T_EXTENDS) { + $extends[$current_class] = $data; + } elseif ($look_for == T_FUNCTION) { + if ($current_class) { + $current_function = "$current_class::$data"; + $declared_methods[$current_class][] = $data; + } elseif ($current_interface) { + $current_function = "$current_interface::$data"; + $declared_methods[$current_interface][] = $data; + } else { + $current_function = $data; + $declared_functions[] = $current_function; + } + $current_function_level = $brace_level; + $m = array(); + } elseif ($look_for == T_NEW) { + $used_classes[$data] = true; + } + $look_for = 0; + continue 2; + case T_VARIABLE: + $look_for = 0; + continue 2; + case T_DOC_COMMENT: + case T_COMMENT: + if (preg_match('!^/\*\*\s!', $data)) { + $lastphpdoc = $data; + if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m)) { + $nodeps = array_merge($nodeps, $m[1]); + } + } + continue 2; + case T_DOUBLE_COLON: + if (!($tokens[$i - 1][0] == T_WHITESPACE || $tokens[$i - 1][0] == T_STRING)) { + $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE, + array('file' => $file)); + return false; + } + $class = $tokens[$i - 1][1]; + if (strtolower($class) != 'parent') { + $used_classes[$class] = true; + } + continue 2; + } + } + return array( + "source_file" => $file, + "declared_classes" => $declared_classes, + "declared_interfaces" => $declared_interfaces, + "declared_methods" => $declared_methods, + "declared_functions" => $declared_functions, + "used_classes" => array_diff(array_keys($used_classes), $nodeps), + "inheritance" => $extends, + "implements" => $implements, + ); } /** - * Convert a package.xml version 1.0 into version 2.0 + * Build a "provides" array from data returned by + * analyzeSourceCode(). The format of the built array is like + * this: + * + * array( + * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'), + * ... + * ) + * + * + * @param array $srcinfo array with information about a source file + * as returned by the analyzeSourceCode() method. + * + * @return void + * + * @access private * - * Note that this does a basic conversion, to allow more advanced - * features like bundles and multiple releases - * @param string the classname to instantiate and return. This must be - * PEAR_PackageFile_v2 or a descendant - * @param boolean if true, only valid, deterministic package.xml 1.0 as defined by the - * strictest parameters will be converted - * @return PEAR_PackageFile_v2|PEAR_Error */ - function &toV2($class = 'PEAR_PackageFile_v2', $strict = false) + function _buildProvidesArray($srcinfo) { - if ($strict) { - if (!$this->_packagefile->validate()) { - $a = PEAR::raiseError('invalid package.xml version 1.0 cannot be converted' . - ' to version 2.0', null, null, null, - $this->_packagefile->getValidationWarnings(true)); - return $a; - } + if (!$this->_isValid) { + return false; } - - $arr = array( - 'attribs' => array( - 'version' => '2.0', - 'xmlns' => 'http://pear.php.net/dtd/package-2.0', - 'xmlns:tasks' => 'http://pear.php.net/dtd/tasks-1.0', - 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', - 'xsi:schemaLocation' => "http://pear.php.net/dtd/tasks-1.0\n" . -"http://pear.php.net/dtd/tasks-1.0.xsd\n" . -"http://pear.php.net/dtd/package-2.0\n" . -'http://pear.php.net/dtd/package-2.0.xsd', - ), - 'name' => $this->_packagefile->getPackage(), - 'channel' => 'pear.php.net', - ); - $arr['summary'] = $this->_packagefile->getSummary(); - $arr['description'] = $this->_packagefile->getDescription(); - $maintainers = $this->_packagefile->getMaintainers(); - foreach ($maintainers as $maintainer) { - if ($maintainer['role'] != 'lead') { + $file = basename($srcinfo['source_file']); + $pn = $this->getPackage(); + $pnl = strlen($pn); + foreach ($srcinfo['declared_classes'] as $class) { + $key = "class;$class"; + if (isset($this->_packageInfo['provides'][$key])) { continue; } - $new = array( - 'name' => $maintainer['name'], - 'user' => $maintainer['handle'], - 'email' => $maintainer['email'], - 'active' => 'yes', - ); - $arr['lead'][] = $new; - } - - if (!isset($arr['lead'])) { // some people... you know? - $arr['lead'] = array( - 'name' => 'unknown', - 'user' => 'unknown', - 'email' => 'noleadmaintainer@example.com', - 'active' => 'no', - ); + $this->_packageInfo['provides'][$key] = + array('file'=> $file, 'type' => 'class', 'name' => $class); + if (isset($srcinfo['inheritance'][$class])) { + $this->_packageInfo['provides'][$key]['extends'] = + $srcinfo['inheritance'][$class]; + } } - - if (count($arr['lead']) == 1) { - $arr['lead'] = $arr['lead'][0]; + foreach ($srcinfo['declared_methods'] as $class => $methods) { + foreach ($methods as $method) { + $function = "$class::$method"; + $key = "function;$function"; + if ($method{0} == '_' || !strcasecmp($method, $class) || + isset($this->_packageInfo['provides'][$key])) { + continue; + } + $this->_packageInfo['provides'][$key] = + array('file'=> $file, 'type' => 'function', 'name' => $function); + } } - foreach ($maintainers as $maintainer) { - if ($maintainer['role'] == 'lead') { + foreach ($srcinfo['declared_functions'] as $function) { + $key = "function;$function"; + if ($function{0} == '_' || isset($this->_packageInfo['provides'][$key])) { continue; } - $new = array( - 'name' => $maintainer['name'], - 'user' => $maintainer['handle'], - 'email' => $maintainer['email'], - 'active' => 'yes', - ); - $arr[$maintainer['role']][] = $new; + if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) { + $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\""; + } + $this->_packageInfo['provides'][$key] = + array('file'=> $file, 'type' => 'function', 'name' => $function); } + } - if (isset($arr['developer']) && count($arr['developer']) == 1) { - $arr['developer'] = $arr['developer'][0]; - } + // }}} +} +?> + + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: v2.php 276383 2009-02-24 23:39:37Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a1 + */ +/** + * For error handling + */ +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/ErrorStack.php'; +/** + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a1 + */ +class PEAR_PackageFile_v2 +{ - if (isset($arr['contributor']) && count($arr['contributor']) == 1) { - $arr['contributor'] = $arr['contributor'][0]; - } + /** + * Parsed package information + * @var array + * @access private + */ + var $_packageInfo = array(); - if (isset($arr['helper']) && count($arr['helper']) == 1) { - $arr['helper'] = $arr['helper'][0]; - } + /** + * path to package .tgz or false if this is a local/extracted package.xml + * @var string|false + * @access private + */ + var $_archiveFile; - $arr['date'] = $this->_packagefile->getDate(); - $arr['version'] = - array( - 'release' => $this->_packagefile->getVersion(), - 'api' => $this->_packagefile->getVersion(), - ); - $arr['stability'] = - array( - 'release' => $this->_packagefile->getState(), - 'api' => $this->_packagefile->getState(), - ); - $licensemap = - array( - 'php' => 'http://www.php.net/license', - 'php license' => 'http://www.php.net/license', - 'lgpl' => 'http://www.gnu.org/copyleft/lesser.html', - 'bsd' => 'http://www.opensource.org/licenses/bsd-license.php', - 'bsd style' => 'http://www.opensource.org/licenses/bsd-license.php', - 'bsd-style' => 'http://www.opensource.org/licenses/bsd-license.php', - 'mit' => 'http://www.opensource.org/licenses/mit-license.php', - 'gpl' => 'http://www.gnu.org/copyleft/gpl.html', - 'apache' => 'http://www.opensource.org/licenses/apache2.0.php' - ); + /** + * path to package .xml or false if this is an abstract parsed-from-string xml + * @var string|false + * @access private + */ + var $_packageFile; - if (isset($licensemap[strtolower($this->_packagefile->getLicense())])) { - $arr['license'] = array( - 'attribs' => array('uri' => - $licensemap[strtolower($this->_packagefile->getLicense())]), - '_content' => $this->_packagefile->getLicense() - ); - } else { - // don't use bogus uri - $arr['license'] = $this->_packagefile->getLicense(); - } + /** + * This is used by file analysis routines to log progress information + * @var PEAR_Common + * @access protected + */ + var $_logger; - $arr['notes'] = $this->_packagefile->getNotes(); - $temp = array(); - $arr['contents'] = $this->_convertFilelist2_0($temp); - $this->_convertDependencies2_0($arr); - $release = ($this->_packagefile->getConfigureOptions() || $this->_isExtension) ? - 'extsrcrelease' : 'phprelease'; - if ($release == 'extsrcrelease') { - $arr['channel'] = 'pecl.php.net'; - $arr['providesextension'] = $arr['name']; // assumption - } + /** + * This is set to the highest validation level that has been validated + * + * If the package.xml is invalid or unknown, this is set to 0. If + * normal validation has occurred, this is set to PEAR_VALIDATE_NORMAL. If + * downloading/installation validation has occurred it is set to PEAR_VALIDATE_DOWNLOADING + * or INSTALLING, and so on up to PEAR_VALIDATE_PACKAGING. This allows validation + * "caching" to occur, which is particularly important for package validation, so + * that PHP files are not validated twice + * @var int + * @access private + */ + var $_isValid = 0; - $arr[$release] = array(); - if ($this->_packagefile->getConfigureOptions()) { - $arr[$release]['configureoption'] = $this->_packagefile->getConfigureOptions(); - foreach ($arr[$release]['configureoption'] as $i => $opt) { - $arr[$release]['configureoption'][$i] = array('attribs' => $opt); - } - if (count($arr[$release]['configureoption']) == 1) { - $arr[$release]['configureoption'] = $arr[$release]['configureoption'][0]; - } - } + /** + * True if the filelist has been validated + * @param bool + */ + var $_filesValid = false; - $this->_convertRelease2_0($arr[$release], $temp); - if ($release == 'extsrcrelease' && count($arr[$release]) > 1) { - // multiple extsrcrelease tags added in PEAR 1.4.1 - $arr['dependencies']['required']['pearinstaller']['min'] = '1.4.1'; - } + /** + * @var PEAR_Registry + * @access protected + */ + var $_registry; - if ($cl = $this->_packagefile->getChangelog()) { - foreach ($cl as $release) { - $rel = array(); - $rel['version'] = - array( - 'release' => $release['version'], - 'api' => $release['version'], - ); - if (!isset($release['release_state'])) { - $release['release_state'] = 'stable'; - } + /** + * @var PEAR_Config + * @access protected + */ + var $_config; - $rel['stability'] = - array( - 'release' => $release['release_state'], - 'api' => $release['release_state'], - ); - if (isset($release['release_date'])) { - $rel['date'] = $release['release_date']; - } else { - $rel['date'] = date('Y-m-d'); - } + /** + * Optional Dependency group requested for installation + * @var string + * @access private + */ + var $_requestedGroup = false; - if (isset($release['release_license'])) { - if (isset($licensemap[strtolower($release['release_license'])])) { - $uri = $licensemap[strtolower($release['release_license'])]; - } else { - $uri = 'http://www.example.com'; - } - $rel['license'] = array( - 'attribs' => array('uri' => $uri), - '_content' => $release['release_license'] - ); - } else { - $rel['license'] = $arr['license']; - } + /** + * @var PEAR_ErrorStack + * @access protected + */ + var $_stack; - if (!isset($release['release_notes'])) { - $release['release_notes'] = 'no release notes'; - } + /** + * Namespace prefix used for tasks in this package.xml - use tasks: whenever possible + */ + var $_tasksNs; - $rel['notes'] = $release['release_notes']; - $arr['changelog']['release'][] = $rel; - } - } + /** + * Determines whether this packagefile was initialized only with partial package info + * + * If this package file was constructed via parsing REST, it will only contain + * + * - package name + * - channel name + * - dependencies + * @var boolean + * @access private + */ + var $_incomplete = true; - $ret = new $class; - $ret->setConfig($this->_packagefile->_config); - if (isset($this->_packagefile->_logger) && is_object($this->_packagefile->_logger)) { - $ret->setLogger($this->_packagefile->_logger); - } + /** + * @var PEAR_PackageFile_v2_Validator + */ + var $_v2Validator; - $ret->fromArray($arr); - return $ret; + /** + * The constructor merely sets up the private error stack + */ + function PEAR_PackageFile_v2() + { + $this->_stack = new PEAR_ErrorStack('PEAR_PackageFile_v2', false, null); + $this->_isValid = false; } /** - * @param array - * @param bool - * @access private + * To make unit-testing easier + * @param PEAR_Frontend_* + * @param array options + * @param PEAR_Config + * @return PEAR_Downloader + * @access protected */ - function _convertDependencies2_0(&$release, $internal = false) + function &getPEARDownloader(&$i, $o, &$c) { - $peardep = array('pearinstaller' => - array('min' => '1.4.0b1')); // this is a lot safer - $required = $optional = array(); - $release['dependencies'] = array('required' => array()); - if ($this->_packagefile->hasDeps()) { - foreach ($this->_packagefile->getDeps() as $dep) { - if (!isset($dep['optional']) || $dep['optional'] == 'no') { - $required[] = $dep; - } else { - $optional[] = $dep; - } - } - foreach (array('required', 'optional') as $arr) { - $deps = array(); - foreach ($$arr as $dep) { - // organize deps by dependency type and name - if (!isset($deps[$dep['type']])) { - $deps[$dep['type']] = array(); - } - if (isset($dep['name'])) { - $deps[$dep['type']][$dep['name']][] = $dep; - } else { - $deps[$dep['type']][] = $dep; - } - } - do { - if (isset($deps['php'])) { - $php = array(); - if (count($deps['php']) > 1) { - $php = $this->_processPhpDeps($deps['php']); - } else { - if (!isset($deps['php'][0])) { - list($key, $blah) = each ($deps['php']); // stupid buggy versions - $deps['php'] = array($blah[0]); - } - $php = $this->_processDep($deps['php'][0]); - if (!$php) { - break; // poor mans throw - } - } - $release['dependencies'][$arr]['php'] = $php; - } - } while (false); - do { - if (isset($deps['pkg'])) { - $pkg = array(); - $pkg = $this->_processMultipleDepsName($deps['pkg']); - if (!$pkg) { - break; // poor mans throw - } - $release['dependencies'][$arr]['package'] = $pkg; - } - } while (false); - do { - if (isset($deps['ext'])) { - $pkg = array(); - $pkg = $this->_processMultipleDepsName($deps['ext']); - $release['dependencies'][$arr]['extension'] = $pkg; - } - } while (false); - // skip sapi - it's not supported so nobody will have used it - // skip os - it's not supported in 1.0 - } - } - if (isset($release['dependencies']['required'])) { - $release['dependencies']['required'] = - array_merge($peardep, $release['dependencies']['required']); - } else { - $release['dependencies']['required'] = $peardep; - } - if (!isset($release['dependencies']['required']['php'])) { - $release['dependencies']['required']['php'] = - array('min' => '4.0.0'); - } - $order = array(); - $bewm = $release['dependencies']['required']; - $order['php'] = $bewm['php']; - $order['pearinstaller'] = $bewm['pearinstaller']; - isset($bewm['package']) ? $order['package'] = $bewm['package'] :0; - isset($bewm['extension']) ? $order['extension'] = $bewm['extension'] :0; - $release['dependencies']['required'] = $order; + $z = &new PEAR_Downloader($i, $o, $c); + return $z; } /** - * @param array - * @access private + * To make unit-testing easier + * @param PEAR_Config + * @param array options + * @param array package name as returned from {@link PEAR_Registry::parsePackageName()} + * @param int PEAR_VALIDATE_* constant + * @return PEAR_Dependency2 + * @access protected */ - function _convertFilelist2_0(&$package) + function &getPEARDependency2(&$c, $o, $p, $s = PEAR_VALIDATE_INSTALLING) { - $ret = array('dir' => - array( - 'attribs' => array('name' => '/'), - 'file' => array() - ) - ); - $package['platform'] = - $package['install-as'] = array(); - $this->_isExtension = false; - foreach ($this->_packagefile->getFilelist() as $name => $file) { - $file['name'] = $name; - if (isset($file['role']) && $file['role'] == 'src') { - $this->_isExtension = true; - } - if (isset($file['replacements'])) { - $repl = $file['replacements']; - unset($file['replacements']); - } else { - unset($repl); - } - if (isset($file['install-as'])) { - $package['install-as'][$name] = $file['install-as']; - unset($file['install-as']); - } - if (isset($file['platform'])) { - $package['platform'][$name] = $file['platform']; - unset($file['platform']); - } - $file = array('attribs' => $file); - if (isset($repl)) { - foreach ($repl as $replace ) { - $file['tasks:replace'][] = array('attribs' => $replace); - } - if (count($repl) == 1) { - $file['tasks:replace'] = $file['tasks:replace'][0]; - } - } - $ret['dir']['file'][] = $file; + if (!class_exists('PEAR_Dependency2')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Dependency2.php'; } - return $ret; + $z = &new PEAR_Dependency2($c, $o, $p, $s); + return $z; + } + + function getInstalledBinary() + { + return isset($this->_packageInfo['#binarypackage']) ? $this->_packageInfo['#binarypackage'] : + false; } /** - * Post-process special files with install-as/platform attributes and - * make the release tag. - * - * This complex method follows this work-flow to create the release tags: - * - *
-     * - if any install-as/platform exist, create a generic release and fill it with
-     *   o  tags for 
-     *   o  tags for 
-     *   o  tags for 
-     *   o  tags for 
-     * - create a release for each platform encountered and fill with
-     *   o  tags for 
-     *   o  tags for 
-     *   o  tags for 
-     *   o  tags for 
-     *   o  tags for 
-     *   o  tags for 
-     *   o  tags for 
-     * 
- * - * It does this by accessing the $package parameter, which contains an array with - * indices: - * - * - platform: mapping of file => OS the file should be installed on - * - install-as: mapping of file => installed name - * - osmap: mapping of OS => list of files that should be installed - * on that OS - * - notosmap: mapping of OS => list of files that should not be - * installed on that OS - * - * @param array - * @param array - * @access private + * Installation of source package has failed, attempt to download and install the + * binary version of this package. + * @param PEAR_Installer + * @return array|false */ - function _convertRelease2_0(&$release, $package) + function installBinary(&$installer) { - //- if any install-as/platform exist, create a generic release and fill it with - if (count($package['platform']) || count($package['install-as'])) { - $generic = array(); - $genericIgnore = array(); - foreach ($package['install-as'] as $file => $as) { - //o tags for - if (!isset($package['platform'][$file])) { - $generic[] = $file; - continue; - } - //o tags for - if (isset($package['platform'][$file]) && - $package['platform'][$file]{0} == '!') { - $generic[] = $file; - continue; - } - //o tags for - if (isset($package['platform'][$file]) && - $package['platform'][$file]{0} != '!') { - $genericIgnore[] = $file; - continue; - } - } - foreach ($package['platform'] as $file => $platform) { - if (isset($package['install-as'][$file])) { - continue; - } - if ($platform{0} != '!') { - //o tags for - $genericIgnore[] = $file; - } + if (!OS_WINDOWS) { + $a = false; + return $a; + } + if ($this->getPackageType() == 'extsrc' || $this->getPackageType() == 'zendextsrc') { + $releasetype = $this->getPackageType() . 'release'; + if (!is_array($installer->getInstallPackages())) { + $a = false; + return $a; } - if (count($package['platform'])) { - $oses = $notplatform = $platform = array(); - foreach ($package['platform'] as $file => $os) { - // get a list of oses - if ($os{0} == '!') { - if (isset($oses[substr($os, 1)])) { - continue; - } - $oses[substr($os, 1)] = count($oses); - } else { - if (isset($oses[$os])) { - continue; - } - $oses[$os] = count($oses); - } - } - //- create a release for each platform encountered and fill with - foreach ($oses as $os => $releaseNum) { - $release[$releaseNum]['installconditions']['os']['name'] = $os; - $release[$releaseNum]['filelist'] = array('install' => array(), - 'ignore' => array()); - foreach ($package['install-as'] as $file => $as) { - //o tags for - if (!isset($package['platform'][$file])) { - $release[$releaseNum]['filelist']['install'][] = - array( - 'attribs' => array( - 'name' => $file, - 'as' => $as, - ), - ); - continue; - } - //o tags for - // - if (isset($package['platform'][$file]) && - $package['platform'][$file] == $os) { - $release[$releaseNum]['filelist']['install'][] = - array( - 'attribs' => array( - 'name' => $file, - 'as' => $as, - ), - ); - continue; - } - //o tags for - // - if (isset($package['platform'][$file]) && - $package['platform'][$file] != "!$os" && - $package['platform'][$file]{0} == '!') { - $release[$releaseNum]['filelist']['install'][] = - array( - 'attribs' => array( - 'name' => $file, - 'as' => $as, - ), - ); - continue; - } - //o tags for - // - if (isset($package['platform'][$file]) && - $package['platform'][$file] == "!$os") { - $release[$releaseNum]['filelist']['ignore'][] = - array( - 'attribs' => array( - 'name' => $file, - ), - ); - continue; - } - //o tags for - // - if (isset($package['platform'][$file]) && - $package['platform'][$file]{0} != '!' && - $package['platform'][$file] != $os) { - $release[$releaseNum]['filelist']['ignore'][] = - array( - 'attribs' => array( - 'name' => $file, - ), - ); - continue; - } - } - foreach ($package['platform'] as $file => $platform) { - if (isset($package['install-as'][$file])) { - continue; - } - //o tags for - if ($platform == "!$os") { - $release[$releaseNum]['filelist']['ignore'][] = - array( - 'attribs' => array( - 'name' => $file, - ), - ); - continue; - } - //o tags for - if ($platform{0} != '!' && $platform != $os) { - $release[$releaseNum]['filelist']['ignore'][] = - array( - 'attribs' => array( - 'name' => $file, - ), - ); - } - } - if (!count($release[$releaseNum]['filelist']['install'])) { - unset($release[$releaseNum]['filelist']['install']); - } - if (!count($release[$releaseNum]['filelist']['ignore'])) { - unset($release[$releaseNum]['filelist']['ignore']); - } - } - if (count($generic) || count($genericIgnore)) { - $release[count($oses)] = array(); - if (count($generic)) { - foreach ($generic as $file) { - if (isset($package['install-as'][$file])) { - $installas = $package['install-as'][$file]; - } else { - $installas = $file; - } - $release[count($oses)]['filelist']['install'][] = - array( - 'attribs' => array( - 'name' => $file, - 'as' => $installas, - ) - ); - } - } - if (count($genericIgnore)) { - foreach ($genericIgnore as $file) { - $release[count($oses)]['filelist']['ignore'][] = - array( - 'attribs' => array( - 'name' => $file, - ) - ); - } + foreach ($installer->getInstallPackages() as $p) { + if ($p->isExtension($this->_packageInfo['providesextension'])) { + if ($p->getPackageType() != 'extsrc' && $p->getPackageType() != 'zendextsrc') { + $a = false; + return $a; // the user probably downloaded it separately } } - // cleanup - foreach ($release as $i => $rel) { - if (isset($rel['filelist']['install']) && - count($rel['filelist']['install']) == 1) { - $release[$i]['filelist']['install'] = - $release[$i]['filelist']['install'][0]; - } - if (isset($rel['filelist']['ignore']) && - count($rel['filelist']['ignore']) == 1) { - $release[$i]['filelist']['ignore'] = - $release[$i]['filelist']['ignore'][0]; - } + } + if (isset($this->_packageInfo[$releasetype]['binarypackage'])) { + $installer->log(0, 'Attempting to download binary version of extension "' . + $this->_packageInfo['providesextension'] . '"'); + $params = $this->_packageInfo[$releasetype]['binarypackage']; + if (!is_array($params) || !isset($params[0])) { + $params = array($params); } - if (count($release) == 1) { - $release = $release[0]; + if (isset($this->_packageInfo['channel'])) { + foreach ($params as $i => $param) { + $params[$i] = array('channel' => $this->_packageInfo['channel'], + 'package' => $param, 'version' => $this->getVersion()); + } } - } else { - // no platform atts, but some install-as atts - foreach ($package['install-as'] as $file => $value) { - $release['filelist']['install'][] = - array( - 'attribs' => array( - 'name' => $file, - 'as' => $value - ) - ); + $dl = &$this->getPEARDownloader($installer->ui, $installer->getOptions(), + $installer->config); + $verbose = $dl->config->get('verbose'); + $dl->config->set('verbose', -1); + foreach ($params as $param) { + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $ret = $dl->download(array($param)); + PEAR::popErrorHandling(); + if (is_array($ret) && count($ret)) { + break; + } } - if (count($release['filelist']['install']) == 1) { - $release['filelist']['install'] = $release['filelist']['install'][0]; + $dl->config->set('verbose', $verbose); + if (is_array($ret)) { + if (count($ret) == 1) { + $pf = $ret[0]->getPackageFile(); + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $err = $installer->install($ret[0]); + PEAR::popErrorHandling(); + if (is_array($err)) { + $this->_packageInfo['#binarypackage'] = $ret[0]->getPackage(); + // "install" self, so all dependencies will work transparently + $this->_registry->addPackage2($this); + $installer->log(0, 'Download and install of binary extension "' . + $this->_registry->parsedPackageNameToString( + array('channel' => $pf->getChannel(), + 'package' => $pf->getPackage()), true) . '" successful'); + $a = array($ret[0], $err); + return $a; + } + $installer->log(0, 'Download and install of binary extension "' . + $this->_registry->parsedPackageNameToString( + array('channel' => $pf->getChannel(), + 'package' => $pf->getPackage()), true) . '" failed'); + } } } } + $a = false; + return $a; } /** - * @param array - * @return array - * @access private + * @return string|false Extension name */ - function _processDep($dep) + function getProvidesExtension() { - if ($dep['type'] == 'php') { - if ($dep['rel'] == 'has') { - // come on - everyone has php! - return false; - } - } - $php = array(); - if ($dep['type'] != 'php') { - $php['name'] = $dep['name']; - if ($dep['type'] == 'pkg') { - $php['channel'] = 'pear.php.net'; + if (in_array($this->getPackageType(), + array('extsrc', 'extbin', 'zendextsrc', 'zendextbin'))) { + if (isset($this->_packageInfo['providesextension'])) { + return $this->_packageInfo['providesextension']; } } - switch ($dep['rel']) { - case 'gt' : - $php['min'] = $dep['version']; - $php['exclude'] = $dep['version']; - break; - case 'ge' : - if (!isset($dep['version'])) { - if ($dep['type'] == 'php') { - if (isset($dep['name'])) { - $dep['version'] = $dep['name']; - } - } - } - $php['min'] = $dep['version']; - break; - case 'lt' : - $php['max'] = $dep['version']; - $php['exclude'] = $dep['version']; - break; - case 'le' : - $php['max'] = $dep['version']; - break; - case 'eq' : - $php['min'] = $dep['version']; - $php['max'] = $dep['version']; - break; - case 'ne' : - $php['exclude'] = $dep['version']; - break; - case 'not' : - $php['conflicts'] = 'yes'; - break; + return false; + } + + /** + * @param string Extension name + * @return bool + */ + function isExtension($extension) + { + if (in_array($this->getPackageType(), + array('extsrc', 'extbin', 'zendextsrc', 'zendextbin'))) { + return $this->_packageInfo['providesextension'] == $extension; } - return $php; + return false; } /** - * @param array - * @return array + * Tests whether every part of the package.xml 1.0 is represented in + * this package.xml 2.0 + * @param PEAR_PackageFile_v1 + * @return bool */ - function _processPhpDeps($deps) + function isEquivalent($pf1) { - $test = array(); - foreach ($deps as $dep) { - $test[] = $this->_processDep($dep); + if (!$pf1) { + return true; } - $min = array(); - $max = array(); - foreach ($test as $dep) { - if (!$dep) { - continue; - } - if (isset($dep['min'])) { - $min[$dep['min']] = count($min); - } - if (isset($dep['max'])) { - $max[$dep['max']] = count($max); - } + if ($this->getPackageType() == 'bundle') { + return false; } - if (count($min) > 0) { - uksort($min, 'version_compare'); + $this->_stack->getErrors(true); + if (!$pf1->validate(PEAR_VALIDATE_NORMAL)) { + return false; } - if (count($max) > 0) { - uksort($max, 'version_compare'); + $pass = true; + if ($pf1->getPackage() != $this->getPackage()) { + $this->_differentPackage($pf1->getPackage()); + $pass = false; } - if (count($min)) { - // get the highest minimum - $min = array_pop($a = array_flip($min)); - } else { - $min = false; + if ($pf1->getVersion() != $this->getVersion()) { + $this->_differentVersion($pf1->getVersion()); + $pass = false; } - if (count($max)) { - // get the lowest maximum - $max = array_shift($a = array_flip($max)); - } else { - $max = false; + if (trim($pf1->getSummary()) != $this->getSummary()) { + $this->_differentSummary($pf1->getSummary()); + $pass = false; } - if ($min) { - $php['min'] = $min; + if (preg_replace('/\s+/', '', $pf1->getDescription()) != + preg_replace('/\s+/', '', $this->getDescription())) { + $this->_differentDescription($pf1->getDescription()); + $pass = false; } - if ($max) { - $php['max'] = $max; + if ($pf1->getState() != $this->getState()) { + $this->_differentState($pf1->getState()); + $pass = false; } - $exclude = array(); - foreach ($test as $dep) { - if (!isset($dep['exclude'])) { - continue; + if (!strstr(preg_replace('/\s+/', '', $this->getNotes()), + preg_replace('/\s+/', '', $pf1->getNotes()))) { + $this->_differentNotes($pf1->getNotes()); + $pass = false; + } + $mymaintainers = $this->getMaintainers(); + $yourmaintainers = $pf1->getMaintainers(); + for ($i1 = 0; $i1 < count($yourmaintainers); $i1++) { + $reset = false; + for ($i2 = 0; $i2 < count($mymaintainers); $i2++) { + if ($mymaintainers[$i2]['handle'] == $yourmaintainers[$i1]['handle']) { + if ($mymaintainers[$i2]['role'] != $yourmaintainers[$i1]['role']) { + $this->_differentRole($mymaintainers[$i2]['handle'], + $yourmaintainers[$i1]['role'], $mymaintainers[$i2]['role']); + $pass = false; + } + if ($mymaintainers[$i2]['email'] != $yourmaintainers[$i1]['email']) { + $this->_differentEmail($mymaintainers[$i2]['handle'], + $yourmaintainers[$i1]['email'], $mymaintainers[$i2]['email']); + $pass = false; + } + if ($mymaintainers[$i2]['name'] != $yourmaintainers[$i1]['name']) { + $this->_differentName($mymaintainers[$i2]['handle'], + $yourmaintainers[$i1]['name'], $mymaintainers[$i2]['name']); + $pass = false; + } + unset($mymaintainers[$i2]); + $mymaintainers = array_values($mymaintainers); + unset($yourmaintainers[$i1]); + $yourmaintainers = array_values($yourmaintainers); + $reset = true; + break; + } + } + if ($reset) { + $i1 = -1; } - $exclude[] = $dep['exclude']; } - if (count($exclude)) { - $php['exclude'] = $exclude; + $this->_unmatchedMaintainers($mymaintainers, $yourmaintainers); + $filelist = $this->getFilelist(); + foreach ($pf1->getFilelist() as $file => $atts) { + if (!isset($filelist[$file])) { + $this->_missingFile($file); + $pass = false; + } } - return $php; + return $pass; } - /** - * process multiple dependencies that have a name, like package deps - * @param array - * @return array - * @access private - */ - function _processMultipleDepsName($deps) + function _differentPackage($package) { - $tests = array(); - foreach ($deps as $name => $dep) { - foreach ($dep as $d) { - $tests[$name][] = $this->_processDep($d); - } + $this->_stack->push(__FUNCTION__, 'error', array('package' => $package, + 'self' => $this->getPackage()), + 'package.xml 1.0 package "%package%" does not match "%self%"'); + } + + function _differentVersion($version) + { + $this->_stack->push(__FUNCTION__, 'error', array('version' => $version, + 'self' => $this->getVersion()), + 'package.xml 1.0 version "%version%" does not match "%self%"'); + } + + function _differentState($state) + { + $this->_stack->push(__FUNCTION__, 'error', array('state' => $state, + 'self' => $this->getState()), + 'package.xml 1.0 state "%state%" does not match "%self%"'); + } + + function _differentRole($handle, $role, $selfrole) + { + $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle, + 'role' => $role, 'self' => $selfrole), + 'package.xml 1.0 maintainer "%handle%" role "%role%" does not match "%self%"'); + } + + function _differentEmail($handle, $email, $selfemail) + { + $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle, + 'email' => $email, 'self' => $selfemail), + 'package.xml 1.0 maintainer "%handle%" email "%email%" does not match "%self%"'); + } + + function _differentName($handle, $name, $selfname) + { + $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle, + 'name' => $name, 'self' => $selfname), + 'package.xml 1.0 maintainer "%handle%" name "%name%" does not match "%self%"'); + } + + function _unmatchedMaintainers($my, $yours) + { + if ($my) { + array_walk($my, create_function('&$i, $k', '$i = $i["handle"];')); + $this->_stack->push(__FUNCTION__, 'error', array('handles' => $my), + 'package.xml 2.0 has unmatched extra maintainers "%handles%"'); } - foreach ($tests as $name => $test) { - $php = array(); - $min = array(); - $max = array(); - $php['name'] = $name; - foreach ($test as $dep) { - if (!$dep) { - continue; - } - if (isset($dep['channel'])) { - $php['channel'] = 'pear.php.net'; - } - if (isset($dep['conflicts']) && $dep['conflicts'] == 'yes') { - $php['conflicts'] = 'yes'; - } - if (isset($dep['min'])) { - $min[$dep['min']] = count($min); - } - if (isset($dep['max'])) { - $max[$dep['max']] = count($max); - } - } - if (count($min) > 0) { - uksort($min, 'version_compare'); - } - if (count($max) > 0) { - uksort($max, 'version_compare'); - } - if (count($min)) { - // get the highest minimum - $min = array_pop($a = array_flip($min)); - } else { - $min = false; - } - if (count($max)) { - // get the lowest maximum - $max = array_shift($a = array_flip($max)); - } else { - $max = false; - } - if ($min) { - $php['min'] = $min; - } - if ($max) { - $php['max'] = $max; - } - $exclude = array(); - foreach ($test as $dep) { - if (!isset($dep['exclude'])) { - continue; - } - $exclude[] = $dep['exclude']; - } - if (count($exclude)) { - $php['exclude'] = $exclude; - } - $ret[] = $php; + if ($yours) { + array_walk($yours, create_function('&$i, $k', '$i = $i["handle"];')); + $this->_stack->push(__FUNCTION__, 'error', array('handles' => $yours), + 'package.xml 1.0 has unmatched extra maintainers "%handles%"'); } - return $ret; } -} -?> - * @author Stephan Schmidt (original XML_Serializer code) - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: v2.php,v 1.51 2009/03/27 17:11:18 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * file/dir manipulation routines - */ -require_once 'phar://install-pear-nozlib.phar/' . 'System.php'; -require_once 'phar://install-pear-nozlib.phar/' . 'XML/Util.php'; -/** - * This class converts a PEAR_PackageFile_v2 object into any output format. - * - * Supported output formats include array, XML string (using S. Schmidt's - * XML_Serializer, slightly customized) - * @category pear - * @package PEAR - * @author Greg Beaver - * @author Stephan Schmidt (original XML_Serializer code) - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_PackageFile_Generator_v2 -{ - /** - * default options for the serialization - * @access private - * @var array $_defaultOptions - */ - var $_defaultOptions = array( - 'indent' => ' ', // string used for indentation - 'linebreak' => "\n", // string used for newlines - 'typeHints' => false, // automatically add type hin attributes - 'addDecl' => true, // add an XML declaration - 'defaultTagName' => 'XML_Serializer_Tag', // tag used for indexed arrays or invalid names - 'classAsTagName' => false, // use classname for objects in indexed arrays - 'keyAttribute' => '_originalKey', // attribute where original key is stored - 'typeAttribute' => '_type', // attribute for type (only if typeHints => true) - 'classAttribute' => '_class', // attribute for class of objects (only if typeHints => true) - 'scalarAsAttributes' => false, // scalar values (strings, ints,..) will be serialized as attribute - 'prependAttributes' => '', // prepend string for attributes - 'indentAttributes' => false, // indent the attributes, if set to '_auto', it will indent attributes so they all start at the same column - 'mode' => 'simplexml', // use 'simplexml' to use parent name as tagname if transforming an indexed array - 'addDoctype' => false, // add a doctype declaration - 'doctype' => null, // supply a string or an array with id and uri ({@see XML_Util::getDoctypeDeclaration()} - 'rootName' => 'package', // name of the root tag - 'rootAttributes' => array( - 'version' => '2.0', - 'xmlns' => 'http://pear.php.net/dtd/package-2.0', - 'xmlns:tasks' => 'http://pear.php.net/dtd/tasks-1.0', - 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', - 'xsi:schemaLocation' => 'http://pear.php.net/dtd/tasks-1.0 -http://pear.php.net/dtd/tasks-1.0.xsd -http://pear.php.net/dtd/package-2.0 -http://pear.php.net/dtd/package-2.0.xsd', - ), // attributes of the root tag - 'attributesArray' => 'attribs', // all values in this key will be treated as attributes - 'contentName' => '_content', // this value will be used directly as content, instead of creating a new tag, may only be used in conjuction with attributesArray - 'beautifyFilelist' => false, - 'encoding' => 'UTF-8', - ); + function _differentNotes($notes) + { + $truncnotes = strlen($notes) < 25 ? $notes : substr($notes, 0, 24) . '...'; + $truncmynotes = strlen($this->getNotes()) < 25 ? $this->getNotes() : + substr($this->getNotes(), 0, 24) . '...'; + $this->_stack->push(__FUNCTION__, 'error', array('notes' => $truncnotes, + 'self' => $truncmynotes), + 'package.xml 1.0 release notes "%notes%" do not match "%self%"'); + } - /** - * options for the serialization - * @access private - * @var array $options - */ - var $options = array(); + function _differentSummary($summary) + { + $truncsummary = strlen($summary) < 25 ? $summary : substr($summary, 0, 24) . '...'; + $truncmysummary = strlen($this->getsummary()) < 25 ? $this->getSummary() : + substr($this->getsummary(), 0, 24) . '...'; + $this->_stack->push(__FUNCTION__, 'error', array('summary' => $truncsummary, + 'self' => $truncmysummary), + 'package.xml 1.0 summary "%summary%" does not match "%self%"'); + } - /** - * current tag depth - * @var integer $_tagDepth - */ - var $_tagDepth = 0; + function _differentDescription($description) + { + $truncdescription = trim(strlen($description) < 25 ? $description : substr($description, 0, 24) . '...'); + $truncmydescription = trim(strlen($this->getDescription()) < 25 ? $this->getDescription() : + substr($this->getdescription(), 0, 24) . '...'); + $this->_stack->push(__FUNCTION__, 'error', array('description' => $truncdescription, + 'self' => $truncmydescription), + 'package.xml 1.0 description "%description%" does not match "%self%"'); + } + + function _missingFile($file) + { + $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), + 'package.xml 1.0 file "%file%" is not present in '); + } - /** - * serilialized representation of the data - * @var string $_serializedData - */ - var $_serializedData = null; /** - * @var PEAR_PackageFile_v2 + * WARNING - do not use this function unless you know what you're doing */ - var $_packagefile; + function setRawState($state) + { + if (!isset($this->_packageInfo['stability'])) { + $this->_packageInfo['stability'] = array(); + } + $this->_packageInfo['stability']['release'] = $state; + } + /** - * @param PEAR_PackageFile_v2 + * WARNING - do not use this function unless you know what you're doing */ - function PEAR_PackageFile_Generator_v2(&$packagefile) + function setRawCompatible($compatible) + { + $this->_packageInfo['compatible'] = $compatible; + } + + /** + * WARNING - do not use this function unless you know what you're doing + */ + function setRawPackage($package) + { + $this->_packageInfo['name'] = $package; + } + + /** + * WARNING - do not use this function unless you know what you're doing + */ + function setRawChannel($channel) + { + $this->_packageInfo['channel'] = $channel; + } + + function setRequestedGroup($group) + { + $this->_requestedGroup = $group; + } + + function getRequestedGroup() { - $this->_packagefile = &$packagefile; - if (isset($this->_packagefile->encoding)) { - $this->_defaultOptions['encoding'] = $this->_packagefile->encoding; + if (isset($this->_requestedGroup)) { + return $this->_requestedGroup; } + return false; } /** - * @return string + * For saving in the registry. + * + * Set the last version that was installed + * @param string */ - function getPackagerVersion() + function setLastInstalledVersion($version) { - return '1.8.0'; + $this->_packageInfo['_lastversion'] = $version; } /** - * @param PEAR_Packager - * @param bool generate a .tgz or a .tar - * @param string|null temporary directory to package in + * @return string|false */ - function toTgz(&$packager, $compress = true, $where = null) + function getLastInstalledVersion() { - $a = null; - return $this->toTgz2($packager, $a, $compress, $where); + if (isset($this->_packageInfo['_lastversion'])) { + return $this->_packageInfo['_lastversion']; + } + return false; } /** - * Package up both a package.xml and package2.xml for the same release - * @param PEAR_Packager - * @param PEAR_PackageFile_v1 - * @param bool generate a .tgz or a .tar - * @param string|null temporary directory to package in + * Determines whether this package.xml has post-install scripts or not + * @return array|false */ - function toTgz2(&$packager, &$pf1, $compress = true, $where = null) + function listPostinstallScripts() { - require_once 'phar://install-pear-nozlib.phar/' . 'Archive/Tar.php'; - if (!$this->_packagefile->isEquivalent($pf1)) { - return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: "' . - basename($pf1->getPackageFile()) . - '" is not equivalent to "' . basename($this->_packagefile->getPackageFile()) - . '"'); + $filelist = $this->getFilelist(); + $contents = $this->getContents(); + $contents = $contents['dir']['file']; + if (!is_array($contents) || !isset($contents[0])) { + $contents = array($contents); } - - if ($where === null) { - if (!($where = System::mktemp(array('-d')))) { - return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: mktemp failed'); + $taskfiles = array(); + foreach ($contents as $file) { + $atts = $file['attribs']; + unset($file['attribs']); + if (count($file)) { + $taskfiles[$atts['name']] = $file; } - } elseif (!@System::mkDir(array('-p', $where))) { - return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: "' . $where . '" could' . - ' not be created'); } - - $file = $where . DIRECTORY_SEPARATOR . 'package.xml'; - if (file_exists($file) && !is_file($file)) { - return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: unable to save package.xml as' . - ' "' . $file .'"'); + $common = new PEAR_Common; + $common->debug = $this->_config->get('verbose'); + $this->_scripts = array(); + $ret = array(); + foreach ($taskfiles as $name => $tasks) { + if (!isset($filelist[$name])) { + // ignored files will not be in the filelist + continue; + } + $atts = $filelist[$name]; + foreach ($tasks as $tag => $raw) { + $task = $this->getTask($tag); + $task = &new $task($this->_config, $common, PEAR_TASK_INSTALL); + if ($task->isScript()) { + $ret[] = $filelist[$name]['installed_as']; + } + } } - - if (!$this->_packagefile->validate(PEAR_VALIDATE_PACKAGING)) { - return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: invalid package.xml'); + if (count($ret)) { + return $ret; } + return false; + } - $ext = $compress ? '.tgz' : '.tar'; - $pkgver = $this->_packagefile->getPackage() . '-' . $this->_packagefile->getVersion(); - $dest_package = getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext; - if (file_exists($dest_package) && !is_file($dest_package)) { - return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: cannot create tgz file "' . - $dest_package . '"'); + /** + * Initialize post-install scripts for running + * + * This method can be used to detect post-install scripts, as the return value + * indicates whether any exist + * @return bool + */ + function initPostinstallScripts() + { + $filelist = $this->getFilelist(); + $contents = $this->getContents(); + $contents = $contents['dir']['file']; + if (!is_array($contents) || !isset($contents[0])) { + $contents = array($contents); + } + $taskfiles = array(); + foreach ($contents as $file) { + $atts = $file['attribs']; + unset($file['attribs']); + if (count($file)) { + $taskfiles[$atts['name']] = $file; + } + } + $common = new PEAR_Common; + $common->debug = $this->_config->get('verbose'); + $this->_scripts = array(); + foreach ($taskfiles as $name => $tasks) { + if (!isset($filelist[$name])) { + // file was not installed due to installconditions + continue; + } + $atts = $filelist[$name]; + foreach ($tasks as $tag => $raw) { + $taskname = $this->getTask($tag); + $task = &new $taskname($this->_config, $common, PEAR_TASK_INSTALL); + if (!$task->isScript()) { + continue; // scripts are only handled after installation + } + $lastversion = isset($this->_packageInfo['_lastversion']) ? + $this->_packageInfo['_lastversion'] : null; + $task->init($raw, $atts, $lastversion); + $res = $task->startSession($this, $atts['installed_as']); + if (!$res) { + continue; // skip this file + } + if (PEAR::isError($res)) { + return $res; + } + $assign = &$task; + $this->_scripts[] = &$assign; + } + } + if (count($this->_scripts)) { + return true; } + return false; + } - $pkgfile = $this->_packagefile->getPackageFile(); - if (!$pkgfile) { - return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: package file object must ' . - 'be created from a real file'); + function runPostinstallScripts() + { + if ($this->initPostinstallScripts()) { + $ui = &PEAR_Frontend::singleton(); + if ($ui) { + $ui->runPostinstallScripts($this->_scripts, $this); + } } + } - $pkgdir = dirname(realpath($pkgfile)); - $pkgfile = basename($pkgfile); - // {{{ Create the package file list + /** + * Convert a recursive set of and tags into a single tag with + * tags. + */ + function flattenFilelist() + { + if (isset($this->_packageInfo['bundle'])) { + return; + } $filelist = array(); - $i = 0; - $this->_packagefile->flattenFilelist(); - $contents = $this->_packagefile->getContents(); - if (isset($contents['bundledpackage'])) { // bundles of packages - $contents = $contents['bundledpackage']; - if (!isset($contents[0])) { - $contents = array($contents); + if (isset($this->_packageInfo['contents']['dir']['dir'])) { + $this->_getFlattenedFilelist($filelist, $this->_packageInfo['contents']['dir']); + if (!isset($filelist[1])) { + $filelist = $filelist[0]; } - - $packageDir = $where; - foreach ($contents as $i => $package) { - $fname = $package; - $file = $pkgdir . DIRECTORY_SEPARATOR . $fname; - if (!file_exists($file)) { - return $packager->raiseError("File does not exist: $fname"); + $this->_packageInfo['contents']['dir']['file'] = $filelist; + unset($this->_packageInfo['contents']['dir']['dir']); + } else { + // else already flattened but check for baseinstalldir propagation + if (isset($this->_packageInfo['contents']['dir']['attribs']['baseinstalldir'])) { + if (isset($this->_packageInfo['contents']['dir']['file'][0])) { + foreach ($this->_packageInfo['contents']['dir']['file'] as $i => $file) { + if (isset($file['attribs']['baseinstalldir'])) { + continue; + } + $this->_packageInfo['contents']['dir']['file'][$i]['attribs']['baseinstalldir'] + = $this->_packageInfo['contents']['dir']['attribs']['baseinstalldir']; + } + } else { + if (!isset($this->_packageInfo['contents']['dir']['file']['attribs']['baseinstalldir'])) { + $this->_packageInfo['contents']['dir']['file']['attribs']['baseinstalldir'] + = $this->_packageInfo['contents']['dir']['attribs']['baseinstalldir']; + } } + } + } + } - $tfile = $packageDir . DIRECTORY_SEPARATOR . $fname; - System::mkdir(array('-p', dirname($tfile))); - copy($file, $tfile); - $filelist[$i++] = $tfile; - $packager->log(2, "Adding package $fname"); + /** + * @param array the final flattened file list + * @param array the current directory being processed + * @param string|false any recursively inherited baeinstalldir attribute + * @param string private recursion variable + * @return array + * @access protected + */ + function _getFlattenedFilelist(&$files, $dir, $baseinstall = false, $path = '') + { + if (isset($dir['attribs']) && isset($dir['attribs']['baseinstalldir'])) { + $baseinstall = $dir['attribs']['baseinstalldir']; + } + if (isset($dir['dir'])) { + if (!isset($dir['dir'][0])) { + $dir['dir'] = array($dir['dir']); } - } else { // normal packages - $contents = $contents['dir']['file']; - if (!isset($contents[0])) { - $contents = array($contents); + foreach ($dir['dir'] as $subdir) { + if (!isset($subdir['attribs']) || !isset($subdir['attribs']['name'])) { + $name = '*unknown*'; + } else { + $name = $subdir['attribs']['name']; + } + $newpath = empty($path) ? $name : + $path . '/' . $name; + $this->_getFlattenedFilelist($files, $subdir, + $baseinstall, $newpath); } - - $packageDir = $where; - foreach ($contents as $i => $file) { - $fname = $file['attribs']['name']; - $atts = $file['attribs']; - $orig = $file; - $file = $pkgdir . DIRECTORY_SEPARATOR . $fname; - if (!file_exists($file)) { - return $packager->raiseError("File does not exist: $fname"); + } + if (isset($dir['file'])) { + if (!isset($dir['file'][0])) { + $dir['file'] = array($dir['file']); + } + foreach ($dir['file'] as $file) { + $attrs = $file['attribs']; + $name = $attrs['name']; + if ($baseinstall && !isset($attrs['baseinstalldir'])) { + $attrs['baseinstalldir'] = $baseinstall; } + $attrs['name'] = empty($path) ? $name : $path . '/' . $name; + $attrs['name'] = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), + $attrs['name']); + $file['attribs'] = $attrs; + $files[] = $file; + } + } + } - $origperms = fileperms($file); - $tfile = $packageDir . DIRECTORY_SEPARATOR . $fname; - unset($orig['attribs']); - if (count($orig)) { // file with tasks - // run any package-time tasks - $contents = file_get_contents($file); - foreach ($orig as $tag => $raw) { - $tag = str_replace( - array($this->_packagefile->getTasksNs() . ':', '-'), - array('', '_'), $tag); - $task = "PEAR_Task_$tag"; - $task = &new $task($this->_packagefile->_config, - $this->_packagefile->_logger, - PEAR_TASK_PACKAGE); - $task->init($raw, $atts, null); - $res = $task->startSession($this->_packagefile, $contents, $tfile); - if (!$res) { - continue; // skip this task - } + function setConfig(&$config) + { + $this->_config = &$config; + $this->_registry = &$config->getRegistry(); + } - if (PEAR::isError($res)) { - return $res; - } + function setLogger(&$logger) + { + if (!is_object($logger) || !method_exists($logger, 'log')) { + return PEAR::raiseError('Logger must be compatible with PEAR_Common::log'); + } + $this->_logger = &$logger; + } - $contents = $res; // save changes - System::mkdir(array('-p', dirname($tfile))); - $wp = fopen($tfile, "wb"); - fwrite($wp, $contents); - fclose($wp); - } - } + /** + * WARNING - do not use this function directly unless you know what you're doing + */ + function setDeps($deps) + { + $this->_packageInfo['dependencies'] = $deps; + } - if (!file_exists($tfile)) { - System::mkdir(array('-p', dirname($tfile))); - copy($file, $tfile); - } + /** + * WARNING - do not use this function directly unless you know what you're doing + */ + function setCompatible($compat) + { + $this->_packageInfo['compatible'] = $compat; + } - chmod($tfile, $origperms); - $filelist[$i++] = $tfile; - $this->_packagefile->setFileAttribute($fname, 'md5sum', md5_file($tfile), $i - 1); - $packager->log(2, "Adding file $fname"); - } - } - // }}} + function setPackagefile($file, $archive = false) + { + $this->_packageFile = $file; + $this->_archiveFile = $archive ? $archive : $file; + } - $name = $pf1 !== null ? 'package2.xml' : 'package.xml'; - $packagexml = $this->toPackageFile($where, PEAR_VALIDATE_PACKAGING, $name); - if ($packagexml) { - $tar =& new Archive_Tar($dest_package, $compress); - $tar->setErrorHandling(PEAR_ERROR_RETURN); // XXX Don't print errors - // ----- Creates with the package.xml file - $ok = $tar->createModify(array($packagexml), '', $where); - if (PEAR::isError($ok)) { - return $packager->raiseError($ok); - } elseif (!$ok) { - return $packager->raiseError('PEAR_Packagefile_v2::toTgz(): adding ' . $name . - ' failed'); - } + /** + * Wrapper to {@link PEAR_ErrorStack::getErrors()} + * @param boolean determines whether to purge the error stack after retrieving + * @return array + */ + function getValidationWarnings($purge = true) + { + return $this->_stack->getErrors($purge); + } - // ----- Add the content of the package - if (!$tar->addModify($filelist, $pkgver, $where)) { - return $packager->raiseError( - 'PEAR_Packagefile_v2::toTgz(): tarball creation failed'); - } + function getPackageFile() + { + return $this->_packageFile; + } - // add the package.xml version 1.0 - if ($pf1 !== null) { - $pfgen = &$pf1->getDefaultGenerator(); - $packagexml1 = $pfgen->toPackageFile($where, PEAR_VALIDATE_PACKAGING, 'package.xml', true); - if (!$tar->addModify(array($packagexml1), '', $where)) { - return $packager->raiseError( - 'PEAR_Packagefile_v2::toTgz(): adding package.xml failed'); - } - } + function getArchiveFile() + { + return $this->_archiveFile; + } - return $dest_package; - } + + /** + * Directly set the array that defines this packagefile + * + * WARNING: no validation. This should only be performed by internal methods + * inside PEAR or by inputting an array saved from an existing PEAR_PackageFile_v2 + * @param array + */ + function fromArray($pinfo) + { + unset($pinfo['old']); + unset($pinfo['xsdversion']); + $this->_incomplete = false; + $this->_packageInfo = $pinfo; } - function toPackageFile($where = null, $state = PEAR_VALIDATE_NORMAL, $name = 'package.xml') + function isIncomplete() { - if (!$this->_packagefile->validate($state)) { - return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: invalid package.xml', - null, null, null, $this->_packagefile->getValidationWarnings()); + return $this->_incomplete; + } + + /** + * @return array + */ + function toArray($forreg = false) + { + if (!$this->validate(PEAR_VALIDATE_NORMAL)) { + return false; } + return $this->getArray($forreg); + } - if ($where === null) { - if (!($where = System::mktemp(array('-d')))) { - return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: mktemp failed'); + function getArray($forReg = false) + { + if ($forReg) { + $arr = $this->_packageInfo; + $arr['old'] = array(); + $arr['old']['version'] = $this->getVersion(); + $arr['old']['release_date'] = $this->getDate(); + $arr['old']['release_state'] = $this->getState(); + $arr['old']['release_license'] = $this->getLicense(); + $arr['old']['release_notes'] = $this->getNotes(); + $arr['old']['release_deps'] = $this->getDeps(); + $arr['old']['maintainers'] = $this->getMaintainers(); + $arr['xsdversion'] = '2.0'; + return $arr; + } else { + $info = $this->_packageInfo; + unset($info['dirtree']); + if (isset($info['_lastversion'])) { + unset($info['_lastversion']); } - } elseif (!@System::mkDir(array('-p', $where))) { - return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: "' . $where . '" could' . - ' not be created'); + if (isset($info['#binarypackage'])) { + unset($info['#binarypackage']); + } + return $info; } + } - $newpkgfile = $where . DIRECTORY_SEPARATOR . $name; - $np = @fopen($newpkgfile, 'wb'); - if (!$np) { - return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: unable to save ' . - "$name as $newpkgfile"); + function packageInfo($field) + { + $arr = $this->getArray(true); + if ($field == 'state') { + return $arr['stability']['release']; } - fwrite($np, $this->toXml($state)); - fclose($np); - return $newpkgfile; + if ($field == 'api-version') { + return $arr['version']['api']; + } + if ($field == 'api-state') { + return $arr['stability']['api']; + } + if (isset($arr['old'][$field])) { + if (!is_string($arr['old'][$field])) { + return null; + } + return $arr['old'][$field]; + } + if (isset($arr[$field])) { + if (!is_string($arr[$field])) { + return null; + } + return $arr[$field]; + } + return null; } - function &toV2() + function getName() { - return $this->_packagefile; + return $this->getPackage(); } - /** - * Return an XML document based on the package info (as returned - * by the PEAR_Common::infoFrom* methods). - * - * @return string XML data - */ - function toXml($state = PEAR_VALIDATE_NORMAL, $options = array()) + function getPackage() { - $this->_packagefile->setDate(date('Y-m-d')); - $this->_packagefile->setTime(date('H:i:s')); - if (!$this->_packagefile->validate($state)) { - return false; + if (isset($this->_packageInfo['name'])) { + return $this->_packageInfo['name']; + } + return false; + } + + function getChannel() + { + if (isset($this->_packageInfo['uri'])) { + return '__uri'; } - - if (is_array($options)) { - $this->options = array_merge($this->_defaultOptions, $options); - } else { - $this->options = $this->_defaultOptions; + if (isset($this->_packageInfo['channel'])) { + return strtolower($this->_packageInfo['channel']); } + return false; + } - $arr = $this->_packagefile->getArray(); - if (isset($arr['filelist'])) { - unset($arr['filelist']); + function getUri() + { + if (isset($this->_packageInfo['uri'])) { + return $this->_packageInfo['uri']; } + return false; + } - if (isset($arr['_lastversion'])) { - unset($arr['_lastversion']); + function getExtends() + { + if (isset($this->_packageInfo['extends'])) { + return $this->_packageInfo['extends']; } + return false; + } - // Fix the notes a little bit - if (isset($arr['notes'])) { - // This trims out the indenting, needs fixing - $arr['notes'] = "\n" . trim($arr['notes']) . "\n"; + function getSummary() + { + if (isset($this->_packageInfo['summary'])) { + return $this->_packageInfo['summary']; } + return false; + } - if (isset($arr['changelog']) && !empty($arr['changelog'])) { - // Fix for inconsistency how the array is filled depending on the changelog release amount - if (!isset($arr['changelog']['release'][0])) { - $release = $arr['changelog']['release']; - unset($arr['changelog']['release']); + function getDescription() + { + if (isset($this->_packageInfo['description'])) { + return $this->_packageInfo['description']; + } + return false; + } - $arr['changelog']['release'] = array(); - $arr['changelog']['release'][0] = $release; + function getMaintainers($raw = false) + { + if (!isset($this->_packageInfo['lead'])) { + return false; + } + if ($raw) { + $ret = array('lead' => $this->_packageInfo['lead']); + (isset($this->_packageInfo['developer'])) ? + $ret['developer'] = $this->_packageInfo['developer'] :null; + (isset($this->_packageInfo['contributor'])) ? + $ret['contributor'] = $this->_packageInfo['contributor'] :null; + (isset($this->_packageInfo['helper'])) ? + $ret['helper'] = $this->_packageInfo['helper'] :null; + return $ret; + } else { + $ret = array(); + $leads = isset($this->_packageInfo['lead'][0]) ? $this->_packageInfo['lead'] : + array($this->_packageInfo['lead']); + foreach ($leads as $lead) { + $s = $lead; + $s['handle'] = $s['user']; + unset($s['user']); + $s['role'] = 'lead'; + $ret[] = $s; } - - foreach ($arr['changelog']['release'] as &$c) { - if (isset($c['notes'])) { - // This trims out the indenting, needs fixing - $c['notes'] = "\n" . trim($c['notes']) . "\n"; + if (isset($this->_packageInfo['developer'])) { + $leads = isset($this->_packageInfo['developer'][0]) ? + $this->_packageInfo['developer'] : + array($this->_packageInfo['developer']); + foreach ($leads as $maintainer) { + $s = $maintainer; + $s['handle'] = $s['user']; + unset($s['user']); + $s['role'] = 'developer'; + $ret[] = $s; } } - } - - if ($state ^ PEAR_VALIDATE_PACKAGING && !isset($arr['bundle'])) { - $use = $this->_recursiveXmlFilelist($arr['contents']['dir']['file']); - unset($arr['contents']['dir']['file']); - if (isset($use['dir'])) { - $arr['contents']['dir']['dir'] = $use['dir']; + if (isset($this->_packageInfo['contributor'])) { + $leads = isset($this->_packageInfo['contributor'][0]) ? + $this->_packageInfo['contributor'] : + array($this->_packageInfo['contributor']); + foreach ($leads as $maintainer) { + $s = $maintainer; + $s['handle'] = $s['user']; + unset($s['user']); + $s['role'] = 'contributor'; + $ret[] = $s; + } } - if (isset($use['file'])) { - $arr['contents']['dir']['file'] = $use['file']; + if (isset($this->_packageInfo['helper'])) { + $leads = isset($this->_packageInfo['helper'][0]) ? + $this->_packageInfo['helper'] : + array($this->_packageInfo['helper']); + foreach ($leads as $maintainer) { + $s = $maintainer; + $s['handle'] = $s['user']; + unset($s['user']); + $s['role'] = 'helper'; + $ret[] = $s; + } } - $this->options['beautifyFilelist'] = true; + return $ret; } + return false; + } - $arr['attribs']['packagerversion'] = '1.8.0'; - if ($this->serialize($arr, $options)) { - return $this->_serializedData . "\n"; + function getLeads() + { + if (isset($this->_packageInfo['lead'])) { + return $this->_packageInfo['lead']; } - return false; } - - function _recursiveXmlFilelist($list) + function getDevelopers() { - $dirs = array(); - if (isset($list['attribs'])) { - $file = $list['attribs']['name']; - unset($list['attribs']['name']); - $attributes = $list['attribs']; - $this->_addDir($dirs, explode('/', dirname($file)), $file, $attributes); - } else { - foreach ($list as $a) { - $file = $a['attribs']['name']; - $attributes = $a['attribs']; - unset($a['attribs']); - $this->_addDir($dirs, explode('/', dirname($file)), $file, $attributes, $a); - } + if (isset($this->_packageInfo['developer'])) { + return $this->_packageInfo['developer']; } - $this->_formatDir($dirs); - $this->_deFormat($dirs); - return $dirs; + return false; } - function _addDir(&$dirs, $dir, $file = null, $attributes = null, $tasks = null) + function getContributors() { - if (!$tasks) { - $tasks = array(); - } - if ($dir == array() || $dir == array('.')) { - $dirs['file'][basename($file)] = $tasks; - $attributes['name'] = basename($file); - $dirs['file'][basename($file)]['attribs'] = $attributes; - return; - } - $curdir = array_shift($dir); - if (!isset($dirs['dir'][$curdir])) { - $dirs['dir'][$curdir] = array(); + if (isset($this->_packageInfo['contributor'])) { + return $this->_packageInfo['contributor']; } - $this->_addDir($dirs['dir'][$curdir], $dir, $file, $attributes, $tasks); + return false; } - function _formatDir(&$dirs) + function getHelpers() { - if (!count($dirs)) { - return array(); - } - $newdirs = array(); - if (isset($dirs['dir'])) { - $newdirs['dir'] = $dirs['dir']; - } - if (isset($dirs['file'])) { - $newdirs['file'] = $dirs['file']; + if (isset($this->_packageInfo['helper'])) { + return $this->_packageInfo['helper']; } - $dirs = $newdirs; - if (isset($dirs['dir'])) { - uksort($dirs['dir'], 'strnatcasecmp'); - foreach ($dirs['dir'] as $dir => $contents) { - $this->_formatDir($dirs['dir'][$dir]); - } + return false; + } + + function setDate($date) + { + if (!isset($this->_packageInfo['date'])) { + // ensure that the extends tag is set up in the right location + $this->_packageInfo = $this->_insertBefore($this->_packageInfo, + array('time', 'version', + 'stability', 'license', 'notes', 'contents', 'compatible', + 'dependencies', 'providesextension', 'srcpackage', 'srcuri', + 'phprelease', 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease', + 'zendextbinrelease', 'bundle', 'changelog'), array(), 'date'); } - if (isset($dirs['file'])) { - uksort($dirs['file'], 'strnatcasecmp'); - }; + $this->_packageInfo['date'] = $date; + $this->_isValid = 0; } - function _deFormat(&$dirs) + function setTime($time) { - if (!count($dirs)) { - return array(); + $this->_isValid = 0; + if (!isset($this->_packageInfo['time'])) { + // ensure that the time tag is set up in the right location + $this->_packageInfo = $this->_insertBefore($this->_packageInfo, + array('version', + 'stability', 'license', 'notes', 'contents', 'compatible', + 'dependencies', 'providesextension', 'srcpackage', 'srcuri', + 'phprelease', 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease', + 'zendextbinrelease', 'bundle', 'changelog'), $time, 'time'); } - $newdirs = array(); - if (isset($dirs['dir'])) { - foreach ($dirs['dir'] as $dir => $contents) { - $newdir = array(); - $newdir['attribs']['name'] = $dir; - $this->_deFormat($contents); - foreach ($contents as $tag => $val) { - $newdir[$tag] = $val; - } - $newdirs['dir'][] = $newdir; - } - if (count($newdirs['dir']) == 1) { - $newdirs['dir'] = $newdirs['dir'][0]; - } + $this->_packageInfo['time'] = $time; + } + + function getDate() + { + if (isset($this->_packageInfo['date'])) { + return $this->_packageInfo['date']; } - if (isset($dirs['file'])) { - foreach ($dirs['file'] as $name => $file) { - $newdirs['file'][] = $file; - } - if (count($newdirs['file']) == 1) { - $newdirs['file'] = $newdirs['file'][0]; - } + return false; + } + + function getTime() + { + if (isset($this->_packageInfo['time'])) { + return $this->_packageInfo['time']; } - $dirs = $newdirs; + return false; } /** - * reset all options to default options - * - * @access public - * @see setOption(), XML_Unserializer() - */ - function resetOptions() + * @param package|api version category to return + */ + function getVersion($key = 'release') { - $this->options = $this->_defaultOptions; + if (isset($this->_packageInfo['version'][$key])) { + return $this->_packageInfo['version'][$key]; + } + return false; } - /** - * set an option - * - * You can use this method if you do not want to set all options in the constructor - * - * @access public - * @see resetOption(), XML_Serializer() - */ - function setOption($name, $value) + function getStability() { - $this->options[$name] = $value; + if (isset($this->_packageInfo['stability'])) { + return $this->_packageInfo['stability']; + } + return false; } - /** - * sets several options at once - * - * You can use this method if you do not want to set all options in the constructor - * - * @access public - * @see resetOption(), XML_Unserializer(), setOption() - */ - function setOptions($options) + function getState($key = 'release') { - $this->options = array_merge($this->options, $options); + if (isset($this->_packageInfo['stability'][$key])) { + return $this->_packageInfo['stability'][$key]; + } + return false; } - /** - * serialize data - * - * @access public - * @param mixed $data data to serialize - * @return boolean true on success, pear error on failure - */ - function serialize($data, $options = null) + function getLicense($raw = false) { - // if options have been specified, use them instead - // of the previously defined ones - if (is_array($options)) { - $optionsBak = $this->options; - if (isset($options['overrideOptions']) && $options['overrideOptions'] == true) { - $this->options = array_merge($this->_defaultOptions, $options); + if (isset($this->_packageInfo['license'])) { + if ($raw) { + return $this->_packageInfo['license']; + } + if (is_array($this->_packageInfo['license'])) { + return $this->_packageInfo['license']['_content']; } else { - $this->options = array_merge($this->options, $options); + return $this->_packageInfo['license']; } - } else { - $optionsBak = null; - } - - // start depth is zero - $this->_tagDepth = 0; - $this->_serializedData = ''; - // serialize an array - if (is_array($data)) { - $tagName = isset($this->options['rootName']) ? $this->options['rootName'] : 'array'; - $this->_serializedData .= $this->_serializeArray($data, $tagName, $this->options['rootAttributes']); - } - - // add doctype declaration - if ($this->options['addDoctype'] === true) { - $this->_serializedData = XML_Util::getDoctypeDeclaration($tagName, $this->options['doctype']) - . $this->options['linebreak'] - . $this->_serializedData; } + return false; + } - // build xml declaration - if ($this->options['addDecl']) { - $atts = array(); - $encoding = isset($this->options['encoding']) ? $this->options['encoding'] : null; - $this->_serializedData = XML_Util::getXMLDeclaration('1.0', $encoding) - . $this->options['linebreak'] - . $this->_serializedData; + function getLicenseLocation() + { + if (!isset($this->_packageInfo['license']) || !is_array($this->_packageInfo['license'])) { + return false; } + return $this->_packageInfo['license']['attribs']; + } - - if ($optionsBak !== null) { - $this->options = $optionsBak; + function getNotes() + { + if (isset($this->_packageInfo['notes'])) { + return $this->_packageInfo['notes']; } - - return true; + return false; } - /** - * get the result of the serialization - * - * @access public - * @return string serialized XML - */ - function getSerializedData() + /** + * Return the tag contents, if any + * @return array|false + */ + function getUsesrole() { - if ($this->_serializedData === null) { - return $this->raiseError('No serialized data available. Use XML_Serializer::serialize() first.', XML_SERIALIZER_ERROR_NO_SERIALIZATION); + if (isset($this->_packageInfo['usesrole'])) { + return $this->_packageInfo['usesrole']; } - return $this->_serializedData; + return false; } - /** - * serialize any value - * - * This method checks for the type of the value and calls the appropriate method - * - * @access private - * @param mixed $value - * @param string $tagName - * @param array $attributes - * @return string - */ - function _serializeValue($value, $tagName = null, $attributes = array()) + /** + * Return the tag contents, if any + * @return array|false + */ + function getUsestask() { - if (is_array($value)) { - $xml = $this->_serializeArray($value, $tagName, $attributes); - } elseif (is_object($value)) { - $xml = $this->_serializeObject($value, $tagName); - } else { - $tag = array( - 'qname' => $tagName, - 'attributes' => $attributes, - 'content' => $value - ); - $xml = $this->_createXMLTag($tag); + if (isset($this->_packageInfo['usestask'])) { + return $this->_packageInfo['usestask']; } - return $xml; + return false; } - /** - * serialize an array - * - * @access private - * @param array $array array to serialize - * @param string $tagName name of the root tag - * @param array $attributes attributes for the root tag - * @return string $string serialized data - * @uses XML_Util::isValidName() to check, whether key has to be substituted - */ - function _serializeArray(&$array, $tagName = null, $attributes = array()) + /** + * This should only be used to retrieve filenames and install attributes + */ + function getFilelist($preserve = false) { - $_content = null; - - /** - * check for special attributes - */ - if ($this->options['attributesArray'] !== null) { - if (isset($array[$this->options['attributesArray']])) { - $attributes = $array[$this->options['attributesArray']]; - unset($array[$this->options['attributesArray']]); - } - /** - * check for special content - */ - if ($this->options['contentName'] !== null) { - if (isset($array[$this->options['contentName']])) { - $_content = $array[$this->options['contentName']]; - unset($array[$this->options['contentName']]); - } - } + if (isset($this->_packageInfo['filelist']) && !$preserve) { + return $this->_packageInfo['filelist']; } - - /* - * if mode is set to simpleXML, check whether - * the array is associative or indexed - */ - if (is_array($array) && $this->options['mode'] == 'simplexml') { - $indexed = true; - if (!count($array)) { - $indexed = false; - } - foreach ($array as $key => $val) { - if (!is_int($key)) { - $indexed = false; - break; - } - } - - if ($indexed && $this->options['mode'] == 'simplexml') { - $string = ''; - foreach ($array as $key => $val) { - if ($this->options['beautifyFilelist'] && $tagName == 'dir') { - if (!isset($this->_curdir)) { - $this->_curdir = ''; - } - $savedir = $this->_curdir; - if (isset($val['attribs'])) { - if ($val['attribs']['name'] == '/') { - $this->_curdir = '/'; - } else { - if ($this->_curdir == '/') { - $this->_curdir = ''; - } - $this->_curdir .= '/' . $val['attribs']['name']; - } - } - } - $string .= $this->_serializeValue( $val, $tagName, $attributes); - if ($this->options['beautifyFilelist'] && $tagName == 'dir') { - $string .= ' '; - if (empty($savedir)) { - unset($this->_curdir); - } else { - $this->_curdir = $savedir; - } - } - - $string .= $this->options['linebreak']; - // do indentation - if ($this->options['indent'] !== null && $this->_tagDepth > 0) { - $string .= str_repeat($this->options['indent'], $this->_tagDepth); - } + $this->flattenFilelist(); + if ($contents = $this->getContents()) { + $ret = array(); + if (!isset($contents['dir'])) { + return false; + } + if (!isset($contents['dir']['file'][0])) { + $contents['dir']['file'] = array($contents['dir']['file']); + } + foreach ($contents['dir']['file'] as $file) { + $name = $file['attribs']['name']; + if (!$preserve) { + $file = $file['attribs']; } - return rtrim($string); + $ret[$name] = $file; + } + if (!$preserve) { + $this->_packageInfo['filelist'] = $ret; } + return $ret; } + return false; + } - if ($this->options['scalarAsAttributes'] === true) { - foreach ($array as $key => $value) { - if (is_scalar($value) && (XML_Util::isValidName($key) === true)) { - unset($array[$key]); - $attributes[$this->options['prependAttributes'].$key] = $value; - } + /** + * Return configure options array, if any + * + * @return array|false + */ + function getConfigureOptions() + { + if ($this->getPackageType() != 'extsrc' && $this->getPackageType() != 'zendextsrc') { + return false; + } + + $releases = $this->getReleases(); + if (isset($releases[0])) { + $releases = $releases[0]; + } + + if (isset($releases['configureoption'])) { + if (!isset($releases['configureoption'][0])) { + $releases['configureoption'] = array($releases['configureoption']); + } + + for ($i = 0; $i < count($releases['configureoption']); $i++) { + $releases['configureoption'][$i] = $releases['configureoption'][$i]['attribs']; } + + return $releases['configureoption']; } - // check for empty array => create empty tag - if (empty($array)) { - $tag = array( - 'qname' => $tagName, - 'content' => $_content, - 'attributes' => $attributes - ); + return false; + } - } else { - $this->_tagDepth++; - $tmp = $this->options['linebreak']; - foreach ($array as $key => $value) { - // do indentation - if ($this->options['indent'] !== null && $this->_tagDepth > 0) { - $tmp .= str_repeat($this->options['indent'], $this->_tagDepth); - } + /** + * This is only used at install-time, after all serialization + * is over. + */ + function resetFilelist() + { + $this->_packageInfo['filelist'] = array(); + } - // copy key - $origKey = $key; - // key cannot be used as tagname => use default tag - $valid = XML_Util::isValidName($key); - if (PEAR::isError($valid)) { - if ($this->options['classAsTagName'] && is_object($value)) { - $key = get_class($value); - } else { - $key = $this->options['defaultTagName']; + /** + * Retrieve a list of files that should be installed on this computer + * @return array + */ + function getInstallationFilelist($forfilecheck = false) + { + $contents = $this->getFilelist(true); + if (isset($contents['dir']['attribs']['baseinstalldir'])) { + $base = $contents['dir']['attribs']['baseinstalldir']; + } + if (isset($this->_packageInfo['bundle'])) { + return PEAR::raiseError( + 'Exception: bundles should be handled in download code only'); + } + $release = $this->getReleases(); + if ($release) { + if (!isset($release[0])) { + if (!isset($release['installconditions']) && !isset($release['filelist'])) { + if ($forfilecheck) { + return $this->getFilelist(); } + return $contents; } - $atts = array(); - if ($this->options['typeHints'] === true) { - $atts[$this->options['typeAttribute']] = gettype($value); - if ($key !== $origKey) { - $atts[$this->options['keyAttribute']] = (string)$origKey; + $release = array($release); + } + $depchecker = &$this->getPEARDependency2($this->_config, array(), + array('channel' => $this->getChannel(), 'package' => $this->getPackage()), + PEAR_VALIDATE_INSTALLING); + foreach ($release as $instance) { + if (isset($instance['installconditions'])) { + $installconditions = $instance['installconditions']; + if (is_array($installconditions)) { + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + foreach ($installconditions as $type => $conditions) { + if (!isset($conditions[0])) { + $conditions = array($conditions); + } + foreach ($conditions as $condition) { + $ret = $depchecker->{"validate{$type}Dependency"}($condition); + if (PEAR::isError($ret)) { + PEAR::popErrorHandling(); + continue 3; // skip this release + } + } + } + PEAR::popErrorHandling(); } - } - if ($this->options['beautifyFilelist'] && $key == 'dir') { - if (!isset($this->_curdir)) { - $this->_curdir = ''; + // this is the release to use + if (isset($instance['filelist'])) { + // ignore files + if (isset($instance['filelist']['ignore'])) { + $ignore = isset($instance['filelist']['ignore'][0]) ? + $instance['filelist']['ignore'] : + array($instance['filelist']['ignore']); + foreach ($ignore as $ig) { + unset ($contents[$ig['attribs']['name']]); + } } - $savedir = $this->_curdir; - if (isset($value['attribs'])) { - if ($value['attribs']['name'] == '/') { - $this->_curdir = '/'; - } else { - $this->_curdir .= '/' . $value['attribs']['name']; + // install files as this name + if (isset($instance['filelist']['install'])) { + $installas = isset($instance['filelist']['install'][0]) ? + $instance['filelist']['install'] : + array($instance['filelist']['install']); + foreach ($installas as $as) { + $contents[$as['attribs']['name']]['attribs']['install-as'] = + $as['attribs']['as']; } } } - - if (is_string($value) && $value && ($value{strlen($value) - 1} == "\n")) { - $value .= str_repeat($this->options['indent'], $this->_tagDepth); - } - $tmp .= $this->_createXMLTag(array( - 'qname' => $key, - 'attributes' => $atts, - 'content' => $value ) - ); - if ($this->options['beautifyFilelist'] && $key == 'dir') { - if (isset($value['attribs'])) { - $tmp .= ' '; - if (empty($savedir)) { - unset($this->_curdir); - } else { - $this->_curdir = $savedir; - } + if ($forfilecheck) { + foreach ($contents as $file => $attrs) { + $contents[$file] = $attrs['attribs']; } } - $tmp .= $this->options['linebreak']; - } - - $this->_tagDepth--; - if ($this->options['indent']!==null && $this->_tagDepth>0) { - $tmp .= str_repeat($this->options['indent'], $this->_tagDepth); - } - - if (trim($tmp) === '') { - $tmp = null; + return $contents; } - - $tag = array( - 'qname' => $tagName, - 'content' => $tmp, - 'attributes' => $attributes - ); - } - if ($this->options['typeHints'] === true) { - if (!isset($tag['attributes'][$this->options['typeAttribute']])) { - $tag['attributes'][$this->options['typeAttribute']] = 'array'; + } else { // simple release - no installconditions or install-as + if ($forfilecheck) { + return $this->getFilelist(); } + return $contents; } - - $string = $this->_createXMLTag($tag, false); - return $string; + // no releases matched + return PEAR::raiseError('No releases in package.xml matched the existing operating ' . + 'system, extensions installed, or architecture, cannot install'); } - /** - * create a tag from an array - * this method awaits an array in the following format - * array( - * 'qname' => $tagName, - * 'attributes' => array(), - * 'content' => $content, // optional - * 'namespace' => $namespace // optional - * 'namespaceUri' => $namespaceUri // optional - * ) - * - * @access private - * @param array $tag tag definition - * @param boolean $replaceEntities whether to replace XML entities in content or not - * @return string $string XML tag - */ - function _createXMLTag($tag, $replaceEntities = true) + /** + * This is only used at install-time, after all serialization + * is over. + * @param string file name + * @param string installed path + */ + function setInstalledAs($file, $path) { - if ($this->options['indentAttributes'] !== false) { - $multiline = true; - $indent = str_repeat($this->options['indent'], $this->_tagDepth); + if ($path) { + return $this->_packageInfo['filelist'][$file]['installed_as'] = $path; + } + unset($this->_packageInfo['filelist'][$file]['installed_as']); + } - if ($this->options['indentAttributes'] == '_auto') { - $indent .= str_repeat(' ', (strlen($tag['qname'])+2)); + function getInstalledLocation($file) + { + if (isset($this->_packageInfo['filelist'][$file]['installed_as'])) { + return $this->_packageInfo['filelist'][$file]['installed_as']; + } + return false; + } - } else { - $indent .= $this->options['indentAttributes']; - } + /** + * This is only used at install-time, after all serialization + * is over. + */ + function installedFile($file, $atts) + { + if (isset($this->_packageInfo['filelist'][$file])) { + $this->_packageInfo['filelist'][$file] = + array_merge($this->_packageInfo['filelist'][$file], $atts['attribs']); } else { - $indent = $multiline = false; + $this->_packageInfo['filelist'][$file] = $atts['attribs']; } + } - if (is_array($tag['content'])) { - if (empty($tag['content'])) { - $tag['content'] = ''; - } - } elseif(is_scalar($tag['content']) && (string)$tag['content'] == '') { - $tag['content'] = ''; + /** + * Retrieve the contents tag + */ + function getContents() + { + if (isset($this->_packageInfo['contents'])) { + return $this->_packageInfo['contents']; } + return false; + } - if (is_scalar($tag['content']) || is_null($tag['content'])) { - if ($this->options['encoding'] == 'UTF-8' && - version_compare(phpversion(), '5.0.0', 'lt') - ) { - $tag = utf8_encode($tag); - } - - if ($replaceEntities === true) { - $replaceEntities = XML_UTIL_ENTITIES_XML; + /** + * @param string full path to file + * @param string attribute name + * @param string attribute value + * @param int risky but fast - use this to choose a file based on its position in the list + * of files. Index is zero-based like PHP arrays. + * @return bool success of operation + */ + function setFileAttribute($filename, $attr, $value, $index = false) + { + $this->_isValid = 0; + if (in_array($attr, array('role', 'name', 'baseinstalldir'))) { + $this->_filesValid = false; + } + if ($index !== false && + isset($this->_packageInfo['contents']['dir']['file'][$index]['attribs'])) { + $this->_packageInfo['contents']['dir']['file'][$index]['attribs'][$attr] = $value; + return true; + } + if (!isset($this->_packageInfo['contents']['dir']['file'])) { + return false; + } + $files = $this->_packageInfo['contents']['dir']['file']; + if (!isset($files[0])) { + $files = array($files); + $ind = false; + } else { + $ind = true; + } + foreach ($files as $i => $file) { + if (isset($file['attribs'])) { + if ($file['attribs']['name'] == $filename) { + if ($ind) { + $this->_packageInfo['contents']['dir']['file'][$i]['attribs'][$attr] = $value; + } else { + $this->_packageInfo['contents']['dir']['file']['attribs'][$attr] = $value; + } + return true; + } } - - $tag = XML_Util::createTagFromArray($tag, $replaceEntities, $multiline, $indent, $this->options['linebreak']); - } elseif (is_array($tag['content'])) { - $tag = $this->_serializeArray($tag['content'], $tag['qname'], $tag['attributes']); - } elseif (is_object($tag['content'])) { - $tag = $this->_serializeObject($tag['content'], $tag['qname'], $tag['attributes']); - } elseif (is_resource($tag['content'])) { - settype($tag['content'], 'string'); - $tag = XML_Util::createTagFromArray($tag, $replaceEntities); } - return $tag; + return false; } -} - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: v1.php,v 1.30 2009/02/24 23:45:22 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * package.xml abstraction class - */ -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/v1.php'; -/** - * Parser for package.xml version 1.0 - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_PackageFile_Parser_v1 -{ - var $_registry; - var $_config; - var $_logger; - /** - * BC hack to allow PEAR_Common::infoFromString() to sort of - * work with the version 2.0 format - there's no filelist though - * @param PEAR_PackageFile_v2 - */ - function fromV2($packagefile) + + function setDirtree($path) { - $info = $packagefile->getArray(true); - $ret = new PEAR_PackageFile_v1; - $ret->fromArray($info['old']); + if (!isset($this->_packageInfo['dirtree'])) { + $this->_packageInfo['dirtree'] = array(); + } + $this->_packageInfo['dirtree'][$path] = true; } - function setConfig(&$c) + function getDirtree() { - $this->_config = &$c; - $this->_registry = &$c->getRegistry(); + if (isset($this->_packageInfo['dirtree']) && count($this->_packageInfo['dirtree'])) { + return $this->_packageInfo['dirtree']; + } + return false; } - function setLogger(&$l) + function resetDirtree() { - $this->_logger = &$l; + unset($this->_packageInfo['dirtree']); } /** - * @param string contents of package.xml file, version 1.0 - * @return bool success of parsing + * Determines whether this package claims it is compatible with the version of + * the package that has a recommended version dependency + * @param PEAR_PackageFile_v2|PEAR_PackageFile_v1|PEAR_Downloader_Package + * @return boolean */ - function &parse($data, $file, $archive = false) + function isCompatible($pf) { - if (!extension_loaded('xml')) { - return PEAR::raiseError('Cannot create xml parser for parsing package.xml, no xml extension'); + if (!isset($this->_packageInfo['compatible'])) { + return false; } - $xp = xml_parser_create(); - if (!$xp) { - $a = &PEAR::raiseError('Cannot create xml parser for parsing package.xml'); - return $a; + if (!isset($this->_packageInfo['channel'])) { + return false; } - xml_set_object($xp, $this); - xml_set_element_handler($xp, '_element_start_1_0', '_element_end_1_0'); - xml_set_character_data_handler($xp, '_pkginfo_cdata_1_0'); - xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, false); - - $this->element_stack = array(); - $this->_packageInfo = array('provides' => array()); - $this->current_element = false; - unset($this->dir_install); - $this->_packageInfo['filelist'] = array(); - $this->filelist =& $this->_packageInfo['filelist']; - $this->dir_names = array(); - $this->in_changelog = false; - $this->d_i = 0; - $this->cdata = ''; - $this->_isValid = true; - - if (!xml_parse($xp, $data, 1)) { - $code = xml_get_error_code($xp); - $line = xml_get_current_line_number($xp); - xml_parser_free($xp); - $a = &PEAR::raiseError(sprintf("XML error: %s at line %d", - $str = xml_error_string($code), $line), 2); - return $a; + $me = $pf->getVersion(); + $compatible = $this->_packageInfo['compatible']; + if (!isset($compatible[0])) { + $compatible = array($compatible); } - - xml_parser_free($xp); - - $pf = new PEAR_PackageFile_v1; - $pf->setConfig($this->_config); - if (isset($this->_logger)) { - $pf->setLogger($this->_logger); + $found = false; + foreach ($compatible as $info) { + if (strtolower($info['name']) == strtolower($pf->getPackage())) { + if (strtolower($info['channel']) == strtolower($pf->getChannel())) { + $found = true; + break; + } + } } - $pf->setPackagefile($file, $archive); - $pf->fromArray($this->_packageInfo); - return $pf; + if (!$found) { + return false; + } + if (isset($info['exclude'])) { + if (!isset($info['exclude'][0])) { + $info['exclude'] = array($info['exclude']); + } + foreach ($info['exclude'] as $exclude) { + if (version_compare($me, $exclude, '==')) { + return false; + } + } + } + if (version_compare($me, $info['min'], '>=') && version_compare($me, $info['max'], '<=')) { + return true; + } + return false; } - // {{{ _unIndent() /** - * Unindent given string - * - * @param string $str The string that has to be unindented. - * @return string - * @access private + * @return array|false */ - function _unIndent($str) + function getCompatible() { - // remove leading newlines - $str = preg_replace('/^[\r\n]+/', '', $str); - // find whitespace at the beginning of the first line - $indent_len = strspn($str, " \t"); - $indent = substr($str, 0, $indent_len); - $data = ''; - // remove the same amount of whitespace from following lines - foreach (explode("\n", $str) as $line) { - if (substr($line, 0, $indent_len) == $indent) { - $data .= substr($line, $indent_len) . "\n"; - } elseif (trim(substr($line, 0, $indent_len))) { - $data .= ltrim($line); - } + if (isset($this->_packageInfo['compatible'])) { + return $this->_packageInfo['compatible']; } - return $data; + return false; + } + + function getDependencies() + { + if (isset($this->_packageInfo['dependencies'])) { + return $this->_packageInfo['dependencies']; + } + return false; } - // Support for package DTD v1.0: - // {{{ _element_start_1_0() + function isSubpackageOf($p) + { + return $p->isSubpackage($this); + } /** - * XML parser callback for ending elements. Used for version 1.0 - * packages. - * - * @param resource $xp XML parser resource - * @param string $name name of ending element - * - * @return void + * Determines whether the passed in package is a subpackage of this package. * - * @access private + * No version checking is done, only name verification. + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @return bool */ - function _element_start_1_0($xp, $name, $attribs) + function isSubpackage($p) { - array_push($this->element_stack, $name); - $this->current_element = $name; - $spos = sizeof($this->element_stack) - 2; - $this->prev_element = ($spos >= 0) ? $this->element_stack[$spos] : ''; - $this->current_attributes = $attribs; - $this->cdata = ''; - switch ($name) { - case 'dir': - if ($this->in_changelog) { - break; + $sub = array(); + if (isset($this->_packageInfo['dependencies']['required']['subpackage'])) { + $sub = $this->_packageInfo['dependencies']['required']['subpackage']; + if (!isset($sub[0])) { + $sub = array($sub); + } + } + if (isset($this->_packageInfo['dependencies']['optional']['subpackage'])) { + $sub1 = $this->_packageInfo['dependencies']['optional']['subpackage']; + if (!isset($sub1[0])) { + $sub1 = array($sub1); + } + $sub = array_merge($sub, $sub1); + } + if (isset($this->_packageInfo['dependencies']['group'])) { + $group = $this->_packageInfo['dependencies']['group']; + if (!isset($group[0])) { + $group = array($group); + } + foreach ($group as $deps) { + if (isset($deps['subpackage'])) { + $sub2 = $deps['subpackage']; + if (!isset($sub2[0])) { + $sub2 = array($sub2); + } + $sub = array_merge($sub, $sub2); } - if (array_key_exists('name', $attribs) && $attribs['name'] != '/') { - $attribs['name'] = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), - $attribs['name']); - if (strrpos($attribs['name'], '/') === strlen($attribs['name']) - 1) { - $attribs['name'] = substr($attribs['name'], 0, - strlen($attribs['name']) - 1); + } + } + foreach ($sub as $dep) { + if (strtolower($dep['name']) == strtolower($p->getPackage())) { + if (isset($dep['channel'])) { + if (strtolower($dep['channel']) == strtolower($p->getChannel())) { + return true; } - if (strpos($attribs['name'], '/') === 0) { - $attribs['name'] = substr($attribs['name'], 1); + } else { + if ($dep['uri'] == $p->getURI()) { + return true; } - $this->dir_names[] = $attribs['name']; - } - if (isset($attribs['baseinstalldir'])) { - $this->dir_install = $attribs['baseinstalldir']; - } - if (isset($attribs['role'])) { - $this->dir_role = $attribs['role']; - } - break; - case 'file': - if ($this->in_changelog) { - break; } - if (isset($attribs['name'])) { - $path = ''; - if (count($this->dir_names)) { - foreach ($this->dir_names as $dir) { - $path .= $dir . '/'; - } - } - $path .= preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), - $attribs['name']); - unset($attribs['name']); - $this->current_path = $path; - $this->filelist[$path] = $attribs; - // Set the baseinstalldir only if the file don't have this attrib - if (!isset($this->filelist[$path]['baseinstalldir']) && - isset($this->dir_install)) - { - $this->filelist[$path]['baseinstalldir'] = $this->dir_install; + } + } + return false; + } + + function dependsOn($package, $channel) + { + if (!($deps = $this->getDependencies())) { + return false; + } + foreach (array('package', 'subpackage') as $type) { + foreach (array('required', 'optional') as $needed) { + if (isset($deps[$needed][$type])) { + if (!isset($deps[$needed][$type][0])) { + $deps[$needed][$type] = array($deps[$needed][$type]); } - // Set the Role - if (!isset($this->filelist[$path]['role']) && isset($this->dir_role)) { - $this->filelist[$path]['role'] = $this->dir_role; + foreach ($deps[$needed][$type] as $dep) { + $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri'; + if (strtolower($dep['name']) == strtolower($package) && + $depchannel == $channel) { + return true; + } } } - break; - case 'replace': - if (!$this->in_changelog) { - $this->filelist[$this->current_path]['replacements'][] = $attribs; - } - break; - case 'maintainers': - $this->_packageInfo['maintainers'] = array(); - $this->m_i = 0; // maintainers array index - break; - case 'maintainer': - // compatibility check - if (!isset($this->_packageInfo['maintainers'])) { - $this->_packageInfo['maintainers'] = array(); - $this->m_i = 0; - } - $this->_packageInfo['maintainers'][$this->m_i] = array(); - $this->current_maintainer =& $this->_packageInfo['maintainers'][$this->m_i]; - break; - case 'changelog': - $this->_packageInfo['changelog'] = array(); - $this->c_i = 0; // changelog array index - $this->in_changelog = true; - break; - case 'release': - if ($this->in_changelog) { - $this->_packageInfo['changelog'][$this->c_i] = array(); - $this->current_release = &$this->_packageInfo['changelog'][$this->c_i]; - } else { - $this->current_release = &$this->_packageInfo; - } - break; - case 'deps': - if (!$this->in_changelog) { - $this->_packageInfo['release_deps'] = array(); - } - break; - case 'dep': - // dependencies array index - if (!$this->in_changelog) { - $this->d_i++; - isset($attribs['type']) ? ($attribs['type'] = strtolower($attribs['type'])) : false; - $this->_packageInfo['release_deps'][$this->d_i] = $attribs; - } - break; - case 'configureoptions': - if (!$this->in_changelog) { - $this->_packageInfo['configure_options'] = array(); - } - break; - case 'configureoption': - if (!$this->in_changelog) { - $this->_packageInfo['configure_options'][] = $attribs; - } - break; - case 'provides': - if (empty($attribs['type']) || empty($attribs['name'])) { - break; - } - $attribs['explicit'] = true; - $this->_packageInfo['provides']["$attribs[type];$attribs[name]"] = $attribs; - break; - case 'package' : - if (isset($attribs['version'])) { - $this->_packageInfo['xsdversion'] = trim($attribs['version']); - } else { - $this->_packageInfo['xsdversion'] = '1.0'; + } + if (isset($deps['group'])) { + if (!isset($deps['group'][0])) { + $dep['group'] = array($deps['group']); } - if (isset($attribs['packagerversion'])) { - $this->_packageInfo['packagerversion'] = $attribs['packagerversion']; + foreach ($deps['group'] as $group) { + if (isset($group[$type])) { + if (!is_array($group[$type])) { + $group[$type] = array($group[$type]); + } + foreach ($group[$type] as $dep) { + $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri'; + if (strtolower($dep['name']) == strtolower($package) && + $depchannel == $channel) { + return true; + } + } + } } - break; + } } + return false; } - // }}} - // {{{ _element_end_1_0() + /** + * Get the contents of a dependency group + * @param string + * @return array|false + */ + function getDependencyGroup($name) + { + $name = strtolower($name); + if (!isset($this->_packageInfo['dependencies']['group'])) { + return false; + } + $groups = $this->_packageInfo['dependencies']['group']; + if (!isset($groups[0])) { + $groups = array($groups); + } + foreach ($groups as $group) { + if (strtolower($group['attribs']['name']) == $name) { + return $group; + } + } + return false; + } /** - * XML parser callback for ending elements. Used for version 1.0 - * packages. - * - * @param resource $xp XML parser resource - * @param string $name name of ending element - * - * @return void + * Retrieve a partial package.xml 1.0 representation of dependencies * - * @access private + * a very limited representation of dependencies is returned by this method. + * The tag for excluding certain versions of a dependency is + * completely ignored. In addition, dependency groups are ignored, with the + * assumption that all dependencies in dependency groups are also listed in + * the optional group that work with all dependency groups + * @param boolean return package.xml 2.0 tag + * @return array|false */ - function _element_end_1_0($xp, $name) + function getDeps($raw = false, $nopearinstaller = false) { - $data = trim($this->cdata); - switch ($name) { - case 'name': - switch ($this->prev_element) { - case 'package': - $this->_packageInfo['package'] = $data; - break; - case 'maintainer': - $this->current_maintainer['name'] = $data; - break; - } - break; - case 'extends' : - $this->_packageInfo['extends'] = $data; - break; - case 'summary': - $this->_packageInfo['summary'] = $data; - break; - case 'description': - $data = $this->_unIndent($this->cdata); - $this->_packageInfo['description'] = $data; - break; - case 'user': - $this->current_maintainer['handle'] = $data; - break; - case 'email': - $this->current_maintainer['email'] = $data; - break; - case 'role': - $this->current_maintainer['role'] = $data; - break; - case 'version': - if ($this->in_changelog) { - $this->current_release['version'] = $data; - } else { - $this->_packageInfo['version'] = $data; - } - break; - case 'date': - if ($this->in_changelog) { - $this->current_release['release_date'] = $data; - } else { - $this->_packageInfo['release_date'] = $data; - } - break; - case 'notes': - // try to "de-indent" release notes in case someone - // has been over-indenting their xml ;-) - // Trim only on the right side - $data = rtrim($this->_unIndent($this->cdata)); - if ($this->in_changelog) { - $this->current_release['release_notes'] = $data; - } else { - $this->_packageInfo['release_notes'] = $data; - } - break; - case 'warnings': - if ($this->in_changelog) { - $this->current_release['release_warnings'] = $data; - } else { - $this->_packageInfo['release_warnings'] = $data; - } - break; - case 'state': - if ($this->in_changelog) { - $this->current_release['release_state'] = $data; - } else { - $this->_packageInfo['release_state'] = $data; - } - break; - case 'license': - if ($this->in_changelog) { - $this->current_release['release_license'] = $data; - } else { - $this->_packageInfo['release_license'] = $data; - } - break; - case 'dep': - if ($data && !$this->in_changelog) { - $this->_packageInfo['release_deps'][$this->d_i]['name'] = $data; - } - break; - case 'dir': - if ($this->in_changelog) { - break; - } - array_pop($this->dir_names); - break; - case 'file': - if ($this->in_changelog) { - break; + if (isset($this->_packageInfo['dependencies'])) { + if ($raw) { + return $this->_packageInfo['dependencies']; + } + $ret = array(); + $map = array( + 'php' => 'php', + 'package' => 'pkg', + 'subpackage' => 'pkg', + 'extension' => 'ext', + 'os' => 'os', + 'pearinstaller' => 'pkg', + ); + foreach (array('required', 'optional') as $type) { + $optional = ($type == 'optional') ? 'yes' : 'no'; + if (!isset($this->_packageInfo['dependencies'][$type]) + || empty($this->_packageInfo['dependencies'][$type])) { + continue; } - if ($data) { - $path = ''; - if (count($this->dir_names)) { - foreach ($this->dir_names as $dir) { - $path .= $dir . '/'; - } + foreach ($this->_packageInfo['dependencies'][$type] as $dtype => $deps) { + if ($dtype == 'pearinstaller' && $nopearinstaller) { + continue; } - $path .= $data; - $this->filelist[$path] = $this->current_attributes; - // Set the baseinstalldir only if the file don't have this attrib - if (!isset($this->filelist[$path]['baseinstalldir']) && - isset($this->dir_install)) - { - $this->filelist[$path]['baseinstalldir'] = $this->dir_install; + if (!isset($deps[0])) { + $deps = array($deps); } - // Set the Role - if (!isset($this->filelist[$path]['role']) && isset($this->dir_role)) { - $this->filelist[$path]['role'] = $this->dir_role; + foreach ($deps as $dep) { + if (!isset($map[$dtype])) { + // no support for arch type + continue; + } + if ($dtype == 'pearinstaller') { + $dep['name'] = 'PEAR'; + $dep['channel'] = 'pear.php.net'; + } + $s = array('type' => $map[$dtype]); + if (isset($dep['channel'])) { + $s['channel'] = $dep['channel']; + } + if (isset($dep['uri'])) { + $s['uri'] = $dep['uri']; + } + if (isset($dep['name'])) { + $s['name'] = $dep['name']; + } + if (isset($dep['conflicts'])) { + $s['rel'] = 'not'; + } else { + if (!isset($dep['min']) && + !isset($dep['max'])) { + $s['rel'] = 'has'; + $s['optional'] = $optional; + } elseif (isset($dep['min']) && + isset($dep['max'])) { + $s['rel'] = 'ge'; + $s1 = $s; + $s1['rel'] = 'le'; + $s['version'] = $dep['min']; + $s1['version'] = $dep['max']; + if (isset($dep['channel'])) { + $s1['channel'] = $dep['channel']; + } + if ($dtype != 'php') { + $s['name'] = $dep['name']; + $s1['name'] = $dep['name']; + } + $s['optional'] = $optional; + $s1['optional'] = $optional; + $ret[] = $s1; + } elseif (isset($dep['min'])) { + if (isset($dep['exclude']) && + $dep['exclude'] == $dep['min']) { + $s['rel'] = 'gt'; + } else { + $s['rel'] = 'ge'; + } + $s['version'] = $dep['min']; + $s['optional'] = $optional; + if ($dtype != 'php') { + $s['name'] = $dep['name']; + } + } elseif (isset($dep['max'])) { + if (isset($dep['exclude']) && + $dep['exclude'] == $dep['max']) { + $s['rel'] = 'lt'; + } else { + $s['rel'] = 'le'; + } + $s['version'] = $dep['max']; + $s['optional'] = $optional; + if ($dtype != 'php') { + $s['name'] = $dep['name']; + } + } + } + $ret[] = $s; } } - break; - case 'maintainer': - if (empty($this->_packageInfo['maintainers'][$this->m_i]['role'])) { - $this->_packageInfo['maintainers'][$this->m_i]['role'] = 'lead'; - } - $this->m_i++; - break; - case 'release': - if ($this->in_changelog) { - $this->c_i++; - } - break; - case 'changelog': - $this->in_changelog = false; - break; + } + if (count($ret)) { + return $ret; + } + } + return false; + } + + /** + * @return php|extsrc|extbin|zendextsrc|zendextbin|bundle|false + */ + function getPackageType() + { + if (isset($this->_packageInfo['phprelease'])) { + return 'php'; + } + if (isset($this->_packageInfo['extsrcrelease'])) { + return 'extsrc'; + } + if (isset($this->_packageInfo['extbinrelease'])) { + return 'extbin'; + } + if (isset($this->_packageInfo['zendextsrcrelease'])) { + return 'zendextsrc'; + } + if (isset($this->_packageInfo['zendextbinrelease'])) { + return 'zendextbin'; + } + if (isset($this->_packageInfo['bundle'])) { + return 'bundle'; + } + return false; + } + + /** + * @return array|false + */ + function getReleases() + { + $type = $this->getPackageType(); + if ($type != 'bundle') { + $type .= 'release'; } - array_pop($this->element_stack); - $spos = sizeof($this->element_stack) - 1; - $this->current_element = ($spos > 0) ? $this->element_stack[$spos] : ''; - $this->cdata = ''; + if ($this->getPackageType() && isset($this->_packageInfo[$type])) { + return $this->_packageInfo[$type]; + } + return false; } - // }}} - // {{{ _pkginfo_cdata_1_0() - /** - * XML parser callback for character data. Used for version 1.0 - * packages. - * - * @param resource $xp XML parser resource - * @param string $name character data - * - * @return void - * - * @access private + * @return array */ - function _pkginfo_cdata_1_0($xp, $data) + function getChangelog() { - if (isset($this->cdata)) { - $this->cdata .= $data; + if (isset($this->_packageInfo['changelog'])) { + return $this->_packageInfo['changelog']; } + return false; } - // }}} -} -?> - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: v2.php,v 1.24 2009/02/24 23:45:22 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * base xml parser class - */ -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/XMLParser.php'; -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/v2.php'; -/** - * Parser for package.xml version 2.0 - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_PackageFile_Parser_v2 extends PEAR_XMLParser -{ - var $_config; - var $_logger; - var $_registry; + function hasDeps() + { + return isset($this->_packageInfo['dependencies']); + } - function setConfig(&$c) + function getPackagexmlVersion() { - $this->_config = &$c; - $this->_registry = &$c->getRegistry(); + if (isset($this->_packageInfo['zendextsrcrelease'])) { + return '2.1'; + } + if (isset($this->_packageInfo['zendextbinrelease'])) { + return '2.1'; + } + return '2.0'; } - function setLogger(&$l) + /** + * @return array|false + */ + function getSourcePackage() { - $this->_logger = &$l; + if (isset($this->_packageInfo['extbinrelease']) || + isset($this->_packageInfo['zendextbinrelease'])) { + return array('channel' => $this->_packageInfo['srcchannel'], + 'package' => $this->_packageInfo['srcpackage']); + } + return false; + } + + function getBundledPackages() + { + if (isset($this->_packageInfo['bundle'])) { + return $this->_packageInfo['contents']['bundledpackage']; + } + return false; + } + + function getLastModified() + { + if (isset($this->_packageInfo['_lastmodified'])) { + return $this->_packageInfo['_lastmodified']; + } + return false; } + /** - * Unindent given string - * - * @param string $str The string that has to be unindented. + * Get the contents of a file listed within the package.xml + * @param string * @return string - * @access private */ - function _unIndent($str) + function getFileContents($file) { - // remove leading newlines - $str = preg_replace('/^[\r\n]+/', '', $str); - // find whitespace at the beginning of the first line - $indent_len = strspn($str, " \t"); - $indent = substr($str, 0, $indent_len); - $data = ''; - // remove the same amount of whitespace from following lines - foreach (explode("\n", $str) as $line) { - if (substr($line, 0, $indent_len) == $indent) { - $data .= substr($line, $indent_len) . "\n"; + if ($this->_archiveFile == $this->_packageFile) { // unpacked + $dir = dirname($this->_packageFile); + $file = $dir . DIRECTORY_SEPARATOR . $file; + $file = str_replace(array('/', '\\'), + array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), $file); + if (file_exists($file) && is_readable($file)) { + return implode('', file($file)); + } + } else { // tgz + $tar = &new Archive_Tar($this->_archiveFile); + $tar->pushErrorHandling(PEAR_ERROR_RETURN); + if ($file != 'package.xml' && $file != 'package2.xml') { + $file = $this->getPackage() . '-' . $this->getVersion() . '/' . $file; + } + $file = $tar->extractInString($file); + $tar->popErrorHandling(); + if (PEAR::isError($file)) { + return PEAR::raiseError("Cannot locate file '$file' in archive"); + } + return $file; + } + } + + function &getRW() + { + if (!class_exists('PEAR_PackageFile_v2_rw')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/v2/rw.php'; + } + $a = new PEAR_PackageFile_v2_rw; + foreach (get_object_vars($this) as $name => $unused) { + if (!isset($this->$name)) { + continue; + } + if ($name == '_config' || $name == '_logger'|| $name == '_registry' || + $name == '_stack') { + $a->$name = &$this->$name; } else { - $data .= $line . "\n"; + $a->$name = $this->$name; } } - return $data; + return $a; + } + + function &getDefaultGenerator() + { + if (!class_exists('PEAR_PackageFile_Generator_v2')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/Generator/v2.php'; + } + $a = &new PEAR_PackageFile_Generator_v2($this); + return $a; + } + + function analyzeSourceCode($file, $string = false) + { + if (!isset($this->_v2Validator) || + !is_a($this->_v2Validator, 'PEAR_PackageFile_v2_Validator')) { + if (!class_exists('PEAR_PackageFile_v2_Validator')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/v2/Validator.php'; + } + $this->_v2Validator = new PEAR_PackageFile_v2_Validator; + } + return $this->_v2Validator->analyzeSourceCode($file, $string); + } + + function validate($state = PEAR_VALIDATE_NORMAL) + { + if (!isset($this->_packageInfo) || !is_array($this->_packageInfo)) { + return false; + } + if (!isset($this->_v2Validator) || + !is_a($this->_v2Validator, 'PEAR_PackageFile_v2_Validator')) { + if (!class_exists('PEAR_PackageFile_v2_Validator')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/v2/Validator.php'; + } + $this->_v2Validator = new PEAR_PackageFile_v2_Validator; + } + if (isset($this->_packageInfo['xsdversion'])) { + unset($this->_packageInfo['xsdversion']); + } + return $this->_v2Validator->validate($this, $state); + } + + function getTasksNs() + { + if (!isset($this->_tasksNs)) { + if (isset($this->_packageInfo['attribs'])) { + foreach ($this->_packageInfo['attribs'] as $name => $value) { + if ($value == 'http://pear.php.net/dtd/tasks-1.0') { + $this->_tasksNs = str_replace('xmlns:', '', $name); + break; + } + } + } + } + return $this->_tasksNs; } /** - * post-process data + * Determine whether a task name is a valid task. Custom tasks may be defined + * using subdirectories by putting a "-" in the name, as in * - * @param string $data - * @param string $element element name + * Note that this method will auto-load the task class file and test for the existence + * of the name with "-" replaced by "_" as in PEAR/Task/mycustom/task.php makes class + * PEAR_Task_mycustom_task + * @param string + * @return boolean */ - function postProcess($data, $element) + function getTask($task) { - if ($element == 'notes') { - return trim($this->_unIndent($data)); + $this->getTasksNs(); + // transform all '-' to '/' and 'tasks:' to '' so tasks:replace becomes replace + $task = str_replace(array($this->_tasksNs . ':', '-'), array('', ' '), $task); + $taskfile = str_replace(' ', '/', ucwords($task)); + $task = str_replace(array(' ', '/'), '_', ucwords($task)); + if (class_exists("PEAR_Task_$task")) { + return "PEAR_Task_$task"; } - return trim($data); + $fp = @fopen("phar://install-pear-nozlib.phar/PEAR/Task/$taskfile.php", 'r', true); + if ($fp) { + fclose($fp); + require_once 'phar://install-pear-nozlib.phar/' . "PEAR/Task/$taskfile.php"; + return "PEAR_Task_$task"; + } + return false; } /** - * @param string - * @param string file name of the package.xml - * @param string|false name of the archive this package.xml came from, if any - * @param string class name to instantiate and return. This must be PEAR_PackageFile_v2 or - * a subclass - * @return PEAR_PackageFile_v2 + * Key-friendly array_splice + * @param tagname to splice a value in before + * @param mixed the value to splice in + * @param string the new tag name */ - function &parse($data, $file, $archive = false, $class = 'PEAR_PackageFile_v2') + function _ksplice($array, $key, $value, $newkey) { - if (PEAR::isError($err = parent::parse($data, $file))) { - return $err; - } + $offset = array_search($key, array_keys($array)); + $after = array_slice($array, $offset); + $before = array_slice($array, 0, $offset); + $before[$newkey] = $value; + return array_merge($before, $after); + } - $ret = new $class; - $ret->encoding = $this->encoding; - $ret->setConfig($this->_config); - if (isset($this->_logger)) { - $ret->setLogger($this->_logger); + /** + * @param array a list of possible keys, in the order they may occur + * @param mixed contents of the new package.xml tag + * @param string tag name + * @access private + */ + function _insertBefore($array, $keys, $contents, $newkey) + { + foreach ($keys as $key) { + if (isset($array[$key])) { + return $array = $this->_ksplice($array, $key, $contents, $newkey); + } } + $array[$newkey] = $contents; + return $array; + } - $ret->fromArray($this->_unserializedData); - $ret->setPackagefile($file, $archive); - return $ret; + /** + * @param subsection of {@link $_packageInfo} + * @param array|string tag contents + * @param array format: + *
+     * array(
+     *   tagname => array(list of tag names that follow this one),
+     *   childtagname => array(list of child tag names that follow this one),
+     * )
+     * 
+ * + * This allows construction of nested tags + * @access private + */ + function _mergeTag($manip, $contents, $order) + { + if (count($order)) { + foreach ($order as $tag => $curorder) { + if (!isset($manip[$tag])) { + // ensure that the tag is set up + $manip = $this->_insertBefore($manip, $curorder, array(), $tag); + } + if (count($order) > 1) { + $manip[$tag] = $this->_mergeTag($manip[$tag], $contents, array_slice($order, 1)); + return $manip; + } + } + } else { + return $manip; + } + if (is_array($manip[$tag]) && !empty($manip[$tag]) && isset($manip[$tag][0])) { + $manip[$tag][] = $contents; + } else { + if (!count($manip[$tag])) { + $manip[$tag] = $contents; + } else { + $manip[$tag] = array($manip[$tag]); + $manip[$tag][] = $contents; + } + } + return $manip; } -} - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: v1.php,v 1.75 2009/02/24 23:39:16 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * For error handling - */ -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/ErrorStack.php'; - -/** - * Error code if parsing is attempted with no xml extension - */ -define('PEAR_PACKAGEFILE_ERROR_NO_XML_EXT', 3); - -/** - * Error code if creating the xml parser resource fails - */ -define('PEAR_PACKAGEFILE_ERROR_CANT_MAKE_PARSER', 4); - -/** - * Error code used for all sax xml parsing errors - */ -define('PEAR_PACKAGEFILE_ERROR_PARSER_ERROR', 5); - -/** - * Error code used when there is no name - */ -define('PEAR_PACKAGEFILE_ERROR_NO_NAME', 6); - -/** - * Error code when a package name is not valid - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_NAME', 7); - -/** - * Error code used when no summary is parsed - */ -define('PEAR_PACKAGEFILE_ERROR_NO_SUMMARY', 8); - -/** - * Error code for summaries that are more than 1 line - */ -define('PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY', 9); - -/** - * Error code used when no description is present - */ -define('PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION', 10); - -/** - * Error code used when no license is present - */ -define('PEAR_PACKAGEFILE_ERROR_NO_LICENSE', 11); - -/** - * Error code used when a version number is not present - */ -define('PEAR_PACKAGEFILE_ERROR_NO_VERSION', 12); - -/** - * Error code used when a version number is invalid - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_VERSION', 13); - -/** - * Error code when release state is missing - */ -define('PEAR_PACKAGEFILE_ERROR_NO_STATE', 14); - -/** - * Error code when release state is invalid - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_STATE', 15); - -/** - * Error code when release state is missing - */ -define('PEAR_PACKAGEFILE_ERROR_NO_DATE', 16); - -/** - * Error code when release state is invalid - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_DATE', 17); - -/** - * Error code when no release notes are found - */ -define('PEAR_PACKAGEFILE_ERROR_NO_NOTES', 18); - -/** - * Error code when no maintainers are found - */ -define('PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS', 19); - -/** - * Error code when a maintainer has no handle - */ -define('PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE', 20); - -/** - * Error code when a maintainer has no handle - */ -define('PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE', 21); - -/** - * Error code when a maintainer has no name - */ -define('PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME', 22); - -/** - * Error code when a maintainer has no email - */ -define('PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL', 23); - -/** - * Error code when a maintainer has no handle - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_MAINTROLE', 24); - -/** - * Error code when a dependency is not a PHP dependency, but has no name - */ -define('PEAR_PACKAGEFILE_ERROR_NO_DEPNAME', 25); - -/** - * Error code when a dependency has no type (pkg, php, etc.) - */ -define('PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE', 26); - -/** - * Error code when a dependency has no relation (lt, ge, has, etc.) - */ -define('PEAR_PACKAGEFILE_ERROR_NO_DEPREL', 27); - -/** - * Error code when a dependency is not a 'has' relation, but has no version - */ -define('PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION', 28); - -/** - * Error code when a dependency has an invalid relation - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPREL', 29); - -/** - * Error code when a dependency has an invalid type - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPTYPE', 30); - -/** - * Error code when a dependency has an invalid optional option - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL', 31); - -/** - * Error code when a dependency is a pkg dependency, and has an invalid package name - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPNAME', 32); - -/** - * Error code when a dependency has a channel="foo" attribute, and foo is not a registered channel - */ -define('PEAR_PACKAGEFILE_ERROR_UNKNOWN_DEPCHANNEL', 33); - -/** - * Error code when rel="has" and version attribute is present. - */ -define('PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED', 34); - -/** - * Error code when type="php" and dependency name is present - */ -define('PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED', 35); - -/** - * Error code when a configure option has no name - */ -define('PEAR_PACKAGEFILE_ERROR_NO_CONFNAME', 36); - -/** - * Error code when a configure option has no name - */ -define('PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT', 37); - -/** - * Error code when a file in the filelist has an invalid role - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE', 38); - -/** - * Error code when a file in the filelist has no role - */ -define('PEAR_PACKAGEFILE_ERROR_NO_FILEROLE', 39); - -/** - * Error code when analyzing a php source file that has parse errors - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE', 40); - -/** - * Error code when analyzing a php source file reveals a source element - * without a package name prefix - */ -define('PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX', 41); - -/** - * Error code when an unknown channel is specified - */ -define('PEAR_PACKAGEFILE_ERROR_UNKNOWN_CHANNEL', 42); - -/** - * Error code when no files are found in the filelist - */ -define('PEAR_PACKAGEFILE_ERROR_NO_FILES', 43); - -/** - * Error code when a file is not valid php according to _analyzeSourceCode() - */ -define('PEAR_PACKAGEFILE_ERROR_INVALID_FILE', 44); - -/** - * Error code when the channel validator returns an error or warning - */ -define('PEAR_PACKAGEFILE_ERROR_CHANNELVAL', 45); - -/** - * Error code when a php5 package is packaged in php4 (analysis doesn't work) - */ -define('PEAR_PACKAGEFILE_ERROR_PHP5', 46); - -/** - * Error code when a file is listed in package.xml but does not exist - */ -define('PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND', 47); - -/** - * Error code when a - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_PackageFile_v1 -{ - /** - * @access private - * @var PEAR_ErrorStack - * @access private - */ - var $_stack; - - /** - * A registry object, used to access the package name validation regex for non-standard channels - * @var PEAR_Registry - * @access private - */ - var $_registry; - - /** - * An object that contains a log method that matches PEAR_Common::log's signature - * @var object - * @access private - */ - var $_logger; - - /** - * Parsed package information - * @var array - * @access private - */ - var $_packageInfo; - - /** - * path to package.xml - * @var string - * @access private - */ - var $_packageFile; - - /** - * path to package .tgz or false if this is a local/extracted package.xml - * @var string - * @access private - */ - var $_archiveFile; - - /** - * @var int - * @access private - */ - var $_isValid = 0; - - /** - * Determines whether this packagefile was initialized only with partial package info - * - * If this package file was constructed via parsing REST, it will only contain - * - * - package name - * - channel name - * - dependencies - * @var boolean - * @access private - */ - var $_incomplete = true; - - /** - * @param bool determines whether to return a PEAR_Error object, or use the PEAR_ErrorStack - * @param string Name of Error Stack class to use. - */ - function PEAR_PackageFile_v1() - { - $this->_stack = &new PEAR_ErrorStack('PEAR_PackageFile_v1'); - $this->_stack->setErrorMessageTemplate($this->_getErrorMessage()); - $this->_isValid = 0; - } - - function installBinary($installer) - { - return false; - } - - function isExtension($name) - { - return false; - } - - function setConfig(&$config) - { - $this->_config = &$config; - $this->_registry = &$config->getRegistry(); - } - - function setRequestedGroup() - { - // placeholder - } - - /** - * For saving in the registry. - * - * Set the last version that was installed - * @param string - */ - function setLastInstalledVersion($version) - { - $this->_packageInfo['_lastversion'] = $version; - } - - /** - * @return string|false - */ - function getLastInstalledVersion() - { - if (isset($this->_packageInfo['_lastversion'])) { - return $this->_packageInfo['_lastversion']; - } - return false; - } - - function getInstalledBinary() - { - return false; - } - - function listPostinstallScripts() - { - return false; - } - - function initPostinstallScripts() - { - return false; - } - - function setLogger(&$logger) - { - if ($logger && (!is_object($logger) || !method_exists($logger, 'log'))) { - return PEAR::raiseError('Logger must be compatible with PEAR_Common::log'); - } - $this->_logger = &$logger; - } - - function setPackagefile($file, $archive = false) - { - $this->_packageFile = $file; - $this->_archiveFile = $archive ? $archive : $file; - } - - function getPackageFile() - { - return isset($this->_packageFile) ? $this->_packageFile : false; - } - - function getPackageType() - { - return 'php'; - } - - function getArchiveFile() - { - return $this->_archiveFile; - } - - function packageInfo($field) - { - if (!is_string($field) || empty($field) || - !isset($this->_packageInfo[$field])) { - return false; - } - return $this->_packageInfo[$field]; - } - - function setDirtree($path) - { - if (!isset($this->_packageInfo['dirtree'])) { - $this->_packageInfo['dirtree'] = array(); - } - $this->_packageInfo['dirtree'][$path] = true; - } - - function getDirtree() - { - if (isset($this->_packageInfo['dirtree']) && count($this->_packageInfo['dirtree'])) { - return $this->_packageInfo['dirtree']; - } - return false; - } - - function resetDirtree() - { - unset($this->_packageInfo['dirtree']); - } - - function fromArray($pinfo) - { - $this->_incomplete = false; - $this->_packageInfo = $pinfo; - } - - function isIncomplete() - { - return $this->_incomplete; - } - - function getChannel() - { - return 'pear.php.net'; - } - - function getUri() - { - return false; - } - - function getTime() - { - return false; - } - - function getExtends() - { - if (isset($this->_packageInfo['extends'])) { - return $this->_packageInfo['extends']; - } - return false; - } - - /** - * @return array - */ - function toArray() - { - if (!$this->validate(PEAR_VALIDATE_NORMAL)) { - return false; - } - return $this->getArray(); - } - - function getArray() - { - return $this->_packageInfo; - } - - function getName() - { - return $this->getPackage(); - } - - function getPackage() - { - if (isset($this->_packageInfo['package'])) { - return $this->_packageInfo['package']; - } - return false; - } - - /** - * WARNING - don't use this unless you know what you are doing - */ - function setRawPackage($package) - { - $this->_packageInfo['package'] = $package; - } - - function setPackage($package) - { - $this->_packageInfo['package'] = $package; - $this->_isValid = false; - } - - function getVersion() - { - if (isset($this->_packageInfo['version'])) { - return $this->_packageInfo['version']; - } - return false; - } - - function setVersion($version) - { - $this->_packageInfo['version'] = $version; - $this->_isValid = false; - } - - function clearMaintainers() - { - unset($this->_packageInfo['maintainers']); - } - - function getMaintainers() - { - if (isset($this->_packageInfo['maintainers'])) { - return $this->_packageInfo['maintainers']; - } - return false; - } - - /** - * Adds a new maintainer - no checking of duplicates is performed, use - * updatemaintainer for that purpose. - */ - function addMaintainer($role, $handle, $name, $email) - { - $this->_packageInfo['maintainers'][] = - array('handle' => $handle, 'role' => $role, 'email' => $email, 'name' => $name); - $this->_isValid = false; - } - - function updateMaintainer($role, $handle, $name, $email) - { - $found = false; - if (!isset($this->_packageInfo['maintainers']) || - !is_array($this->_packageInfo['maintainers'])) { - return $this->addMaintainer($role, $handle, $name, $email); - } - foreach ($this->_packageInfo['maintainers'] as $i => $maintainer) { - if ($maintainer['handle'] == $handle) { - $found = $i; - break; - } - } - if ($found !== false) { - unset($this->_packageInfo['maintainers'][$found]); - $this->_packageInfo['maintainers'] = - array_values($this->_packageInfo['maintainers']); - } - $this->addMaintainer($role, $handle, $name, $email); - } - - function deleteMaintainer($handle) - { - $found = false; - foreach ($this->_packageInfo['maintainers'] as $i => $maintainer) { - if ($maintainer['handle'] == $handle) { - $found = $i; - break; - } - } - if ($found !== false) { - unset($this->_packageInfo['maintainers'][$found]); - $this->_packageInfo['maintainers'] = - array_values($this->_packageInfo['maintainers']); - return true; - } - return false; - } - - function getState() - { - if (isset($this->_packageInfo['release_state'])) { - return $this->_packageInfo['release_state']; - } - return false; - } - - function setRawState($state) - { - $this->_packageInfo['release_state'] = $state; - } - - function setState($state) - { - $this->_packageInfo['release_state'] = $state; - $this->_isValid = false; - } - - function getDate() - { - if (isset($this->_packageInfo['release_date'])) { - return $this->_packageInfo['release_date']; - } - return false; - } - - function setDate($date) - { - $this->_packageInfo['release_date'] = $date; - $this->_isValid = false; - } - - function getLicense() - { - if (isset($this->_packageInfo['release_license'])) { - return $this->_packageInfo['release_license']; - } - return false; - } - - function setLicense($date) - { - $this->_packageInfo['release_license'] = $date; - $this->_isValid = false; - } - - function getSummary() - { - if (isset($this->_packageInfo['summary'])) { - return $this->_packageInfo['summary']; - } - return false; - } - - function setSummary($summary) - { - $this->_packageInfo['summary'] = $summary; - $this->_isValid = false; - } - - function getDescription() - { - if (isset($this->_packageInfo['description'])) { - return $this->_packageInfo['description']; - } - return false; - } - - function setDescription($desc) - { - $this->_packageInfo['description'] = $desc; - $this->_isValid = false; - } - - function getNotes() - { - if (isset($this->_packageInfo['release_notes'])) { - return $this->_packageInfo['release_notes']; - } - return false; - } - - function setNotes($notes) - { - $this->_packageInfo['release_notes'] = $notes; - $this->_isValid = false; - } - - function getDeps() - { - if (isset($this->_packageInfo['release_deps'])) { - return $this->_packageInfo['release_deps']; - } - return false; - } - - /** - * Reset dependencies prior to adding new ones - */ - function clearDeps() - { - unset($this->_packageInfo['release_deps']); - } - - function addPhpDep($version, $rel) - { - $this->_isValid = false; - $this->_packageInfo['release_deps'][] = - array('type' => 'php', - 'rel' => $rel, - 'version' => $version); - } - - function addPackageDep($name, $version, $rel, $optional = 'no') - { - $this->_isValid = false; - $dep = - array('type' => 'pkg', - 'name' => $name, - 'rel' => $rel, - 'optional' => $optional); - if ($rel != 'has' && $rel != 'not') { - $dep['version'] = $version; - } - $this->_packageInfo['release_deps'][] = $dep; - } - - function addExtensionDep($name, $version, $rel, $optional = 'no') - { - $this->_isValid = false; - $this->_packageInfo['release_deps'][] = - array('type' => 'ext', - 'name' => $name, - 'rel' => $rel, - 'version' => $version, - 'optional' => $optional); - } - - /** - * WARNING - do not use this function directly unless you know what you're doing - */ - function setDeps($deps) - { - $this->_packageInfo['release_deps'] = $deps; - } - - function hasDeps() - { - return isset($this->_packageInfo['release_deps']) && - count($this->_packageInfo['release_deps']); - } - - function getDependencyGroup($group) - { - return false; - } - - function isCompatible($pf) - { - return false; - } - - function isSubpackageOf($p) - { - return $p->isSubpackage($this); - } - - function isSubpackage($p) - { - return false; - } - - function dependsOn($package, $channel) - { - if (strtolower($channel) != 'pear.php.net') { - return false; - } - if (!($deps = $this->getDeps())) { - return false; - } - foreach ($deps as $dep) { - if ($dep['type'] != 'pkg') { - continue; - } - if (strtolower($dep['name']) == strtolower($package)) { - return true; - } - } - return false; - } - - function getConfigureOptions() - { - if (isset($this->_packageInfo['configure_options'])) { - return $this->_packageInfo['configure_options']; - } - return false; - } - - function hasConfigureOptions() - { - return isset($this->_packageInfo['configure_options']) && - count($this->_packageInfo['configure_options']); - } - - function addConfigureOption($name, $prompt, $default = false) - { - $o = array('name' => $name, 'prompt' => $prompt); - if ($default !== false) { - $o['default'] = $default; - } - if (!isset($this->_packageInfo['configure_options'])) { - $this->_packageInfo['configure_options'] = array(); - } - $this->_packageInfo['configure_options'][] = $o; - } - - function clearConfigureOptions() - { - unset($this->_packageInfo['configure_options']); - } - - function getProvides() - { - if (isset($this->_packageInfo['provides'])) { - return $this->_packageInfo['provides']; - } - return false; - } - - function getProvidesExtension() - { - return false; - } - - function addFile($dir, $file, $attrs) - { - $dir = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), $dir); - if ($dir == '/' || $dir == '') { - $dir = ''; - } else { - $dir .= '/'; - } - $file = $dir . $file; - $file = preg_replace('![\\/]+!', '/', $file); - $this->_packageInfo['filelist'][$file] = $attrs; - } - - function getInstallationFilelist() - { - return $this->getFilelist(); - } - - function getFilelist() - { - if (isset($this->_packageInfo['filelist'])) { - return $this->_packageInfo['filelist']; - } - return false; - } - - function setFileAttribute($file, $attr, $value) - { - $this->_packageInfo['filelist'][$file][$attr] = $value; - } - - function resetFilelist() - { - $this->_packageInfo['filelist'] = array(); - } - - function setInstalledAs($file, $path) - { - if ($path) { - return $this->_packageInfo['filelist'][$file]['installed_as'] = $path; - } - unset($this->_packageInfo['filelist'][$file]['installed_as']); - } - - function installedFile($file, $atts) - { - if (isset($this->_packageInfo['filelist'][$file])) { - $this->_packageInfo['filelist'][$file] = - array_merge($this->_packageInfo['filelist'][$file], $atts); - } else { - $this->_packageInfo['filelist'][$file] = $atts; - } - } - - function getChangelog() - { - if (isset($this->_packageInfo['changelog'])) { - return $this->_packageInfo['changelog']; - } - return false; - } - - function getPackagexmlVersion() - { - return '1.0'; - } - - /** - * Wrapper to {@link PEAR_ErrorStack::getErrors()} - * @param boolean determines whether to purge the error stack after retrieving - * @return array - */ - function getValidationWarnings($purge = true) - { - return $this->_stack->getErrors($purge); - } - - // }}} - /** - * Validation error. Also marks the object contents as invalid - * @param error code - * @param array error information - * @access private - */ - function _validateError($code, $params = array()) - { - $this->_stack->push($code, 'error', $params, false, false, debug_backtrace()); - $this->_isValid = false; - } - - /** - * Validation warning. Does not mark the object contents invalid. - * @param error code - * @param array error information - * @access private - */ - function _validateWarning($code, $params = array()) - { - $this->_stack->push($code, 'warning', $params, false, false, debug_backtrace()); - } - - /** - * @param integer error code - * @access protected - */ - function _getErrorMessage() - { - return array( - PEAR_PACKAGEFILE_ERROR_NO_NAME => - 'Missing Package Name', - PEAR_PACKAGEFILE_ERROR_NO_SUMMARY => - 'No summary found', - PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY => - 'Summary should be on one line', - PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION => - 'Missing description', - PEAR_PACKAGEFILE_ERROR_NO_LICENSE => - 'Missing license', - PEAR_PACKAGEFILE_ERROR_NO_VERSION => - 'No release version found', - PEAR_PACKAGEFILE_ERROR_NO_STATE => - 'No release state found', - PEAR_PACKAGEFILE_ERROR_NO_DATE => - 'No release date found', - PEAR_PACKAGEFILE_ERROR_NO_NOTES => - 'No release notes found', - PEAR_PACKAGEFILE_ERROR_NO_LEAD => - 'Package must have at least one lead maintainer', - PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS => - 'No maintainers found, at least one must be defined', - PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE => - 'Maintainer %index% has no handle (user ID at channel server)', - PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE => - 'Maintainer %index% has no role', - PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME => - 'Maintainer %index% has no name', - PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL => - 'Maintainer %index% has no email', - PEAR_PACKAGEFILE_ERROR_NO_DEPNAME => - 'Dependency %index% is not a php dependency, and has no name', - PEAR_PACKAGEFILE_ERROR_NO_DEPREL => - 'Dependency %index% has no relation (rel)', - PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE => - 'Dependency %index% has no type', - PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED => - 'PHP Dependency %index% has a name attribute of "%name%" which will be' . - ' ignored!', - PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION => - 'Dependency %index% is not a rel="has" or rel="not" dependency, ' . - 'and has no version', - PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION => - 'Dependency %index% is a type="php" dependency, ' . - 'and has no version', - PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED => - 'Dependency %index% is a rel="%rel%" dependency, versioning is ignored', - PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL => - 'Dependency %index% has invalid optional value "%opt%", should be yes or no', - PEAR_PACKAGEFILE_PHP_NO_NOT => - 'Dependency %index%: php dependencies cannot use "not" rel, use "ne"' . - ' to exclude specific versions', - PEAR_PACKAGEFILE_ERROR_NO_CONFNAME => - 'Configure Option %index% has no name', - PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT => - 'Configure Option %index% has no prompt', - PEAR_PACKAGEFILE_ERROR_NO_FILES => - 'No files in section of package.xml', - PEAR_PACKAGEFILE_ERROR_NO_FILEROLE => - 'File "%file%" has no role, expecting one of "%roles%"', - PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE => - 'File "%file%" has invalid role "%role%", expecting one of "%roles%"', - PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME => - 'File "%file%" cannot start with ".", cannot package or install', - PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE => - 'Parser error: invalid PHP found in file "%file%"', - PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX => - 'in %file%: %type% "%name%" not prefixed with package name "%package%"', - PEAR_PACKAGEFILE_ERROR_INVALID_FILE => - 'Parser error: invalid PHP file "%file%"', - PEAR_PACKAGEFILE_ERROR_CHANNELVAL => - 'Channel validator error: field "%field%" - %reason%', - PEAR_PACKAGEFILE_ERROR_PHP5 => - 'Error, PHP5 token encountered in %file%, analysis should be in PHP5', - PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND => - 'File "%file%" in package.xml does not exist', - PEAR_PACKAGEFILE_ERROR_NON_ISO_CHARS => - 'Package.xml contains non-ISO-8859-1 characters, and may not validate', - ); - } - - /** - * Validate XML package definition file. - * - * @access public - * @return boolean - */ - function validate($state = PEAR_VALIDATE_NORMAL, $nofilechecking = false) - { - if (($this->_isValid & $state) == $state) { - return true; - } - $this->_isValid = true; - $info = $this->_packageInfo; - if (empty($info['package'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_NAME); - $this->_packageName = $pn = 'unknown'; - } else { - $this->_packageName = $pn = $info['package']; - } - - if (empty($info['summary'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_SUMMARY); - } elseif (strpos(trim($info['summary']), "\n") !== false) { - $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY, - array('summary' => $info['summary'])); - } - if (empty($info['description'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION); - } - if (empty($info['release_license'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_LICENSE); - } - if (empty($info['version'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_VERSION); - } - if (empty($info['release_state'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_STATE); - } - if (empty($info['release_date'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DATE); - } - if (empty($info['release_notes'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_NOTES); - } - if (empty($info['maintainers'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS); - } else { - $haslead = false; - $i = 1; - foreach ($info['maintainers'] as $m) { - if (empty($m['handle'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE, - array('index' => $i)); - } - if (empty($m['role'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE, - array('index' => $i, 'roles' => PEAR_Common::getUserRoles())); - } elseif ($m['role'] == 'lead') { - $haslead = true; - } - if (empty($m['name'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME, - array('index' => $i)); - } - if (empty($m['email'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL, - array('index' => $i)); - } - $i++; - } - if (!$haslead) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_LEAD); - } - } - if (!empty($info['release_deps'])) { - $i = 1; - foreach ($info['release_deps'] as $d) { - if (!isset($d['type']) || empty($d['type'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE, - array('index' => $i, 'types' => PEAR_Common::getDependencyTypes())); - continue; - } - if (!isset($d['rel']) || empty($d['rel'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPREL, - array('index' => $i, 'rels' => PEAR_Common::getDependencyRelations())); - continue; - } - if (!empty($d['optional'])) { - if (!in_array($d['optional'], array('yes', 'no'))) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL, - array('index' => $i, 'opt' => $d['optional'])); - } - } - if ($d['rel'] != 'has' && $d['rel'] != 'not' && empty($d['version'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION, - array('index' => $i)); - } elseif (($d['rel'] == 'has' || $d['rel'] == 'not') && !empty($d['version'])) { - $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED, - array('index' => $i, 'rel' => $d['rel'])); - } - if ($d['type'] == 'php' && !empty($d['name'])) { - $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED, - array('index' => $i, 'name' => $d['name'])); - } elseif ($d['type'] != 'php' && empty($d['name'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPNAME, - array('index' => $i)); - } - if ($d['type'] == 'php' && empty($d['version'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION, - array('index' => $i)); - } - if (($d['rel'] == 'not') && ($d['type'] == 'php')) { - $this->_validateError(PEAR_PACKAGEFILE_PHP_NO_NOT, - array('index' => $i)); - } - $i++; - } - } - if (!empty($info['configure_options'])) { - $i = 1; - foreach ($info['configure_options'] as $c) { - if (empty($c['name'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_CONFNAME, - array('index' => $i)); - } - if (empty($c['prompt'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT, - array('index' => $i)); - } - $i++; - } - } - if (empty($info['filelist'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_FILES); - $errors[] = 'no files'; - } else { - foreach ($info['filelist'] as $file => $fa) { - if (empty($fa['role'])) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_FILEROLE, - array('file' => $file, 'roles' => PEAR_Common::getFileRoles())); - continue; - } elseif (!in_array($fa['role'], PEAR_Common::getFileRoles())) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE, - array('file' => $file, 'role' => $fa['role'], 'roles' => PEAR_Common::getFileRoles())); - } - if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~', str_replace('\\', '/', $file))) { - // file contains .. parent directory or . cur directory references - $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME, - array('file' => $file)); - } - if (isset($fa['install-as']) && - preg_match('~/\.\.?(/|\\z)|^\.\.?/~', - str_replace('\\', '/', $fa['install-as']))) { - // install-as contains .. parent directory or . cur directory references - $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME, - array('file' => $file . ' [installed as ' . $fa['install-as'] . ']')); - } - if (isset($fa['baseinstalldir']) && - preg_match('~/\.\.?(/|\\z)|^\.\.?/~', - str_replace('\\', '/', $fa['baseinstalldir']))) { - // install-as contains .. parent directory or . cur directory references - $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME, - array('file' => $file . ' [baseinstalldir ' . $fa['baseinstalldir'] . ']')); - } - } - } - if (isset($this->_registry) && $this->_isValid) { - $chan = $this->_registry->getChannel('pear.php.net'); - if (PEAR::isError($chan)) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $chan->getMessage()); - return $this->_isValid = 0; - } - $validator = $chan->getValidationObject(); - $validator->setPackageFile($this); - $validator->validate($state); - $failures = $validator->getFailures(); - foreach ($failures['errors'] as $error) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $error); - } - foreach ($failures['warnings'] as $warning) { - $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $warning); - } - } - if ($this->_isValid && $state == PEAR_VALIDATE_PACKAGING && !$nofilechecking) { - if ($this->_analyzePhpFiles()) { - $this->_isValid = true; - } - } - if ($this->_isValid) { - return $this->_isValid = $state; - } - return $this->_isValid = 0; - } - - function _analyzePhpFiles() - { - if (!$this->_isValid) { - return false; - } - if (!isset($this->_packageFile)) { - return false; - } - $dir_prefix = dirname($this->_packageFile); - $common = new PEAR_Common; - $log = isset($this->_logger) ? array(&$this->_logger, 'log') : - array($common, 'log'); - $info = $this->getFilelist(); - foreach ($info as $file => $fa) { - if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $file)) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND, - array('file' => realpath($dir_prefix) . DIRECTORY_SEPARATOR . $file)); - continue; - } - if ($fa['role'] == 'php' && $dir_prefix) { - call_user_func_array($log, array(1, "Analyzing $file")); - $srcinfo = $this->_analyzeSourceCode($dir_prefix . DIRECTORY_SEPARATOR . $file); - if ($srcinfo) { - $this->_buildProvidesArray($srcinfo); - } - } - } - $this->_packageName = $pn = $this->getPackage(); - $pnl = strlen($pn); - if (isset($this->_packageInfo['provides'])) { - foreach ((array) $this->_packageInfo['provides'] as $key => $what) { - if (isset($what['explicit'])) { - // skip conformance checks if the provides entry is - // specified in the package.xml file - continue; - } - extract($what); - if ($type == 'class') { - if (!strncasecmp($name, $pn, $pnl)) { - continue; - } - $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX, - array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn)); - } elseif ($type == 'function') { - if (strstr($name, '::') || !strncasecmp($name, $pn, $pnl)) { - continue; - } - $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX, - array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn)); - } - } - } - return $this->_isValid; - } - - /** - * Get the default xml generator object - * - * @return PEAR_PackageFile_Generator_v1 - */ - function &getDefaultGenerator() - { - if (!class_exists('PEAR_PackageFile_Generator_v1')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/Generator/v1.php'; - } - $a = &new PEAR_PackageFile_Generator_v1($this); - return $a; - } - - /** - * Get the contents of a file listed within the package.xml - * @param string - * @return string - */ - function getFileContents($file) - { - if ($this->_archiveFile == $this->_packageFile) { // unpacked - $dir = dirname($this->_packageFile); - $file = $dir . DIRECTORY_SEPARATOR . $file; - $file = str_replace(array('/', '\\'), - array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), $file); - if (file_exists($file) && is_readable($file)) { - return implode('', file($file)); - } - } else { // tgz - if (!class_exists('Archive_Tar')) { - require_once 'phar://install-pear-nozlib.phar/' . 'Archive/Tar.php'; - } - $tar = &new Archive_Tar($this->_archiveFile); - $tar->pushErrorHandling(PEAR_ERROR_RETURN); - if ($file != 'package.xml' && $file != 'package2.xml') { - $file = $this->getPackage() . '-' . $this->getVersion() . '/' . $file; - } - $file = $tar->extractInString($file); - $tar->popErrorHandling(); - if (PEAR::isError($file)) { - return PEAR::raiseError("Cannot locate file '$file' in archive"); - } - return $file; - } - } - - // {{{ analyzeSourceCode() - /** - * Analyze the source code of the given PHP file - * - * @param string Filename of the PHP file - * @return mixed - * @access private - */ - function _analyzeSourceCode($file) - { - if (!function_exists("token_get_all")) { - return false; - } - if (!defined('T_DOC_COMMENT')) { - define('T_DOC_COMMENT', T_COMMENT); - } - if (!defined('T_INTERFACE')) { - define('T_INTERFACE', -1); - } - if (!defined('T_IMPLEMENTS')) { - define('T_IMPLEMENTS', -1); - } - if (!$fp = @fopen($file, "r")) { - return false; - } - fclose($fp); - $contents = file_get_contents($file); - $tokens = token_get_all($contents); -/* - for ($i = 0; $i < sizeof($tokens); $i++) { - @list($token, $data) = $tokens[$i]; - if (is_string($token)) { - var_dump($token); - } else { - print token_name($token) . ' '; - var_dump(rtrim($data)); - } - } -*/ - $look_for = 0; - $paren_level = 0; - $bracket_level = 0; - $brace_level = 0; - $lastphpdoc = ''; - $current_class = ''; - $current_interface = ''; - $current_class_level = -1; - $current_function = ''; - $current_function_level = -1; - $declared_classes = array(); - $declared_interfaces = array(); - $declared_functions = array(); - $declared_methods = array(); - $used_classes = array(); - $used_functions = array(); - $extends = array(); - $implements = array(); - $nodeps = array(); - $inquote = false; - $interface = false; - for ($i = 0; $i < sizeof($tokens); $i++) { - if (is_array($tokens[$i])) { - list($token, $data) = $tokens[$i]; - } else { - $token = $tokens[$i]; - $data = ''; - } - if ($inquote) { - if ($token != '"' && $token != T_END_HEREDOC) { - continue; - } else { - $inquote = false; - continue; - } - } - switch ($token) { - case T_WHITESPACE : - continue; - case ';': - if ($interface) { - $current_function = ''; - $current_function_level = -1; - } - break; - case '"': - case T_START_HEREDOC: - $inquote = true; - break; - case T_CURLY_OPEN: - case T_DOLLAR_OPEN_CURLY_BRACES: - case '{': $brace_level++; continue 2; - case '}': - $brace_level--; - if ($current_class_level == $brace_level) { - $current_class = ''; - $current_class_level = -1; - } - if ($current_function_level == $brace_level) { - $current_function = ''; - $current_function_level = -1; - } - continue 2; - case '[': $bracket_level++; continue 2; - case ']': $bracket_level--; continue 2; - case '(': $paren_level++; continue 2; - case ')': $paren_level--; continue 2; - case T_INTERFACE: - $interface = true; - case T_CLASS: - if (($current_class_level != -1) || ($current_function_level != -1)) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE, - array('file' => $file)); - return false; - } - case T_FUNCTION: - case T_NEW: - case T_EXTENDS: - case T_IMPLEMENTS: - $look_for = $token; - continue 2; - case T_STRING: - if (version_compare(zend_version(), '2.0', '<')) { - if (in_array(strtolower($data), - array('public', 'private', 'protected', 'abstract', - 'interface', 'implements', 'throw') - )) { - $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_PHP5, - array($file)); - } - } - if ($look_for == T_CLASS) { - $current_class = $data; - $current_class_level = $brace_level; - $declared_classes[] = $current_class; - } elseif ($look_for == T_INTERFACE) { - $current_interface = $data; - $current_class_level = $brace_level; - $declared_interfaces[] = $current_interface; - } elseif ($look_for == T_IMPLEMENTS) { - $implements[$current_class] = $data; - } elseif ($look_for == T_EXTENDS) { - $extends[$current_class] = $data; - } elseif ($look_for == T_FUNCTION) { - if ($current_class) { - $current_function = "$current_class::$data"; - $declared_methods[$current_class][] = $data; - } elseif ($current_interface) { - $current_function = "$current_interface::$data"; - $declared_methods[$current_interface][] = $data; - } else { - $current_function = $data; - $declared_functions[] = $current_function; - } - $current_function_level = $brace_level; - $m = array(); - } elseif ($look_for == T_NEW) { - $used_classes[$data] = true; - } - $look_for = 0; - continue 2; - case T_VARIABLE: - $look_for = 0; - continue 2; - case T_DOC_COMMENT: - case T_COMMENT: - if (preg_match('!^/\*\*\s!', $data)) { - $lastphpdoc = $data; - if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m)) { - $nodeps = array_merge($nodeps, $m[1]); - } - } - continue 2; - case T_DOUBLE_COLON: - if (!($tokens[$i - 1][0] == T_WHITESPACE || $tokens[$i - 1][0] == T_STRING)) { - $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE, - array('file' => $file)); - return false; - } - $class = $tokens[$i - 1][1]; - if (strtolower($class) != 'parent') { - $used_classes[$class] = true; - } - continue 2; - } - } - return array( - "source_file" => $file, - "declared_classes" => $declared_classes, - "declared_interfaces" => $declared_interfaces, - "declared_methods" => $declared_methods, - "declared_functions" => $declared_functions, - "used_classes" => array_diff(array_keys($used_classes), $nodeps), - "inheritance" => $extends, - "implements" => $implements, - ); - } - - /** - * Build a "provides" array from data returned by - * analyzeSourceCode(). The format of the built array is like - * this: - * - * array( - * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'), - * ... - * ) - * - * - * @param array $srcinfo array with information about a source file - * as returned by the analyzeSourceCode() method. - * - * @return void - * - * @access private - * - */ - function _buildProvidesArray($srcinfo) - { - if (!$this->_isValid) { - return false; - } - $file = basename($srcinfo['source_file']); - $pn = $this->getPackage(); - $pnl = strlen($pn); - foreach ($srcinfo['declared_classes'] as $class) { - $key = "class;$class"; - if (isset($this->_packageInfo['provides'][$key])) { - continue; - } - $this->_packageInfo['provides'][$key] = - array('file'=> $file, 'type' => 'class', 'name' => $class); - if (isset($srcinfo['inheritance'][$class])) { - $this->_packageInfo['provides'][$key]['extends'] = - $srcinfo['inheritance'][$class]; - } - } - foreach ($srcinfo['declared_methods'] as $class => $methods) { - foreach ($methods as $method) { - $function = "$class::$method"; - $key = "function;$function"; - if ($method{0} == '_' || !strcasecmp($method, $class) || - isset($this->_packageInfo['provides'][$key])) { - continue; - } - $this->_packageInfo['provides'][$key] = - array('file'=> $file, 'type' => 'function', 'name' => $function); - } - } - - foreach ($srcinfo['declared_functions'] as $function) { - $key = "function;$function"; - if ($function{0} == '_' || isset($this->_packageInfo['provides'][$key])) { - continue; - } - if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) { - $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\""; - } - $this->_packageInfo['provides'][$key] = - array('file'=> $file, 'type' => 'function', 'name' => $function); - } - } - - // }}} -} -?> +} +?> * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: v2.php,v 1.145 2009/02/24 23:39:16 dufuz Exp $ + * @version CVS: $Id: Validator.php 277885 2009-03-27 19:29:31Z dufuz $ * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a1 - */ -/** - * For error handling + * @since File available since Release 1.4.0a8 */ -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/ErrorStack.php'; /** + * Private validation class used by PEAR_PackageFile_v2 - do not use directly, its + * sole purpose is to split up the PEAR/PackageFile/v2.php file to make it smaller * @category pear * @package PEAR * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 + * @since Class available since Release 1.4.0a8 + * @access private */ -class PEAR_PackageFile_v2 +class PEAR_PackageFile_v2_Validator { - - /** - * Parsed package information - * @var array - * @access private - */ - var $_packageInfo = array(); - /** - * path to package .tgz or false if this is a local/extracted package.xml - * @var string|false - * @access private + * @var array */ - var $_archiveFile; - + var $_packageInfo; /** - * path to package .xml or false if this is an abstract parsed-from-string xml - * @var string|false - * @access private + * @var PEAR_PackageFile_v2 */ - var $_packageFile; - + var $_pf; /** - * This is used by file analysis routines to log progress information - * @var PEAR_Common - * @access protected + * @var PEAR_ErrorStack */ - var $_logger; - + var $_stack; /** - * This is set to the highest validation level that has been validated - * - * If the package.xml is invalid or unknown, this is set to 0. If - * normal validation has occurred, this is set to PEAR_VALIDATE_NORMAL. If - * downloading/installation validation has occurred it is set to PEAR_VALIDATE_DOWNLOADING - * or INSTALLING, and so on up to PEAR_VALIDATE_PACKAGING. This allows validation - * "caching" to occur, which is particularly important for package validation, so - * that PHP files are not validated twice * @var int - * @access private */ var $_isValid = 0; - - /** - * True if the filelist has been validated - * @param bool - */ - var $_filesValid = false; - - /** - * @var PEAR_Registry - * @access protected - */ - var $_registry; - - /** - * @var PEAR_Config - * @access protected - */ - var $_config; - /** - * Optional Dependency group requested for installation - * @var string - * @access private + * @var int */ - var $_requestedGroup = false; - + var $_filesValid = 0; /** - * @var PEAR_ErrorStack - * @access protected + * @var int */ - var $_stack; - + var $_curState = 0; /** - * Namespace prefix used for tasks in this package.xml - use tasks: whenever possible + * @param PEAR_PackageFile_v2 + * @param int */ - var $_tasksNs; + function validate(&$pf, $state = PEAR_VALIDATE_NORMAL) + { + $this->_pf = &$pf; + $this->_curState = $state; + $this->_packageInfo = $this->_pf->getArray(); + $this->_isValid = $this->_pf->_isValid; + $this->_filesValid = $this->_pf->_filesValid; + $this->_stack = &$pf->_stack; + $this->_stack->getErrors(true); + if (($this->_isValid & $state) == $state) { + return true; + } + if (!isset($this->_packageInfo) || !is_array($this->_packageInfo)) { + return false; + } + if (!isset($this->_packageInfo['attribs']['version']) || + ($this->_packageInfo['attribs']['version'] != '2.0' && + $this->_packageInfo['attribs']['version'] != '2.1') + ) { + $this->_noPackageVersion(); + } + $structure = + array( + 'name', + 'channel|uri', + '*extends', // can't be multiple, but this works fine + 'summary', + 'description', + '+lead', // these all need content checks + '*developer', + '*contributor', + '*helper', + 'date', + '*time', + 'version', + 'stability', + 'license->?uri->?filesource', + 'notes', + 'contents', //special validation needed + '*compatible', + 'dependencies', //special validation needed + '*usesrole', + '*usestask', // reserve these for 1.4.0a1 to implement + // this will allow a package.xml to gracefully say it + // needs a certain package installed in order to implement a role or task + '*providesextension', + '*srcpackage|*srcuri', + '+phprelease|+extsrcrelease|+extbinrelease|' . + '+zendextsrcrelease|+zendextbinrelease|bundle', //special validation needed + '*changelog', + ); + $test = $this->_packageInfo; + if (isset($test['dependencies']) && + isset($test['dependencies']['required']) && + isset($test['dependencies']['required']['pearinstaller']) && + isset($test['dependencies']['required']['pearinstaller']['min']) && + version_compare('1.9.0', + $test['dependencies']['required']['pearinstaller']['min'], '<') + ) { + $this->_pearVersionTooLow($test['dependencies']['required']['pearinstaller']['min']); + return false; + } + // ignore post-installation array fields + if (array_key_exists('filelist', $test)) { + unset($test['filelist']); + } + if (array_key_exists('_lastmodified', $test)) { + unset($test['_lastmodified']); + } + if (array_key_exists('#binarypackage', $test)) { + unset($test['#binarypackage']); + } + if (array_key_exists('old', $test)) { + unset($test['old']); + } + if (array_key_exists('_lastversion', $test)) { + unset($test['_lastversion']); + } + if (!$this->_stupidSchemaValidate($structure, $test, '')) { + return false; + } + if (empty($this->_packageInfo['name'])) { + $this->_tagCannotBeEmpty('name'); + } + $test = isset($this->_packageInfo['uri']) ? 'uri' :'channel'; + if (empty($this->_packageInfo[$test])) { + $this->_tagCannotBeEmpty($test); + } + if (is_array($this->_packageInfo['license']) && + (!isset($this->_packageInfo['license']['_content']) || + empty($this->_packageInfo['license']['_content']))) { + $this->_tagCannotBeEmpty('license'); + } elseif (empty($this->_packageInfo['license'])) { + $this->_tagCannotBeEmpty('license'); + } + if (empty($this->_packageInfo['summary'])) { + $this->_tagCannotBeEmpty('summary'); + } + if (empty($this->_packageInfo['description'])) { + $this->_tagCannotBeEmpty('description'); + } + if (empty($this->_packageInfo['date'])) { + $this->_tagCannotBeEmpty('date'); + } + if (empty($this->_packageInfo['notes'])) { + $this->_tagCannotBeEmpty('notes'); + } + if (isset($this->_packageInfo['time']) && empty($this->_packageInfo['time'])) { + $this->_tagCannotBeEmpty('time'); + } + if (isset($this->_packageInfo['dependencies'])) { + $this->_validateDependencies(); + } + if (isset($this->_packageInfo['compatible'])) { + $this->_validateCompatible(); + } + if (!isset($this->_packageInfo['bundle'])) { + if (empty($this->_packageInfo['contents'])) { + $this->_tagCannotBeEmpty('contents'); + } + if (!isset($this->_packageInfo['contents']['dir'])) { + $this->_filelistMustContainDir('contents'); + return false; + } + if (isset($this->_packageInfo['contents']['file'])) { + $this->_filelistCannotContainFile('contents'); + return false; + } + } + $this->_validateMaintainers(); + $this->_validateStabilityVersion(); + $fail = false; + if (array_key_exists('usesrole', $this->_packageInfo)) { + $roles = $this->_packageInfo['usesrole']; + if (!is_array($roles) || !isset($roles[0])) { + $roles = array($roles); + } + foreach ($roles as $role) { + if (!isset($role['role'])) { + $this->_usesroletaskMustHaveRoleTask('usesrole', 'role'); + $fail = true; + } else { + if (!isset($role['channel'])) { + if (!isset($role['uri'])) { + $this->_usesroletaskMustHaveChannelOrUri($role['role'], 'usesrole'); + $fail = true; + } + } elseif (!isset($role['package'])) { + $this->_usesroletaskMustHavePackage($role['role'], 'usesrole'); + $fail = true; + } + } + } + } + if (array_key_exists('usestask', $this->_packageInfo)) { + $roles = $this->_packageInfo['usestask']; + if (!is_array($roles) || !isset($roles[0])) { + $roles = array($roles); + } + foreach ($roles as $role) { + if (!isset($role['task'])) { + $this->_usesroletaskMustHaveRoleTask('usestask', 'task'); + $fail = true; + } else { + if (!isset($role['channel'])) { + if (!isset($role['uri'])) { + $this->_usesroletaskMustHaveChannelOrUri($role['task'], 'usestask'); + $fail = true; + } + } elseif (!isset($role['package'])) { + $this->_usesroletaskMustHavePackage($role['task'], 'usestask'); + $fail = true; + } + } + } + } - /** - * Determines whether this packagefile was initialized only with partial package info - * - * If this package file was constructed via parsing REST, it will only contain - * - * - package name - * - channel name - * - dependencies - * @var boolean - * @access private - */ - var $_incomplete = true; + if ($fail) { + return false; + } - /** - * @var PEAR_PackageFile_v2_Validator - */ - var $_v2Validator; + $list = $this->_packageInfo['contents']; + if (isset($list['dir']) && is_array($list['dir']) && isset($list['dir'][0])) { + $this->_multipleToplevelDirNotAllowed(); + return $this->_isValid = 0; + } - /** - * The constructor merely sets up the private error stack - */ - function PEAR_PackageFile_v2() - { - $this->_stack = new PEAR_ErrorStack('PEAR_PackageFile_v2', false, null); - $this->_isValid = false; - } + $this->_validateFilelist(); + $this->_validateRelease(); + if (!$this->_stack->hasErrors()) { + $chan = $this->_pf->_registry->getChannel($this->_pf->getChannel(), true); + if (PEAR::isError($chan)) { + $this->_unknownChannel($this->_pf->getChannel()); + } else { + $valpack = $chan->getValidationPackage(); + // for channel validator packages, always use the default PEAR validator. + // otherwise, they can't be installed or packaged + $validator = $chan->getValidationObject($this->_pf->getPackage()); + if (!$validator) { + $this->_stack->push(__FUNCTION__, 'error', + array_merge( + array('channel' => $chan->getName(), + 'package' => $this->_pf->getPackage()), + $valpack + ), + 'package "%channel%/%package%" cannot be properly validated without ' . + 'validation package "%channel%/%name%-%version%"'); + return $this->_isValid = 0; + } + $validator->setPackageFile($this->_pf); + $validator->validate($state); + $failures = $validator->getFailures(); + foreach ($failures['errors'] as $error) { + $this->_stack->push(__FUNCTION__, 'error', $error, + 'Channel validator error: field "%field%" - %reason%'); + } + foreach ($failures['warnings'] as $warning) { + $this->_stack->push(__FUNCTION__, 'warning', $warning, + 'Channel validator warning: field "%field%" - %reason%'); + } + } + } - /** - * To make unit-testing easier - * @param PEAR_Frontend_* - * @param array options - * @param PEAR_Config - * @return PEAR_Downloader - * @access protected - */ - function &getPEARDownloader(&$i, $o, &$c) - { - $z = &new PEAR_Downloader($i, $o, $c); - return $z; - } + $this->_pf->_isValid = $this->_isValid = !$this->_stack->hasErrors('error'); + if ($this->_isValid && $state == PEAR_VALIDATE_PACKAGING && !$this->_filesValid) { + if ($this->_pf->getPackageType() == 'bundle') { + if ($this->_analyzeBundledPackages()) { + $this->_filesValid = $this->_pf->_filesValid = true; + } else { + $this->_pf->_isValid = $this->_isValid = 0; + } + } else { + if (!$this->_analyzePhpFiles()) { + $this->_pf->_isValid = $this->_isValid = 0; + } else { + $this->_filesValid = $this->_pf->_filesValid = true; + } + } + } - /** - * To make unit-testing easier - * @param PEAR_Config - * @param array options - * @param array package name as returned from {@link PEAR_Registry::parsePackageName()} - * @param int PEAR_VALIDATE_* constant - * @return PEAR_Dependency2 - * @access protected - */ - function &getPEARDependency2(&$c, $o, $p, $s = PEAR_VALIDATE_INSTALLING) - { - if (!class_exists('PEAR_Dependency2')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Dependency2.php'; + if ($this->_isValid) { + return $this->_pf->_isValid = $this->_isValid = $state; } - $z = &new PEAR_Dependency2($c, $o, $p, $s); - return $z; - } - function getInstalledBinary() - { - return isset($this->_packageInfo['#binarypackage']) ? $this->_packageInfo['#binarypackage'] : - false; + return $this->_pf->_isValid = $this->_isValid = 0; } - /** - * Installation of source package has failed, attempt to download and install the - * binary version of this package. - * @param PEAR_Installer - * @return array|false - */ - function installBinary(&$installer) + function _stupidSchemaValidate($structure, $xml, $root) { - if (!OS_WINDOWS) { - $a = false; - return $a; + if (!is_array($xml)) { + $xml = array(); } - if ($this->getPackageType() == 'extsrc' || $this->getPackageType() == 'zendextsrc') { - $releasetype = $this->getPackageType() . 'release'; - if (!is_array($installer->getInstallPackages())) { - $a = false; - return $a; + $keys = array_keys($xml); + reset($keys); + $key = current($keys); + while ($key == 'attribs' || $key == '_contents') { + $key = next($keys); + } + $unfoundtags = $optionaltags = array(); + $ret = true; + $mismatch = false; + foreach ($structure as $struc) { + if ($key) { + $tag = $xml[$key]; } - foreach ($installer->getInstallPackages() as $p) { - if ($p->isExtension($this->_packageInfo['providesextension'])) { - if ($p->getPackageType() != 'extsrc' && $p->getPackageType() != 'zendextsrc') { - $a = false; - return $a; // the user probably downloaded it separately + $test = $this->_processStructure($struc); + if (isset($test['choices'])) { + $loose = true; + foreach ($test['choices'] as $choice) { + if ($key == $choice['tag']) { + $key = next($keys); + while ($key == 'attribs' || $key == '_contents') { + $key = next($keys); + } + $unfoundtags = $optionaltags = array(); + $mismatch = false; + if ($key && $key != $choice['tag'] && isset($choice['multiple'])) { + $unfoundtags[] = $choice['tag']; + $optionaltags[] = $choice['tag']; + if ($key) { + $mismatch = true; + } + } + $ret &= $this->_processAttribs($choice, $tag, $root); + continue 2; + } else { + $unfoundtags[] = $choice['tag']; + $mismatch = true; + } + if (!isset($choice['multiple']) || $choice['multiple'] != '*') { + $loose = false; + } else { + $optionaltags[] = $choice['tag']; } } - } - if (isset($this->_packageInfo[$releasetype]['binarypackage'])) { - $installer->log(0, 'Attempting to download binary version of extension "' . - $this->_packageInfo['providesextension'] . '"'); - $params = $this->_packageInfo[$releasetype]['binarypackage']; - if (!is_array($params) || !isset($params[0])) { - $params = array($params); + if (!$loose) { + $this->_invalidTagOrder($unfoundtags, $key, $root); + return false; } - if (isset($this->_packageInfo['channel'])) { - foreach ($params as $i => $param) { - $params[$i] = array('channel' => $this->_packageInfo['channel'], - 'package' => $param, 'version' => $this->getVersion()); + } else { + if ($key != $test['tag']) { + if (isset($test['multiple']) && $test['multiple'] != '*') { + $unfoundtags[] = $test['tag']; + $this->_invalidTagOrder($unfoundtags, $key, $root); + return false; + } else { + if ($key) { + $mismatch = true; + } + $unfoundtags[] = $test['tag']; + $optionaltags[] = $test['tag']; + } + if (!isset($test['multiple'])) { + $this->_invalidTagOrder($unfoundtags, $key, $root); + return false; } + continue; + } else { + $unfoundtags = $optionaltags = array(); + $mismatch = false; } - $dl = &$this->getPEARDownloader($installer->ui, $installer->getOptions(), - $installer->config); - $verbose = $dl->config->get('verbose'); - $dl->config->set('verbose', -1); - foreach ($params as $param) { - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $ret = $dl->download(array($param)); - PEAR::popErrorHandling(); - if (is_array($ret) && count($ret)) { - break; + $key = next($keys); + while ($key == 'attribs' || $key == '_contents') { + $key = next($keys); + } + if ($key && $key != $test['tag'] && isset($test['multiple'])) { + $unfoundtags[] = $test['tag']; + $optionaltags[] = $test['tag']; + $mismatch = true; + } + $ret &= $this->_processAttribs($test, $tag, $root); + continue; + } + } + if (!$mismatch && count($optionaltags)) { + // don't error out on any optional tags + $unfoundtags = array_diff($unfoundtags, $optionaltags); + } + if (count($unfoundtags)) { + $this->_invalidTagOrder($unfoundtags, $key, $root); + } elseif ($key) { + // unknown tags + $this->_invalidTagOrder('*no tags allowed here*', $key, $root); + while ($key = next($keys)) { + $this->_invalidTagOrder('*no tags allowed here*', $key, $root); + } + } + return $ret; + } + + function _processAttribs($choice, $tag, $context) + { + if (isset($choice['attribs'])) { + if (!is_array($tag)) { + $tag = array($tag); + } + $tags = $tag; + if (!isset($tags[0])) { + $tags = array($tags); + } + $ret = true; + foreach ($tags as $i => $tag) { + if (!is_array($tag) || !isset($tag['attribs'])) { + foreach ($choice['attribs'] as $attrib) { + if ($attrib{0} != '?') { + $ret &= $this->_tagHasNoAttribs($choice['tag'], + $context); + continue 2; + } } } - $dl->config->set('verbose', $verbose); - if (is_array($ret)) { - if (count($ret) == 1) { - $pf = $ret[0]->getPackageFile(); - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $err = $installer->install($ret[0]); - PEAR::popErrorHandling(); - if (is_array($err)) { - $this->_packageInfo['#binarypackage'] = $ret[0]->getPackage(); - // "install" self, so all dependencies will work transparently - $this->_registry->addPackage2($this); - $installer->log(0, 'Download and install of binary extension "' . - $this->_registry->parsedPackageNameToString( - array('channel' => $pf->getChannel(), - 'package' => $pf->getPackage()), true) . '" successful'); - $a = array($ret[0], $err); - return $a; + foreach ($choice['attribs'] as $attrib) { + if ($attrib{0} != '?') { + if (!isset($tag['attribs'][$attrib])) { + $ret &= $this->_tagMissingAttribute($choice['tag'], + $attrib, $context); } - $installer->log(0, 'Download and install of binary extension "' . - $this->_registry->parsedPackageNameToString( - array('channel' => $pf->getChannel(), - 'package' => $pf->getPackage()), true) . '" failed'); } } } + return $ret; } - $a = false; - return $a; + return true; } - /** - * @return string|false Extension name - */ - function getProvidesExtension() + function _processStructure($key) { - if (in_array($this->getPackageType(), - array('extsrc', 'extbin', 'zendextsrc', 'zendextbin'))) { - if (isset($this->_packageInfo['providesextension'])) { - return $this->_packageInfo['providesextension']; + $ret = array(); + if (count($pieces = explode('|', $key)) > 1) { + $ret['choices'] = array(); + foreach ($pieces as $piece) { + $ret['choices'][] = $this->_processStructure($piece); } + return $ret; } - return false; + $multi = $key{0}; + if ($multi == '+' || $multi == '*') { + $ret['multiple'] = $key{0}; + $key = substr($key, 1); + } + if (count($attrs = explode('->', $key)) > 1) { + $ret['tag'] = array_shift($attrs); + $ret['attribs'] = $attrs; + } else { + $ret['tag'] = $key; + } + return $ret; } - /** - * @param string Extension name - * @return bool - */ - function isExtension($extension) + function _validateStabilityVersion() { - if (in_array($this->getPackageType(), - array('extsrc', 'extbin', 'zendextsrc', 'zendextbin'))) { - return $this->_packageInfo['providesextension'] == $extension; + $structure = array('release', 'api'); + $a = $this->_stupidSchemaValidate($structure, $this->_packageInfo['version'], ''); + $a &= $this->_stupidSchemaValidate($structure, $this->_packageInfo['stability'], ''); + if ($a) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $this->_packageInfo['version']['release'])) { + $this->_invalidVersion('release', $this->_packageInfo['version']['release']); + } + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $this->_packageInfo['version']['api'])) { + $this->_invalidVersion('api', $this->_packageInfo['version']['api']); + } + if (!in_array($this->_packageInfo['stability']['release'], + array('snapshot', 'devel', 'alpha', 'beta', 'stable'))) { + $this->_invalidState('release', $this->_packageInfo['stability']['release']); + } + if (!in_array($this->_packageInfo['stability']['api'], + array('devel', 'alpha', 'beta', 'stable'))) { + $this->_invalidState('api', $this->_packageInfo['stability']['api']); + } } - return false; } - /** - * Tests whether every part of the package.xml 1.0 is represented in - * this package.xml 2.0 - * @param PEAR_PackageFile_v1 - * @return bool - */ - function isEquivalent($pf1) + function _validateMaintainers() { - if (!$pf1) { - return true; + $structure = + array( + 'name', + 'user', + 'email', + 'active', + ); + foreach (array('lead', 'developer', 'contributor', 'helper') as $type) { + if (!isset($this->_packageInfo[$type])) { + continue; + } + if (isset($this->_packageInfo[$type][0])) { + foreach ($this->_packageInfo[$type] as $lead) { + $this->_stupidSchemaValidate($structure, $lead, '<' . $type . '>'); + } + } else { + $this->_stupidSchemaValidate($structure, $this->_packageInfo[$type], + '<' . $type . '>'); + } } - if ($this->getPackageType() == 'bundle') { - return false; + } + + function _validatePhpDep($dep, $installcondition = false) + { + $structure = array( + 'min', + '*max', + '*exclude', + ); + $type = $installcondition ? '' : ''; + $this->_stupidSchemaValidate($structure, $dep, $type); + if (isset($dep['min'])) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/', + $dep['min'])) { + $this->_invalidVersion($type . '', $dep['min']); + } } - $this->_stack->getErrors(true); - if (!$pf1->validate(PEAR_VALIDATE_NORMAL)) { - return false; + if (isset($dep['max'])) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/', + $dep['max'])) { + $this->_invalidVersion($type . '', $dep['max']); + } } - $pass = true; - if ($pf1->getPackage() != $this->getPackage()) { - $this->_differentPackage($pf1->getPackage()); - $pass = false; + if (isset($dep['exclude'])) { + if (!is_array($dep['exclude'])) { + $dep['exclude'] = array($dep['exclude']); + } + foreach ($dep['exclude'] as $exclude) { + if (!preg_match( + '/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/', + $exclude)) { + $this->_invalidVersion($type . '', $exclude); + } + } } - if ($pf1->getVersion() != $this->getVersion()) { - $this->_differentVersion($pf1->getVersion()); - $pass = false; + } + + function _validatePearinstallerDep($dep) + { + $structure = array( + 'min', + '*max', + '*recommended', + '*exclude', + ); + $this->_stupidSchemaValidate($structure, $dep, ''); + if (isset($dep['min'])) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $dep['min'])) { + $this->_invalidVersion('', + $dep['min']); + } } - if (trim($pf1->getSummary()) != $this->getSummary()) { - $this->_differentSummary($pf1->getSummary()); - $pass = false; + if (isset($dep['max'])) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $dep['max'])) { + $this->_invalidVersion('', + $dep['max']); + } } - if (preg_replace('/\s+/', '', $pf1->getDescription()) != - preg_replace('/\s+/', '', $this->getDescription())) { - $this->_differentDescription($pf1->getDescription()); - $pass = false; + if (isset($dep['recommended'])) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $dep['recommended'])) { + $this->_invalidVersion('', + $dep['recommended']); + } } - if ($pf1->getState() != $this->getState()) { - $this->_differentState($pf1->getState()); - $pass = false; + if (isset($dep['exclude'])) { + if (!is_array($dep['exclude'])) { + $dep['exclude'] = array($dep['exclude']); + } + foreach ($dep['exclude'] as $exclude) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $exclude)) { + $this->_invalidVersion('', + $exclude); + } + } } - if (!strstr(preg_replace('/\s+/', '', $this->getNotes()), - preg_replace('/\s+/', '', $pf1->getNotes()))) { - $this->_differentNotes($pf1->getNotes()); - $pass = false; + } + + function _validatePackageDep($dep, $group, $type = '') + { + if (isset($dep['uri'])) { + if (isset($dep['conflicts'])) { + $structure = array( + 'name', + 'uri', + 'conflicts', + '*providesextension', + ); + } else { + $structure = array( + 'name', + 'uri', + '*providesextension', + ); + } + } else { + if (isset($dep['conflicts'])) { + $structure = array( + 'name', + 'channel', + '*min', + '*max', + '*exclude', + 'conflicts', + '*providesextension', + ); + } else { + $structure = array( + 'name', + 'channel', + '*min', + '*max', + '*recommended', + '*exclude', + '*nodefault', + '*providesextension', + ); + } } - $mymaintainers = $this->getMaintainers(); - $yourmaintainers = $pf1->getMaintainers(); - for ($i1 = 0; $i1 < count($yourmaintainers); $i1++) { - $reset = false; - for ($i2 = 0; $i2 < count($mymaintainers); $i2++) { - if ($mymaintainers[$i2]['handle'] == $yourmaintainers[$i1]['handle']) { - if ($mymaintainers[$i2]['role'] != $yourmaintainers[$i1]['role']) { - $this->_differentRole($mymaintainers[$i2]['handle'], - $yourmaintainers[$i1]['role'], $mymaintainers[$i2]['role']); - $pass = false; - } - if ($mymaintainers[$i2]['email'] != $yourmaintainers[$i1]['email']) { - $this->_differentEmail($mymaintainers[$i2]['handle'], - $yourmaintainers[$i1]['email'], $mymaintainers[$i2]['email']); - $pass = false; - } - if ($mymaintainers[$i2]['name'] != $yourmaintainers[$i1]['name']) { - $this->_differentName($mymaintainers[$i2]['handle'], - $yourmaintainers[$i1]['name'], $mymaintainers[$i2]['name']); - $pass = false; - } - unset($mymaintainers[$i2]); - $mymaintainers = array_values($mymaintainers); - unset($yourmaintainers[$i1]); - $yourmaintainers = array_values($yourmaintainers); - $reset = true; - break; - } + if (isset($dep['name'])) { + $type .= '' . $dep['name'] . ''; + } + $this->_stupidSchemaValidate($structure, $dep, '' . $group . $type); + if (isset($dep['uri']) && (isset($dep['min']) || isset($dep['max']) || + isset($dep['recommended']) || isset($dep['exclude']))) { + $this->_uriDepsCannotHaveVersioning('' . $group . $type); + } + if (isset($dep['channel']) && strtolower($dep['channel']) == '__uri') { + $this->_DepchannelCannotBeUri('' . $group . $type); + } + if (isset($dep['min'])) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $dep['min'])) { + $this->_invalidVersion('' . $group . $type . '', $dep['min']); } - if ($reset) { - $i1 = -1; + } + if (isset($dep['max'])) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $dep['max'])) { + $this->_invalidVersion('' . $group . $type . '', $dep['max']); } } - $this->_unmatchedMaintainers($mymaintainers, $yourmaintainers); - $filelist = $this->getFilelist(); - foreach ($pf1->getFilelist() as $file => $atts) { - if (!isset($filelist[$file])) { - $this->_missingFile($file); - $pass = false; + if (isset($dep['recommended'])) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $dep['recommended'])) { + $this->_invalidVersion('' . $group . $type . '', + $dep['recommended']); + } + } + if (isset($dep['exclude'])) { + if (!is_array($dep['exclude'])) { + $dep['exclude'] = array($dep['exclude']); + } + foreach ($dep['exclude'] as $exclude) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $exclude)) { + $this->_invalidVersion('' . $group . $type . '', + $exclude); + } } } - return $pass; - } - - function _differentPackage($package) - { - $this->_stack->push(__FUNCTION__, 'error', array('package' => $package, - 'self' => $this->getPackage()), - 'package.xml 1.0 package "%package%" does not match "%self%"'); - } - - function _differentVersion($version) - { - $this->_stack->push(__FUNCTION__, 'error', array('version' => $version, - 'self' => $this->getVersion()), - 'package.xml 1.0 version "%version%" does not match "%self%"'); - } - - function _differentState($state) - { - $this->_stack->push(__FUNCTION__, 'error', array('state' => $state, - 'self' => $this->getState()), - 'package.xml 1.0 state "%state%" does not match "%self%"'); - } - - function _differentRole($handle, $role, $selfrole) - { - $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle, - 'role' => $role, 'self' => $selfrole), - 'package.xml 1.0 maintainer "%handle%" role "%role%" does not match "%self%"'); - } - - function _differentEmail($handle, $email, $selfemail) - { - $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle, - 'email' => $email, 'self' => $selfemail), - 'package.xml 1.0 maintainer "%handle%" email "%email%" does not match "%self%"'); - } - - function _differentName($handle, $name, $selfname) - { - $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle, - 'name' => $name, 'self' => $selfname), - 'package.xml 1.0 maintainer "%handle%" name "%name%" does not match "%self%"'); } - function _unmatchedMaintainers($my, $yours) + function _validateSubpackageDep($dep, $group) { - if ($my) { - array_walk($my, create_function('&$i, $k', '$i = $i["handle"];')); - $this->_stack->push(__FUNCTION__, 'error', array('handles' => $my), - 'package.xml 2.0 has unmatched extra maintainers "%handles%"'); + $this->_validatePackageDep($dep, $group, ''); + if (isset($dep['providesextension'])) { + $this->_subpackageCannotProvideExtension(isset($dep['name']) ? $dep['name'] : ''); } - if ($yours) { - array_walk($yours, create_function('&$i, $k', '$i = $i["handle"];')); - $this->_stack->push(__FUNCTION__, 'error', array('handles' => $yours), - 'package.xml 1.0 has unmatched extra maintainers "%handles%"'); + if (isset($dep['conflicts'])) { + $this->_subpackagesCannotConflict(isset($dep['name']) ? $dep['name'] : ''); } } - function _differentNotes($notes) - { - $truncnotes = strlen($notes) < 25 ? $notes : substr($notes, 0, 24) . '...'; - $truncmynotes = strlen($this->getNotes()) < 25 ? $this->getNotes() : - substr($this->getNotes(), 0, 24) . '...'; - $this->_stack->push(__FUNCTION__, 'error', array('notes' => $truncnotes, - 'self' => $truncmynotes), - 'package.xml 1.0 release notes "%notes%" do not match "%self%"'); - } - - function _differentSummary($summary) - { - $truncsummary = strlen($summary) < 25 ? $summary : substr($summary, 0, 24) . '...'; - $truncmysummary = strlen($this->getsummary()) < 25 ? $this->getSummary() : - substr($this->getsummary(), 0, 24) . '...'; - $this->_stack->push(__FUNCTION__, 'error', array('summary' => $truncsummary, - 'self' => $truncmysummary), - 'package.xml 1.0 summary "%summary%" does not match "%self%"'); - } - - function _differentDescription($description) - { - $truncdescription = trim(strlen($description) < 25 ? $description : substr($description, 0, 24) . '...'); - $truncmydescription = trim(strlen($this->getDescription()) < 25 ? $this->getDescription() : - substr($this->getdescription(), 0, 24) . '...'); - $this->_stack->push(__FUNCTION__, 'error', array('description' => $truncdescription, - 'self' => $truncmydescription), - 'package.xml 1.0 description "%description%" does not match "%self%"'); - } - - function _missingFile($file) - { - $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), - 'package.xml 1.0 file "%file%" is not present in '); - } - - /** - * WARNING - do not use this function unless you know what you're doing - */ - function setRawState($state) + function _validateExtensionDep($dep, $group = false, $installcondition = false) { - if (!isset($this->_packageInfo['stability'])) { - $this->_packageInfo['stability'] = array(); + if (isset($dep['conflicts'])) { + $structure = array( + 'name', + '*min', + '*max', + '*exclude', + 'conflicts', + ); + } else { + $structure = array( + 'name', + '*min', + '*max', + '*recommended', + '*exclude', + ); + } + if ($installcondition) { + $type = ''; + } else { + $type = '' . $group . ''; + } + if (isset($dep['name'])) { + $type .= '' . $dep['name'] . ''; + } + $this->_stupidSchemaValidate($structure, $dep, $type); + if (isset($dep['min'])) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $dep['min'])) { + $this->_invalidVersion(substr($type, 1) . '_invalidVersion(substr($type, 1) . '_invalidVersion(substr($type, 1) . '_invalidVersion(substr($type, 1) . '_packageInfo['stability']['release'] = $state; - } - - /** - * WARNING - do not use this function unless you know what you're doing - */ - function setRawCompatible($compatible) - { - $this->_packageInfo['compatible'] = $compatible; } - /** - * WARNING - do not use this function unless you know what you're doing - */ - function setRawPackage($package) + function _validateOsDep($dep, $installcondition = false) { - $this->_packageInfo['name'] = $package; + $structure = array( + 'name', + '*conflicts', + ); + $type = $installcondition ? '' : ''; + if ($this->_stupidSchemaValidate($structure, $dep, $type)) { + if ($dep['name'] == '*') { + if (array_key_exists('conflicts', $dep)) { + $this->_cannotConflictWithAllOs($type); + } + } + } } - /** - * WARNING - do not use this function unless you know what you're doing - */ - function setRawChannel($channel) + function _validateArchDep($dep, $installcondition = false) { - $this->_packageInfo['channel'] = $channel; + $structure = array( + 'pattern', + '*conflicts', + ); + $type = $installcondition ? '' : ''; + $this->_stupidSchemaValidate($structure, $dep, $type); } - function setRequestedGroup($group) + function _validateInstallConditions($cond, $release) { - $this->_requestedGroup = $group; + $structure = array( + '*php', + '*extension', + '*os', + '*arch', + ); + if (!$this->_stupidSchemaValidate($structure, + $cond, $release)) { + return false; + } + foreach (array('php', 'extension', 'os', 'arch') as $type) { + if (isset($cond[$type])) { + $iter = $cond[$type]; + if (!is_array($iter) || !isset($iter[0])) { + $iter = array($iter); + } + foreach ($iter as $package) { + if ($type == 'extension') { + $this->{"_validate{$type}Dep"}($package, false, true); + } else { + $this->{"_validate{$type}Dep"}($package, true); + } + } + } + } } - function getRequestedGroup() + function _validateDependencies() { - if (isset($this->_requestedGroup)) { - return $this->_requestedGroup; + $structure = array( + 'required', + '*optional', + '*group->name->hint' + ); + if (!$this->_stupidSchemaValidate($structure, + $this->_packageInfo['dependencies'], '')) { + return false; + } + foreach (array('required', 'optional') as $simpledep) { + if (isset($this->_packageInfo['dependencies'][$simpledep])) { + if ($simpledep == 'optional') { + $structure = array( + '*package', + '*subpackage', + '*extension', + ); + } else { + $structure = array( + 'php', + 'pearinstaller', + '*package', + '*subpackage', + '*extension', + '*os', + '*arch', + ); + } + if ($this->_stupidSchemaValidate($structure, + $this->_packageInfo['dependencies'][$simpledep], + "<$simpledep>")) { + foreach (array('package', 'subpackage', 'extension') as $type) { + if (isset($this->_packageInfo['dependencies'][$simpledep][$type])) { + $iter = $this->_packageInfo['dependencies'][$simpledep][$type]; + if (!isset($iter[0])) { + $iter = array($iter); + } + foreach ($iter as $package) { + if ($type != 'extension') { + if (isset($package['uri'])) { + if (isset($package['channel'])) { + $this->_UrlOrChannel($type, + $package['name']); + } + } else { + if (!isset($package['channel'])) { + $this->_NoChannel($type, $package['name']); + } + } + } + $this->{"_validate{$type}Dep"}($package, "<$simpledep>"); + } + } + } + if ($simpledep == 'optional') { + continue; + } + foreach (array('php', 'pearinstaller', 'os', 'arch') as $type) { + if (isset($this->_packageInfo['dependencies'][$simpledep][$type])) { + $iter = $this->_packageInfo['dependencies'][$simpledep][$type]; + if (!isset($iter[0])) { + $iter = array($iter); + } + foreach ($iter as $package) { + $this->{"_validate{$type}Dep"}($package); + } + } + } + } + } + } + if (isset($this->_packageInfo['dependencies']['group'])) { + $groups = $this->_packageInfo['dependencies']['group']; + if (!isset($groups[0])) { + $groups = array($groups); + } + $structure = array( + '*package', + '*subpackage', + '*extension', + ); + foreach ($groups as $group) { + if ($this->_stupidSchemaValidate($structure, $group, '')) { + if (!PEAR_Validate::validGroupName($group['attribs']['name'])) { + $this->_invalidDepGroupName($group['attribs']['name']); + } + foreach (array('package', 'subpackage', 'extension') as $type) { + if (isset($group[$type])) { + $iter = $group[$type]; + if (!isset($iter[0])) { + $iter = array($iter); + } + foreach ($iter as $package) { + if ($type != 'extension') { + if (isset($package['uri'])) { + if (isset($package['channel'])) { + $this->_UrlOrChannelGroup($type, + $package['name'], + $group['name']); + } + } else { + if (!isset($package['channel'])) { + $this->_NoChannelGroup($type, + $package['name'], + $group['name']); + } + } + } + $this->{"_validate{$type}Dep"}($package, ''); + } + } + } + } + } } - return false; } - /** - * For saving in the registry. - * - * Set the last version that was installed - * @param string - */ - function setLastInstalledVersion($version) + function _validateCompatible() { - $this->_packageInfo['_lastversion'] = $version; + $compat = $this->_packageInfo['compatible']; + if (!isset($compat[0])) { + $compat = array($compat); + } + $required = array('name', 'channel', 'min', 'max', '*exclude'); + foreach ($compat as $package) { + $type = ''; + if (is_array($package) && array_key_exists('name', $package)) { + $type .= '' . $package['name'] . ''; + } + $this->_stupidSchemaValidate($required, $package, $type); + if (is_array($package) && array_key_exists('min', $package)) { + if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', + $package['min'])) { + $this->_invalidVersion(substr($type, 1) . '_invalidVersion(substr($type, 1) . '_invalidVersion(substr($type, 1) . '_packageInfo['_lastversion'])) { - return $this->_packageInfo['_lastversion']; + if (!is_array($list) || !isset($list['bundledpackage'])) { + return $this->_NoBundledPackages(); + } + if (!is_array($list['bundledpackage']) || !isset($list['bundledpackage'][0])) { + return $this->_AtLeast2BundledPackages(); + } + foreach ($list['bundledpackage'] as $package) { + if (!is_string($package)) { + $this->_bundledPackagesMustBeFilename(); + } } - return false; } - /** - * Determines whether this package.xml has post-install scripts or not - * @return array|false - */ - function listPostinstallScripts() + function _validateFilelist($list = false, $allowignore = false, $dirs = '') { - $filelist = $this->getFilelist(); - $contents = $this->getContents(); - $contents = $contents['dir']['file']; - if (!is_array($contents) || !isset($contents[0])) { - $contents = array($contents); + $iscontents = false; + if (!$list) { + $iscontents = true; + $list = $this->_packageInfo['contents']; + if (isset($this->_packageInfo['bundle'])) { + return $this->_validateBundle($list); + } } - $taskfiles = array(); - foreach ($contents as $file) { - $atts = $file['attribs']; - unset($file['attribs']); - if (count($file)) { - $taskfiles[$atts['name']] = $file; + if ($allowignore) { + $struc = array( + '*install->name->as', + '*ignore->name' + ); + } else { + $struc = array( + '*dir->name->?baseinstalldir', + '*file->name->role->?baseinstalldir->?md5sum' + ); + if (isset($list['dir']) && isset($list['file'])) { + // stave off validation errors without requiring a set order. + $_old = $list; + if (isset($list['attribs'])) { + $list = array('attribs' => $_old['attribs']); + } + $list['dir'] = $_old['dir']; + $list['file'] = $_old['file']; } } - $common = new PEAR_Common; - $common->debug = $this->_config->get('verbose'); - $this->_scripts = array(); - $ret = array(); - foreach ($taskfiles as $name => $tasks) { - if (!isset($filelist[$name])) { - // ignored files will not be in the filelist - continue; + if (!isset($list['attribs']) || !isset($list['attribs']['name'])) { + $unknown = $allowignore ? '' : ''; + $dirname = $iscontents ? '' : $unknown; + } else { + $dirname = ''; + if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~', + str_replace('\\', '/', $list['attribs']['name']))) { + // file contains .. parent directory or . cur directory + $this->_invalidDirName($list['attribs']['name']); } - $atts = $filelist[$name]; - foreach ($tasks as $tag => $raw) { - $task = $this->getTask($tag); - $task = &new $task($this->_config, $common, PEAR_TASK_INSTALL); - if ($task->isScript()) { - $ret[] = $filelist[$name]['installed_as']; + } + $res = $this->_stupidSchemaValidate($struc, $list, $dirname); + if ($allowignore && $res) { + $ignored_or_installed = array(); + $this->_pf->getFilelist(); + $fcontents = $this->_pf->getContents(); + $filelist = array(); + if (!isset($fcontents['dir']['file'][0])) { + $fcontents['dir']['file'] = array($fcontents['dir']['file']); + } + foreach ($fcontents['dir']['file'] as $file) { + $filelist[$file['attribs']['name']] = true; + } + if (isset($list['install'])) { + if (!isset($list['install'][0])) { + $list['install'] = array($list['install']); + } + foreach ($list['install'] as $file) { + if (!isset($filelist[$file['attribs']['name']])) { + $this->_notInContents($file['attribs']['name'], 'install'); + continue; + } + if (array_key_exists($file['attribs']['name'], $ignored_or_installed)) { + $this->_multipleInstallAs($file['attribs']['name']); + } + if (!isset($ignored_or_installed[$file['attribs']['name']])) { + $ignored_or_installed[$file['attribs']['name']] = array(); + } + $ignored_or_installed[$file['attribs']['name']][] = 1; + if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~', + str_replace('\\', '/', $file['attribs']['as']))) { + // file contains .. parent directory or . cur directory references + $this->_invalidFileInstallAs($file['attribs']['name'], + $file['attribs']['as']); + } + } + } + if (isset($list['ignore'])) { + if (!isset($list['ignore'][0])) { + $list['ignore'] = array($list['ignore']); + } + foreach ($list['ignore'] as $file) { + if (!isset($filelist[$file['attribs']['name']])) { + $this->_notInContents($file['attribs']['name'], 'ignore'); + continue; + } + if (array_key_exists($file['attribs']['name'], $ignored_or_installed)) { + $this->_ignoreAndInstallAs($file['attribs']['name']); + } } } } - if (count($ret)) { - return $ret; + if (!$allowignore && isset($list['file'])) { + if (is_string($list['file'])) { + $this->_oldStyleFileNotAllowed(); + return false; + } + if (!isset($list['file'][0])) { + // single file + $list['file'] = array($list['file']); + } + foreach ($list['file'] as $i => $file) + { + if (isset($file['attribs']) && isset($file['attribs']['name'])) { + if ($file['attribs']['name']{0} == '.' && + $file['attribs']['name']{1} == '/') { + // name is something like "./doc/whatever.txt" + $this->_invalidFileName($file['attribs']['name'], $dirname); + } + if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~', + str_replace('\\', '/', $file['attribs']['name']))) { + // file contains .. parent directory or . cur directory + $this->_invalidFileName($file['attribs']['name'], $dirname); + } + } + if (isset($file['attribs']) && isset($file['attribs']['role'])) { + if (!$this->_validateRole($file['attribs']['role'])) { + if (isset($this->_packageInfo['usesrole'])) { + $roles = $this->_packageInfo['usesrole']; + if (!isset($roles[0])) { + $roles = array($roles); + } + foreach ($roles as $role) { + if ($role['role'] = $file['attribs']['role']) { + $msg = 'This package contains role "%role%" and requires ' . + 'package "%package%" to be used'; + if (isset($role['uri'])) { + $params = array('role' => $role['role'], + 'package' => $role['uri']); + } else { + $params = array('role' => $role['role'], + 'package' => $this->_pf->_registry-> + parsedPackageNameToString(array('package' => + $role['package'], 'channel' => $role['channel']), + true)); + } + $this->_stack->push('_mustInstallRole', 'error', $params, $msg); + } + } + } + $this->_invalidFileRole($file['attribs']['name'], + $dirname, $file['attribs']['role']); + } + } + if (!isset($file['attribs'])) { + continue; + } + $save = $file['attribs']; + if ($dirs) { + $save['name'] = $dirs . '/' . $save['name']; + } + unset($file['attribs']); + if (count($file) && $this->_curState != PEAR_VALIDATE_DOWNLOADING) { // has tasks + foreach ($file as $task => $value) { + if ($tagClass = $this->_pf->getTask($task)) { + if (!is_array($value) || !isset($value[0])) { + $value = array($value); + } + foreach ($value as $v) { + $ret = call_user_func(array($tagClass, 'validateXml'), + $this->_pf, $v, $this->_pf->_config, $save); + if (is_array($ret)) { + $this->_invalidTask($task, $ret, isset($save['name']) ? + $save['name'] : ''); + } + } + } else { + if (isset($this->_packageInfo['usestask'])) { + $roles = $this->_packageInfo['usestask']; + if (!isset($roles[0])) { + $roles = array($roles); + } + foreach ($roles as $role) { + if ($role['task'] = $task) { + $msg = 'This package contains task "%task%" and requires ' . + 'package "%package%" to be used'; + if (isset($role['uri'])) { + $params = array('task' => $role['task'], + 'package' => $role['uri']); + } else { + $params = array('task' => $role['task'], + 'package' => $this->_pf->_registry-> + parsedPackageNameToString(array('package' => + $role['package'], 'channel' => $role['channel']), + true)); + } + $this->_stack->push('_mustInstallTask', 'error', + $params, $msg); + } + } + } + $this->_unknownTask($task, $save['name']); + } + } + } + } } - return false; - } - - /** - * Initialize post-install scripts for running - * - * This method can be used to detect post-install scripts, as the return value - * indicates whether any exist - * @return bool - */ - function initPostinstallScripts() - { - $filelist = $this->getFilelist(); - $contents = $this->getContents(); - $contents = $contents['dir']['file']; - if (!is_array($contents) || !isset($contents[0])) { - $contents = array($contents); + if (isset($list['ignore'])) { + if (!$allowignore) { + $this->_ignoreNotAllowed('ignore'); + } } - $taskfiles = array(); - foreach ($contents as $file) { - $atts = $file['attribs']; - unset($file['attribs']); - if (count($file)) { - $taskfiles[$atts['name']] = $file; + if (isset($list['install'])) { + if (!$allowignore) { + $this->_ignoreNotAllowed('install'); } } - $common = new PEAR_Common; - $common->debug = $this->_config->get('verbose'); - $this->_scripts = array(); - foreach ($taskfiles as $name => $tasks) { - if (!isset($filelist[$name])) { - // file was not installed due to installconditions - continue; + if (isset($list['file'])) { + if ($allowignore) { + $this->_fileNotAllowed('file'); } - $atts = $filelist[$name]; - foreach ($tasks as $tag => $raw) { - $taskname = $this->getTask($tag); - $task = &new $taskname($this->_config, $common, PEAR_TASK_INSTALL); - if (!$task->isScript()) { - continue; // scripts are only handled after installation - } - $lastversion = isset($this->_packageInfo['_lastversion']) ? - $this->_packageInfo['_lastversion'] : null; - $task->init($raw, $atts, $lastversion); - $res = $task->startSession($this, $atts['installed_as']); - if (!$res) { - continue; // skip this file + } + if (isset($list['dir'])) { + if ($allowignore) { + $this->_fileNotAllowed('dir'); + } else { + if (!isset($list['dir'][0])) { + $list['dir'] = array($list['dir']); } - if (PEAR::isError($res)) { - return $res; + foreach ($list['dir'] as $dir) { + if (isset($dir['attribs']) && isset($dir['attribs']['name'])) { + if ($dir['attribs']['name'] == '/' || + !isset($this->_packageInfo['contents']['dir']['dir'])) { + // always use nothing if the filelist has already been flattened + $newdirs = ''; + } elseif ($dirs == '') { + $newdirs = $dir['attribs']['name']; + } else { + $newdirs = $dirs . '/' . $dir['attribs']['name']; + } + } else { + $newdirs = $dirs; + } + $this->_validateFilelist($dir, $allowignore, $newdirs); } - $assign = &$task; - $this->_scripts[] = &$assign; } } - if (count($this->_scripts)) { - return true; - } - return false; } - function runPostinstallScripts() + function _validateRelease() { - if ($this->initPostinstallScripts()) { - $ui = &PEAR_Frontend::singleton(); - if ($ui) { - $ui->runPostinstallScripts($this->_scripts, $this); + if (isset($this->_packageInfo['phprelease'])) { + $release = 'phprelease'; + if (isset($this->_packageInfo['providesextension'])) { + $this->_cannotProvideExtension($release); } - } - } - - - /** - * Convert a recursive set of and tags into a single tag with - * tags. - */ - function flattenFilelist() - { - if (isset($this->_packageInfo['bundle'])) { - return; - } - $filelist = array(); - if (isset($this->_packageInfo['contents']['dir']['dir'])) { - $this->_getFlattenedFilelist($filelist, $this->_packageInfo['contents']['dir']); - if (!isset($filelist[1])) { - $filelist = $filelist[0]; + if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) { + $this->_cannotHaveSrcpackage($release); } - $this->_packageInfo['contents']['dir']['file'] = $filelist; - unset($this->_packageInfo['contents']['dir']['dir']); - } else { - // else already flattened but check for baseinstalldir propagation - if (isset($this->_packageInfo['contents']['dir']['attribs']['baseinstalldir'])) { - if (isset($this->_packageInfo['contents']['dir']['file'][0])) { - foreach ($this->_packageInfo['contents']['dir']['file'] as $i => $file) { - if (isset($file['attribs']['baseinstalldir'])) { - continue; + $releases = $this->_packageInfo['phprelease']; + if (!is_array($releases)) { + return true; + } + if (!isset($releases[0])) { + $releases = array($releases); + } + foreach ($releases as $rel) { + $this->_stupidSchemaValidate(array( + '*installconditions', + '*filelist', + ), $rel, ''); + } + } + foreach (array('', 'zend') as $prefix) { + $releasetype = $prefix . 'extsrcrelease'; + if (isset($this->_packageInfo[$releasetype])) { + $release = $releasetype; + if (!isset($this->_packageInfo['providesextension'])) { + $this->_mustProvideExtension($release); + } + if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) { + $this->_cannotHaveSrcpackage($release); + } + $releases = $this->_packageInfo[$releasetype]; + if (!is_array($releases)) { + return true; + } + if (!isset($releases[0])) { + $releases = array($releases); + } + foreach ($releases as $rel) { + $this->_stupidSchemaValidate(array( + '*installconditions', + '*configureoption->name->prompt->?default', + '*binarypackage', + '*filelist', + ), $rel, '<' . $releasetype . '>'); + if (isset($rel['binarypackage'])) { + if (!is_array($rel['binarypackage']) || !isset($rel['binarypackage'][0])) { + $rel['binarypackage'] = array($rel['binarypackage']); + } + foreach ($rel['binarypackage'] as $bin) { + if (!is_string($bin)) { + $this->_binaryPackageMustBePackagename(); + } } - $this->_packageInfo['contents']['dir']['file'][$i]['attribs']['baseinstalldir'] - = $this->_packageInfo['contents']['dir']['attribs']['baseinstalldir']; - } - } else { - if (!isset($this->_packageInfo['contents']['dir']['file']['attribs']['baseinstalldir'])) { - $this->_packageInfo['contents']['dir']['file']['attribs']['baseinstalldir'] - = $this->_packageInfo['contents']['dir']['attribs']['baseinstalldir']; } } } + $releasetype = 'extbinrelease'; + if (isset($this->_packageInfo[$releasetype])) { + $release = $releasetype; + if (!isset($this->_packageInfo['providesextension'])) { + $this->_mustProvideExtension($release); + } + if (isset($this->_packageInfo['channel']) && + !isset($this->_packageInfo['srcpackage'])) { + $this->_mustSrcPackage($release); + } + if (isset($this->_packageInfo['uri']) && !isset($this->_packageInfo['srcuri'])) { + $this->_mustSrcuri($release); + } + $releases = $this->_packageInfo[$releasetype]; + if (!is_array($releases)) { + return true; + } + if (!isset($releases[0])) { + $releases = array($releases); + } + foreach ($releases as $rel) { + $this->_stupidSchemaValidate(array( + '*installconditions', + '*filelist', + ), $rel, '<' . $releasetype . '>'); + } + } } - } - - /** - * @param array the final flattened file list - * @param array the current directory being processed - * @param string|false any recursively inherited baeinstalldir attribute - * @param string private recursion variable - * @return array - * @access protected - */ - function _getFlattenedFilelist(&$files, $dir, $baseinstall = false, $path = '') - { - if (isset($dir['attribs']) && isset($dir['attribs']['baseinstalldir'])) { - $baseinstall = $dir['attribs']['baseinstalldir']; - } - if (isset($dir['dir'])) { - if (!isset($dir['dir'][0])) { - $dir['dir'] = array($dir['dir']); + if (isset($this->_packageInfo['bundle'])) { + $release = 'bundle'; + if (isset($this->_packageInfo['providesextension'])) { + $this->_cannotProvideExtension($release); } - foreach ($dir['dir'] as $subdir) { - if (!isset($subdir['attribs']) || !isset($subdir['attribs']['name'])) { - $name = '*unknown*'; - } else { - $name = $subdir['attribs']['name']; - } - $newpath = empty($path) ? $name : - $path . '/' . $name; - $this->_getFlattenedFilelist($files, $subdir, - $baseinstall, $newpath); + if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) { + $this->_cannotHaveSrcpackage($release); + } + $releases = $this->_packageInfo['bundle']; + if (!is_array($releases) || !isset($releases[0])) { + $releases = array($releases); + } + foreach ($releases as $rel) { + $this->_stupidSchemaValidate(array( + '*installconditions', + '*filelist', + ), $rel, ''); } } - if (isset($dir['file'])) { - if (!isset($dir['file'][0])) { - $dir['file'] = array($dir['file']); + foreach ($releases as $rel) { + if (is_array($rel) && array_key_exists('installconditions', $rel)) { + $this->_validateInstallConditions($rel['installconditions'], + "<$release>"); } - foreach ($dir['file'] as $file) { - $attrs = $file['attribs']; - $name = $attrs['name']; - if ($baseinstall && !isset($attrs['baseinstalldir'])) { - $attrs['baseinstalldir'] = $baseinstall; + if (is_array($rel) && array_key_exists('filelist', $rel)) { + if ($rel['filelist']) { + + $this->_validateFilelist($rel['filelist'], true); } - $attrs['name'] = empty($path) ? $name : $path . '/' . $name; - $attrs['name'] = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), - $attrs['name']); - $file['attribs'] = $attrs; - $files[] = $file; } } } - function setConfig(&$config) + /** + * This is here to allow role extension through plugins + * @param string + */ + function _validateRole($role) { - $this->_config = &$config; - $this->_registry = &$config->getRegistry(); + return in_array($role, PEAR_Installer_Role::getValidRoles($this->_pf->getPackageType())); } - function setLogger(&$logger) + function _pearVersionTooLow($version) { - if (!is_object($logger) || !method_exists($logger, 'log')) { - return PEAR::raiseError('Logger must be compatible with PEAR_Common::log'); - } - $this->_logger = &$logger; + $this->_stack->push(__FUNCTION__, 'error', + array('version' => $version), + 'This package.xml requires PEAR version %version% to parse properly, we are ' . + 'version 1.9.0'); } - /** - * WARNING - do not use this function directly unless you know what you're doing - */ - function setDeps($deps) + function _invalidTagOrder($oktags, $actual, $root) { - $this->_packageInfo['dependencies'] = $deps; + $this->_stack->push(__FUNCTION__, 'error', + array('oktags' => $oktags, 'actual' => $actual, 'root' => $root), + 'Invalid tag order in %root%, found <%actual%> expected one of "%oktags%"'); } - /** - * WARNING - do not use this function directly unless you know what you're doing - */ - function setCompatible($compat) + function _ignoreNotAllowed($type) { - $this->_packageInfo['compatible'] = $compat; + $this->_stack->push(__FUNCTION__, 'error', array('type' => $type), + '<%type%> is not allowed inside global , only inside ' . + '//, use and only'); } - function setPackagefile($file, $archive = false) + function _fileNotAllowed($type) { - $this->_packageFile = $file; - $this->_archiveFile = $archive ? $archive : $file; + $this->_stack->push(__FUNCTION__, 'error', array('type' => $type), + '<%type%> is not allowed inside release , only inside ' . + ', use and only'); } - /** - * Wrapper to {@link PEAR_ErrorStack::getErrors()} - * @param boolean determines whether to purge the error stack after retrieving - * @return array - */ - function getValidationWarnings($purge = true) + function _oldStyleFileNotAllowed() { - return $this->_stack->getErrors($purge); + $this->_stack->push(__FUNCTION__, 'error', array(), + 'Old-style name is not allowed. Use' . + ''); } - function getPackageFile() + function _tagMissingAttribute($tag, $attr, $context) { - return $this->_packageFile; + $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag, + 'attribute' => $attr, 'context' => $context), + 'tag <%tag%> in context "%context%" has no attribute "%attribute%"'); } - function getArchiveFile() + function _tagHasNoAttribs($tag, $context) { - return $this->_archiveFile; + $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag, + 'context' => $context), + 'tag <%tag%> has no attributes in context "%context%"'); } - - /** - * Directly set the array that defines this packagefile - * - * WARNING: no validation. This should only be performed by internal methods - * inside PEAR or by inputting an array saved from an existing PEAR_PackageFile_v2 - * @param array - */ - function fromArray($pinfo) + function _invalidInternalStructure() { - unset($pinfo['old']); - unset($pinfo['xsdversion']); - $this->_incomplete = false; - $this->_packageInfo = $pinfo; + $this->_stack->push(__FUNCTION__, 'exception', array(), + 'internal array was not generated by compatible parser, or extreme parser error, cannot continue'); } - function isIncomplete() + function _invalidFileRole($file, $dir, $role) { - return $this->_incomplete; + $this->_stack->push(__FUNCTION__, 'error', array( + 'file' => $file, 'dir' => $dir, 'role' => $role, + 'roles' => PEAR_Installer_Role::getValidRoles($this->_pf->getPackageType())), + 'File "%file%" in directory "%dir%" has invalid role "%role%", should be one of %roles%'); } - /** - * @return array - */ - function toArray($forreg = false) + function _invalidFileName($file, $dir) { - if (!$this->validate(PEAR_VALIDATE_NORMAL)) { - return false; - } - return $this->getArray($forreg); + $this->_stack->push(__FUNCTION__, 'error', array( + 'file' => $file), + 'File "%file%" in directory "%dir%" cannot begin with "./" or contain ".."'); } - function getArray($forReg = false) + function _invalidFileInstallAs($file, $as) { - if ($forReg) { - $arr = $this->_packageInfo; - $arr['old'] = array(); - $arr['old']['version'] = $this->getVersion(); - $arr['old']['release_date'] = $this->getDate(); - $arr['old']['release_state'] = $this->getState(); - $arr['old']['release_license'] = $this->getLicense(); - $arr['old']['release_notes'] = $this->getNotes(); - $arr['old']['release_deps'] = $this->getDeps(); - $arr['old']['maintainers'] = $this->getMaintainers(); - $arr['xsdversion'] = '2.0'; - return $arr; - } else { - $info = $this->_packageInfo; - unset($info['dirtree']); - if (isset($info['_lastversion'])) { - unset($info['_lastversion']); - } - if (isset($info['#binarypackage'])) { - unset($info['#binarypackage']); - } - return $info; - } + $this->_stack->push(__FUNCTION__, 'error', array( + 'file' => $file, 'as' => $as), + 'File "%file%" cannot contain "./" or contain ".."'); } - function packageInfo($field) + function _invalidDirName($dir) { - $arr = $this->getArray(true); - if ($field == 'state') { - return $arr['stability']['release']; - } - if ($field == 'api-version') { - return $arr['version']['api']; - } - if ($field == 'api-state') { - return $arr['stability']['api']; - } - if (isset($arr['old'][$field])) { - if (!is_string($arr['old'][$field])) { - return null; - } - return $arr['old'][$field]; - } - if (isset($arr[$field])) { - if (!is_string($arr[$field])) { - return null; - } - return $arr[$field]; - } - return null; + $this->_stack->push(__FUNCTION__, 'error', array( + 'dir' => $file), + 'Directory "%dir%" cannot begin with "./" or contain ".."'); } - function getName() + function _filelistCannotContainFile($filelist) { - return $this->getPackage(); + $this->_stack->push(__FUNCTION__, 'error', array('tag' => $filelist), + '<%tag%> can only contain , contains . Use ' . + ' as the first dir element'); } - function getPackage() + function _filelistMustContainDir($filelist) { - if (isset($this->_packageInfo['name'])) { - return $this->_packageInfo['name']; - } - return false; + $this->_stack->push(__FUNCTION__, 'error', array('tag' => $filelist), + '<%tag%> must contain . Use as the ' . + 'first dir element'); } - function getChannel() + function _tagCannotBeEmpty($tag) { - if (isset($this->_packageInfo['uri'])) { - return '__uri'; - } - if (isset($this->_packageInfo['channel'])) { - return strtolower($this->_packageInfo['channel']); - } - return false; + $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag), + '<%tag%> cannot be empty (<%tag%/>)'); } - function getUri() + function _UrlOrChannel($type, $name) { - if (isset($this->_packageInfo['uri'])) { - return $this->_packageInfo['uri']; - } - return false; + $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, + 'name' => $name), + 'Required dependency <%type%> "%name%" can have either url OR ' . + 'channel attributes, and not both'); } - function getExtends() + function _NoChannel($type, $name) { - if (isset($this->_packageInfo['extends'])) { - return $this->_packageInfo['extends']; - } - return false; + $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, + 'name' => $name), + 'Required dependency <%type%> "%name%" must have either url OR ' . + 'channel attributes'); } - function getSummary() + function _UrlOrChannelGroup($type, $name, $group) { - if (isset($this->_packageInfo['summary'])) { - return $this->_packageInfo['summary']; - } - return false; + $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, + 'name' => $name, 'group' => $group), + 'Group "%group%" dependency <%type%> "%name%" can have either url OR ' . + 'channel attributes, and not both'); } - function getDescription() + function _NoChannelGroup($type, $name, $group) { - if (isset($this->_packageInfo['description'])) { - return $this->_packageInfo['description']; - } - return false; + $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, + 'name' => $name, 'group' => $group), + 'Group "%group%" dependency <%type%> "%name%" must have either url OR ' . + 'channel attributes'); } - function getMaintainers($raw = false) + function _unknownChannel($channel) { - if (!isset($this->_packageInfo['lead'])) { - return false; - } - if ($raw) { - $ret = array('lead' => $this->_packageInfo['lead']); - (isset($this->_packageInfo['developer'])) ? - $ret['developer'] = $this->_packageInfo['developer'] :null; - (isset($this->_packageInfo['contributor'])) ? - $ret['contributor'] = $this->_packageInfo['contributor'] :null; - (isset($this->_packageInfo['helper'])) ? - $ret['helper'] = $this->_packageInfo['helper'] :null; - return $ret; - } else { - $ret = array(); - $leads = isset($this->_packageInfo['lead'][0]) ? $this->_packageInfo['lead'] : - array($this->_packageInfo['lead']); - foreach ($leads as $lead) { - $s = $lead; - $s['handle'] = $s['user']; - unset($s['user']); - $s['role'] = 'lead'; - $ret[] = $s; - } - if (isset($this->_packageInfo['developer'])) { - $leads = isset($this->_packageInfo['developer'][0]) ? - $this->_packageInfo['developer'] : - array($this->_packageInfo['developer']); - foreach ($leads as $maintainer) { - $s = $maintainer; - $s['handle'] = $s['user']; - unset($s['user']); - $s['role'] = 'developer'; - $ret[] = $s; - } - } - if (isset($this->_packageInfo['contributor'])) { - $leads = isset($this->_packageInfo['contributor'][0]) ? - $this->_packageInfo['contributor'] : - array($this->_packageInfo['contributor']); - foreach ($leads as $maintainer) { - $s = $maintainer; - $s['handle'] = $s['user']; - unset($s['user']); - $s['role'] = 'contributor'; - $ret[] = $s; - } - } - if (isset($this->_packageInfo['helper'])) { - $leads = isset($this->_packageInfo['helper'][0]) ? - $this->_packageInfo['helper'] : - array($this->_packageInfo['helper']); - foreach ($leads as $maintainer) { - $s = $maintainer; - $s['handle'] = $s['user']; - unset($s['user']); - $s['role'] = 'helper'; - $ret[] = $s; - } - } - return $ret; - } - return false; + $this->_stack->push(__FUNCTION__, 'error', array('channel' => $channel), + 'Unknown channel "%channel%"'); } - function getLeads() + function _noPackageVersion() { - if (isset($this->_packageInfo['lead'])) { - return $this->_packageInfo['lead']; - } - return false; + $this->_stack->push(__FUNCTION__, 'error', array(), + 'package.xml tag has no version attribute, or version is not 2.0'); } - function getDevelopers() + function _NoBundledPackages() { - if (isset($this->_packageInfo['developer'])) { - return $this->_packageInfo['developer']; - } - return false; + $this->_stack->push(__FUNCTION__, 'error', array(), + 'No tag was found in , required for bundle packages'); } - function getContributors() + function _AtLeast2BundledPackages() { - if (isset($this->_packageInfo['contributor'])) { - return $this->_packageInfo['contributor']; - } - return false; + $this->_stack->push(__FUNCTION__, 'error', array(), + 'At least 2 packages must be bundled in a bundle package'); } - function getHelpers() + function _ChannelOrUri($name) { - if (isset($this->_packageInfo['helper'])) { - return $this->_packageInfo['helper']; - } - return false; + $this->_stack->push(__FUNCTION__, 'error', array('name' => $name), + 'Bundled package "%name%" can have either a uri or a channel, not both'); } - function setDate($date) + function _noChildTag($child, $tag) { - if (!isset($this->_packageInfo['date'])) { - // ensure that the extends tag is set up in the right location - $this->_packageInfo = $this->_insertBefore($this->_packageInfo, - array('time', 'version', - 'stability', 'license', 'notes', 'contents', 'compatible', - 'dependencies', 'providesextension', 'srcpackage', 'srcuri', - 'phprelease', 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease', - 'zendextbinrelease', 'bundle', 'changelog'), array(), 'date'); - } - $this->_packageInfo['date'] = $date; - $this->_isValid = 0; + $this->_stack->push(__FUNCTION__, 'error', array('child' => $child, 'tag' => $tag), + 'Tag <%tag%> is missing child tag <%child%>'); } - function setTime($time) + function _invalidVersion($type, $value) { - $this->_isValid = 0; - if (!isset($this->_packageInfo['time'])) { - // ensure that the time tag is set up in the right location - $this->_packageInfo = $this->_insertBefore($this->_packageInfo, - array('version', - 'stability', 'license', 'notes', 'contents', 'compatible', - 'dependencies', 'providesextension', 'srcpackage', 'srcuri', - 'phprelease', 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease', - 'zendextbinrelease', 'bundle', 'changelog'), $time, 'time'); - } - $this->_packageInfo['time'] = $time; + $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, 'value' => $value), + 'Version type <%type%> is not a valid version (%value%)'); } - function getDate() + function _invalidState($type, $value) { - if (isset($this->_packageInfo['date'])) { - return $this->_packageInfo['date']; + $states = array('stable', 'beta', 'alpha', 'devel'); + if ($type != 'api') { + $states[] = 'snapshot'; } - return false; + if (strtolower($value) == 'rc') { + $this->_stack->push(__FUNCTION__, 'error', + array('version' => $this->_packageInfo['version']['release']), + 'RC is not a state, it is a version postfix, try %version%RC1, stability beta'); + } + $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, 'value' => $value, + 'types' => $states), + 'Stability type <%type%> is not a valid stability (%value%), must be one of ' . + '%types%'); } - function getTime() + function _invalidTask($task, $ret, $file) { - if (isset($this->_packageInfo['time'])) { - return $this->_packageInfo['time']; + switch ($ret[0]) { + case PEAR_TASK_ERROR_MISSING_ATTRIB : + $info = array('attrib' => $ret[1], 'task' => $task, 'file' => $file); + $msg = 'task <%task%> is missing attribute "%attrib%" in file %file%'; + break; + case PEAR_TASK_ERROR_NOATTRIBS : + $info = array('task' => $task, 'file' => $file); + $msg = 'task <%task%> has no attributes in file %file%'; + break; + case PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE : + $info = array('attrib' => $ret[1], 'values' => $ret[3], + 'was' => $ret[2], 'task' => $task, 'file' => $file); + $msg = 'task <%task%> attribute "%attrib%" has the wrong value "%was%" '. + 'in file %file%, expecting one of "%values%"'; + break; + case PEAR_TASK_ERROR_INVALID : + $info = array('reason' => $ret[1], 'task' => $task, 'file' => $file); + $msg = 'task <%task%> in file %file% is invalid because of "%reason%"'; + break; } - return false; + $this->_stack->push(__FUNCTION__, 'error', $info, $msg); } - /** - * @param package|api version category to return - */ - function getVersion($key = 'release') + function _unknownTask($task, $file) { - if (isset($this->_packageInfo['version'][$key])) { - return $this->_packageInfo['version'][$key]; - } - return false; + $this->_stack->push(__FUNCTION__, 'error', array('task' => $task, 'file' => $file), + 'Unknown task "%task%" passed in file '); } - function getStability() + function _subpackageCannotProvideExtension($name) { - if (isset($this->_packageInfo['stability'])) { - return $this->_packageInfo['stability']; - } - return false; + $this->_stack->push(__FUNCTION__, 'error', array('name' => $name), + 'Subpackage dependency "%name%" cannot use , ' . + 'only package dependencies can use this tag'); } - function getState($key = 'release') + function _subpackagesCannotConflict($name) { - if (isset($this->_packageInfo['stability'][$key])) { - return $this->_packageInfo['stability'][$key]; - } - return false; + $this->_stack->push(__FUNCTION__, 'error', array('name' => $name), + 'Subpackage dependency "%name%" cannot use , ' . + 'only package dependencies can use this tag'); } - function getLicense($raw = false) + function _cannotProvideExtension($release) { - if (isset($this->_packageInfo['license'])) { - if ($raw) { - return $this->_packageInfo['license']; - } - if (is_array($this->_packageInfo['license'])) { - return $this->_packageInfo['license']['_content']; - } else { - return $this->_packageInfo['license']; - } - } - return false; + $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), + '<%release%> packages cannot use , only extbinrelease, extsrcrelease, zendextsrcrelease, and zendextbinrelease can provide a PHP extension'); } - function getLicenseLocation() + function _mustProvideExtension($release) { - if (!isset($this->_packageInfo['license']) || !is_array($this->_packageInfo['license'])) { - return false; - } - return $this->_packageInfo['license']['attribs']; + $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), + '<%release%> packages must use to indicate which PHP extension is provided'); } - function getNotes() + function _cannotHaveSrcpackage($release) { - if (isset($this->_packageInfo['notes'])) { - return $this->_packageInfo['notes']; - } - return false; + $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), + '<%release%> packages cannot specify a source code package, only extension binaries may use the tag'); } - /** - * Return the tag contents, if any - * @return array|false - */ - function getUsesrole() + function _mustSrcPackage($release) { - if (isset($this->_packageInfo['usesrole'])) { - return $this->_packageInfo['usesrole']; - } - return false; + $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), + '/ packages must specify a source code package with '); } - /** - * Return the tag contents, if any - * @return array|false - */ - function getUsestask() + function _mustSrcuri($release) { - if (isset($this->_packageInfo['usestask'])) { - return $this->_packageInfo['usestask']; - } - return false; + $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), + '/ packages must specify a source code package with '); } - /** - * This should only be used to retrieve filenames and install attributes - */ - function getFilelist($preserve = false) + function _uriDepsCannotHaveVersioning($type) { - if (isset($this->_packageInfo['filelist']) && !$preserve) { - return $this->_packageInfo['filelist']; - } - $this->flattenFilelist(); - if ($contents = $this->getContents()) { - $ret = array(); - if (!isset($contents['dir'])) { - return false; - } - if (!isset($contents['dir']['file'][0])) { - $contents['dir']['file'] = array($contents['dir']['file']); - } - foreach ($contents['dir']['file'] as $file) { - $name = $file['attribs']['name']; - if (!$preserve) { - $file = $file['attribs']; - } - $ret[$name] = $file; - } - if (!$preserve) { - $this->_packageInfo['filelist'] = $ret; - } - return $ret; - } - return false; + $this->_stack->push(__FUNCTION__, 'error', array('type' => $type), + '%type%: dependencies with a tag cannot have any versioning information'); } - /** - * Return configure options array, if any - * - * @return array|false - */ - function getConfigureOptions() + function _conflictingDepsCannotHaveVersioning($type) { - if ($this->getPackageType() != 'extsrc' && $this->getPackageType() != 'zendextsrc') { - return false; - } - - $releases = $this->getReleases(); - if (isset($releases[0])) { - $releases = $releases[0]; - } - - if (isset($releases['configureoption'])) { - if (!isset($releases['configureoption'][0])) { - $releases['configureoption'] = array($releases['configureoption']); - } - - for ($i = 0; $i < count($releases['configureoption']); $i++) { - $releases['configureoption'][$i] = $releases['configureoption'][$i]['attribs']; - } - - return $releases['configureoption']; - } - - return false; + $this->_stack->push(__FUNCTION__, 'error', array('type' => $type), + '%type%: conflicting dependencies cannot have versioning info, use to ' . + 'exclude specific versions of a dependency'); } - /** - * This is only used at install-time, after all serialization - * is over. - */ - function resetFilelist() + function _DepchannelCannotBeUri($type) { - $this->_packageInfo['filelist'] = array(); + $this->_stack->push(__FUNCTION__, 'error', array('type' => $type), + '%type%: channel cannot be __uri, this is a pseudo-channel reserved for uri ' . + 'dependencies only'); } - /** - * Retrieve a list of files that should be installed on this computer - * @return array - */ - function getInstallationFilelist($forfilecheck = false) + function _bundledPackagesMustBeFilename() { - $contents = $this->getFilelist(true); - if (isset($contents['dir']['attribs']['baseinstalldir'])) { - $base = $contents['dir']['attribs']['baseinstalldir']; - } - if (isset($this->_packageInfo['bundle'])) { - return PEAR::raiseError( - 'Exception: bundles should be handled in download code only'); - } - $release = $this->getReleases(); - if ($release) { - if (!isset($release[0])) { - if (!isset($release['installconditions']) && !isset($release['filelist'])) { - if ($forfilecheck) { - return $this->getFilelist(); - } - return $contents; - } - $release = array($release); - } - $depchecker = &$this->getPEARDependency2($this->_config, array(), - array('channel' => $this->getChannel(), 'package' => $this->getPackage()), - PEAR_VALIDATE_INSTALLING); - foreach ($release as $instance) { - if (isset($instance['installconditions'])) { - $installconditions = $instance['installconditions']; - if (is_array($installconditions)) { - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - foreach ($installconditions as $type => $conditions) { - if (!isset($conditions[0])) { - $conditions = array($conditions); - } - foreach ($conditions as $condition) { - $ret = $depchecker->{"validate{$type}Dependency"}($condition); - if (PEAR::isError($ret)) { - PEAR::popErrorHandling(); - continue 3; // skip this release - } - } - } - PEAR::popErrorHandling(); - } - } - // this is the release to use - if (isset($instance['filelist'])) { - // ignore files - if (isset($instance['filelist']['ignore'])) { - $ignore = isset($instance['filelist']['ignore'][0]) ? - $instance['filelist']['ignore'] : - array($instance['filelist']['ignore']); - foreach ($ignore as $ig) { - unset ($contents[$ig['attribs']['name']]); - } - } - // install files as this name - if (isset($instance['filelist']['install'])) { - $installas = isset($instance['filelist']['install'][0]) ? - $instance['filelist']['install'] : - array($instance['filelist']['install']); - foreach ($installas as $as) { - $contents[$as['attribs']['name']]['attribs']['install-as'] = - $as['attribs']['as']; - } - } - } - if ($forfilecheck) { - foreach ($contents as $file => $attrs) { - $contents[$file] = $attrs['attribs']; - } - } - return $contents; - } - } else { // simple release - no installconditions or install-as - if ($forfilecheck) { - return $this->getFilelist(); - } - return $contents; - } - // no releases matched - return PEAR::raiseError('No releases in package.xml matched the existing operating ' . - 'system, extensions installed, or architecture, cannot install'); + $this->_stack->push(__FUNCTION__, 'error', array(), + ' tags must contain only the filename of a package release ' . + 'in the bundle'); } - /** - * This is only used at install-time, after all serialization - * is over. - * @param string file name - * @param string installed path - */ - function setInstalledAs($file, $path) + function _binaryPackageMustBePackagename() { - if ($path) { - return $this->_packageInfo['filelist'][$file]['installed_as'] = $path; - } - unset($this->_packageInfo['filelist'][$file]['installed_as']); + $this->_stack->push(__FUNCTION__, 'error', array(), + ' tags must contain the name of a package that is ' . + 'a compiled version of this extsrc/zendextsrc package'); } - function getInstalledLocation($file) + function _fileNotFound($file) { - if (isset($this->_packageInfo['filelist'][$file]['installed_as'])) { - return $this->_packageInfo['filelist'][$file]['installed_as']; - } - return false; + $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), + 'File "%file%" in package.xml does not exist'); } - /** - * This is only used at install-time, after all serialization - * is over. - */ - function installedFile($file, $atts) + function _notInContents($file, $tag) { - if (isset($this->_packageInfo['filelist'][$file])) { - $this->_packageInfo['filelist'][$file] = - array_merge($this->_packageInfo['filelist'][$file], $atts['attribs']); - } else { - $this->_packageInfo['filelist'][$file] = $atts['attribs']; - } + $this->_stack->push(__FUNCTION__, 'error', array('file' => $file, 'tag' => $tag), + '<%tag% name="%file%"> is invalid, file is not in '); } - /** - * Retrieve the contents tag - */ - function getContents() + function _cannotValidateNoPathSet() { - if (isset($this->_packageInfo['contents'])) { - return $this->_packageInfo['contents']; - } - return false; + $this->_stack->push(__FUNCTION__, 'error', array(), + 'Cannot validate files, no path to package file is set (use setPackageFile())'); } - /** - * @param string full path to file - * @param string attribute name - * @param string attribute value - * @param int risky but fast - use this to choose a file based on its position in the list - * of files. Index is zero-based like PHP arrays. - * @return bool success of operation - */ - function setFileAttribute($filename, $attr, $value, $index = false) + function _usesroletaskMustHaveChannelOrUri($role, $tag) { - $this->_isValid = 0; - if (in_array($attr, array('role', 'name', 'baseinstalldir'))) { - $this->_filesValid = false; - } - if ($index !== false && - isset($this->_packageInfo['contents']['dir']['file'][$index]['attribs'])) { - $this->_packageInfo['contents']['dir']['file'][$index]['attribs'][$attr] = $value; - return true; - } - if (!isset($this->_packageInfo['contents']['dir']['file'])) { - return false; - } - $files = $this->_packageInfo['contents']['dir']['file']; - if (!isset($files[0])) { - $files = array($files); - $ind = false; - } else { - $ind = true; - } - foreach ($files as $i => $file) { - if (isset($file['attribs'])) { - if ($file['attribs']['name'] == $filename) { - if ($ind) { - $this->_packageInfo['contents']['dir']['file'][$i]['attribs'][$attr] = $value; - } else { - $this->_packageInfo['contents']['dir']['file']['attribs'][$attr] = $value; - } - return true; - } - } - } - return false; + $this->_stack->push(__FUNCTION__, 'error', array('role' => $role, 'tag' => $tag), + '<%tag%> for role "%role%" must contain either , or and '); } - function setDirtree($path) + function _usesroletaskMustHavePackage($role, $tag) { - if (!isset($this->_packageInfo['dirtree'])) { - $this->_packageInfo['dirtree'] = array(); - } - $this->_packageInfo['dirtree'][$path] = true; + $this->_stack->push(__FUNCTION__, 'error', array('role' => $role, 'tag' => $tag), + '<%tag%> for role "%role%" must contain '); } - function getDirtree() + function _usesroletaskMustHaveRoleTask($tag, $type) { - if (isset($this->_packageInfo['dirtree']) && count($this->_packageInfo['dirtree'])) { - return $this->_packageInfo['dirtree']; - } - return false; + $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag, 'type' => $type), + '<%tag%> must contain <%type%> defining the %type% to be used'); } - function resetDirtree() + function _cannotConflictWithAllOs($type) { - unset($this->_packageInfo['dirtree']); + $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag), + '%tag% cannot conflict with all OSes'); } - /** - * Determines whether this package claims it is compatible with the version of - * the package that has a recommended version dependency - * @param PEAR_PackageFile_v2|PEAR_PackageFile_v1|PEAR_Downloader_Package - * @return boolean - */ - function isCompatible($pf) + function _invalidDepGroupName($name) { - if (!isset($this->_packageInfo['compatible'])) { - return false; - } - if (!isset($this->_packageInfo['channel'])) { - return false; - } - $me = $pf->getVersion(); - $compatible = $this->_packageInfo['compatible']; - if (!isset($compatible[0])) { - $compatible = array($compatible); - } - $found = false; - foreach ($compatible as $info) { - if (strtolower($info['name']) == strtolower($pf->getPackage())) { - if (strtolower($info['channel']) == strtolower($pf->getChannel())) { - $found = true; - break; - } - } - } - if (!$found) { - return false; - } - if (isset($info['exclude'])) { - if (!isset($info['exclude'][0])) { - $info['exclude'] = array($info['exclude']); - } - foreach ($info['exclude'] as $exclude) { - if (version_compare($me, $exclude, '==')) { - return false; - } - } - } - if (version_compare($me, $info['min'], '>=') && version_compare($me, $info['max'], '<=')) { - return true; - } - return false; + $this->_stack->push(__FUNCTION__, 'error', array('name' => $name), + 'Invalid dependency group name "%name%"'); } - /** - * @return array|false - */ - function getCompatible() + function _multipleToplevelDirNotAllowed() { - if (isset($this->_packageInfo['compatible'])) { - return $this->_packageInfo['compatible']; - } - return false; + $this->_stack->push(__FUNCTION__, 'error', array(), + 'Multiple top-level tags are not allowed. Enclose them ' . + 'in a '); } - function getDependencies() + function _multipleInstallAs($file) { - if (isset($this->_packageInfo['dependencies'])) { - return $this->_packageInfo['dependencies']; - } - return false; + $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), + 'Only one tag is allowed for file "%file%"'); } - function isSubpackageOf($p) + function _ignoreAndInstallAs($file) { - return $p->isSubpackage($this); + $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), + 'Cannot have both and tags for file "%file%"'); } - /** - * Determines whether the passed in package is a subpackage of this package. - * - * No version checking is done, only name verification. - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @return bool - */ - function isSubpackage($p) + function _analyzeBundledPackages() { - $sub = array(); - if (isset($this->_packageInfo['dependencies']['required']['subpackage'])) { - $sub = $this->_packageInfo['dependencies']['required']['subpackage']; - if (!isset($sub[0])) { - $sub = array($sub); - } + if (!$this->_isValid) { + return false; } - if (isset($this->_packageInfo['dependencies']['optional']['subpackage'])) { - $sub1 = $this->_packageInfo['dependencies']['optional']['subpackage']; - if (!isset($sub1[0])) { - $sub1 = array($sub1); - } - $sub = array_merge($sub, $sub1); + if (!$this->_pf->getPackageType() == 'bundle') { + return false; } - if (isset($this->_packageInfo['dependencies']['group'])) { - $group = $this->_packageInfo['dependencies']['group']; - if (!isset($group[0])) { - $group = array($group); - } - foreach ($group as $deps) { - if (isset($deps['subpackage'])) { - $sub2 = $deps['subpackage']; - if (!isset($sub2[0])) { - $sub2 = array($sub2); - } - $sub = array_merge($sub, $sub2); - } - } + if (!isset($this->_pf->_packageFile)) { + return false; } - foreach ($sub as $dep) { - if (strtolower($dep['name']) == strtolower($p->getPackage())) { - if (isset($dep['channel'])) { - if (strtolower($dep['channel']) == strtolower($p->getChannel())) { - return true; - } - } else { - if ($dep['uri'] == $p->getURI()) { - return true; + $dir_prefix = dirname($this->_pf->_packageFile); + $common = new PEAR_Common; + $log = isset($this->_pf->_logger) ? array(&$this->_pf->_logger, 'log') : + array($common, 'log'); + $info = $this->_pf->getContents(); + $info = $info['bundledpackage']; + if (!is_array($info)) { + $info = array($info); + } + $pkg = &new PEAR_PackageFile($this->_pf->_config); + foreach ($info as $package) { + if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $package)) { + $this->_fileNotFound($dir_prefix . DIRECTORY_SEPARATOR . $package); + $this->_isValid = 0; + continue; + } + call_user_func_array($log, array(1, "Analyzing bundled package $package")); + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $ret = $pkg->fromAnyFile($dir_prefix . DIRECTORY_SEPARATOR . $package, + PEAR_VALIDATE_NORMAL); + PEAR::popErrorHandling(); + if (PEAR::isError($ret)) { + call_user_func_array($log, array(0, "ERROR: package $package is not a valid " . + 'package')); + $inf = $ret->getUserInfo(); + if (is_array($inf)) { + foreach ($inf as $err) { + call_user_func_array($log, array(1, $err['message'])); } } + return false; } } - return false; + return true; } - function dependsOn($package, $channel) + function _analyzePhpFiles() { - if (!($deps = $this->getDependencies())) { + if (!$this->_isValid) { return false; } - foreach (array('package', 'subpackage') as $type) { - foreach (array('required', 'optional') as $needed) { - if (isset($deps[$needed][$type])) { - if (!isset($deps[$needed][$type][0])) { - $deps[$needed][$type] = array($deps[$needed][$type]); - } - foreach ($deps[$needed][$type] as $dep) { - $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri'; - if (strtolower($dep['name']) == strtolower($package) && - $depchannel == $channel) { - return true; - } - } + if (!isset($this->_pf->_packageFile)) { + $this->_cannotValidateNoPathSet(); + return false; + } + $dir_prefix = dirname($this->_pf->_packageFile); + $common = new PEAR_Common; + $log = isset($this->_pf->_logger) ? array(&$this->_pf->_logger, 'log') : + array(&$common, 'log'); + $info = $this->_pf->getContents(); + if (!$info || !isset($info['dir']['file'])) { + $this->_tagCannotBeEmpty('contents>_fileNotFound($dir_prefix . DIRECTORY_SEPARATOR . $file); + $this->_isValid = 0; + continue; + } + if (in_array($fa['role'], PEAR_Installer_Role::getPhpRoles()) && $dir_prefix) { + call_user_func_array($log, array(1, "Analyzing $file")); + $srcinfo = $this->analyzeSourceCode($dir_prefix . DIRECTORY_SEPARATOR . $file); + if ($srcinfo) { + $provides = array_merge($provides, $this->_buildProvidesArray($srcinfo)); } } - if (isset($deps['group'])) { - if (!isset($deps['group'][0])) { - $dep['group'] = array($deps['group']); + } + $this->_packageName = $pn = $this->_pf->getPackage(); + $pnl = strlen($pn); + foreach ($provides as $key => $what) { + if (isset($what['explicit']) || !$what) { + // skip conformance checks if the provides entry is + // specified in the package.xml file + continue; + } + extract($what); + if ($type == 'class') { + if (!strncasecmp($name, $pn, $pnl)) { + continue; } - foreach ($deps['group'] as $group) { - if (isset($group[$type])) { - if (!is_array($group[$type])) { - $group[$type] = array($group[$type]); - } - foreach ($group[$type] as $dep) { - $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri'; - if (strtolower($dep['name']) == strtolower($package) && - $depchannel == $channel) { - return true; - } - } - } + $this->_stack->push(__FUNCTION__, 'warning', + array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn), + 'in %file%: %type% "%name%" not prefixed with package name "%package%"'); + } elseif ($type == 'function') { + if (strstr($name, '::') || !strncasecmp($name, $pn, $pnl)) { + continue; } + $this->_stack->push(__FUNCTION__, 'warning', + array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn), + 'in %file%: %type% "%name%" not prefixed with package name "%package%"'); } } - return false; + return $this->_isValid; } /** - * Get the contents of a dependency group - * @param string - * @return array|false + * Analyze the source code of the given PHP file + * + * @param string Filename of the PHP file + * @param boolean whether to analyze $file as the file contents + * @return mixed */ - function getDependencyGroup($name) + function analyzeSourceCode($file, $string = false) { - $name = strtolower($name); - if (!isset($this->_packageInfo['dependencies']['group'])) { + if (!function_exists("token_get_all")) { + $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), + 'Parser error: token_get_all() function must exist to analyze source code, PHP may have been compiled with --disable-tokenizer'); return false; } - $groups = $this->_packageInfo['dependencies']['group']; - if (!isset($groups[0])) { - $groups = array($groups); + + if (!defined('T_DOC_COMMENT')) { + define('T_DOC_COMMENT', T_COMMENT); } - foreach ($groups as $group) { - if (strtolower($group['attribs']['name']) == $name) { - return $group; + + if (!defined('T_INTERFACE')) { + define('T_INTERFACE', -1); + } + + if (!defined('T_IMPLEMENTS')) { + define('T_IMPLEMENTS', -1); + } + + if ($string) { + $contents = $file; + } else { + if (!$fp = @fopen($file, "r")) { + return false; } + fclose($fp); + $contents = file_get_contents($file); } - return false; - } - /** - * Retrieve a partial package.xml 1.0 representation of dependencies - * - * a very limited representation of dependencies is returned by this method. - * The tag for excluding certain versions of a dependency is - * completely ignored. In addition, dependency groups are ignored, with the - * assumption that all dependencies in dependency groups are also listed in - * the optional group that work with all dependency groups - * @param boolean return package.xml 2.0 tag - * @return array|false - */ - function getDeps($raw = false, $nopearinstaller = false) - { - if (isset($this->_packageInfo['dependencies'])) { - if ($raw) { - return $this->_packageInfo['dependencies']; + // Silence this function so we can catch PHP Warnings and show our own custom message + $tokens = @token_get_all($contents); + if (isset($php_errormsg)) { + if (isset($this->_stack)) { + $pn = $this->_pf->getPackage(); + $this->_stack->push(__FUNCTION__, 'warning', + array('file' => $file, 'package' => $pn), + 'in %file%: Could not process file for unkown reasons,' . + ' possibly a PHP parse error in %file% from %package%'); } - $ret = array(); - $map = array( - 'php' => 'php', - 'package' => 'pkg', - 'subpackage' => 'pkg', - 'extension' => 'ext', - 'os' => 'os', - 'pearinstaller' => 'pkg', - ); - foreach (array('required', 'optional') as $type) { - $optional = ($type == 'optional') ? 'yes' : 'no'; - if (!isset($this->_packageInfo['dependencies'][$type]) - || empty($this->_packageInfo['dependencies'][$type])) { + } +/* + for ($i = 0; $i < sizeof($tokens); $i++) { + @list($token, $data) = $tokens[$i]; + if (is_string($token)) { + var_dump($token); + } else { + print token_name($token) . ' '; + var_dump(rtrim($data)); + } + } +*/ + $look_for = 0; + $paren_level = 0; + $bracket_level = 0; + $brace_level = 0; + $lastphpdoc = ''; + $current_class = ''; + $current_interface = ''; + $current_class_level = -1; + $current_function = ''; + $current_function_level = -1; + $declared_classes = array(); + $declared_interfaces = array(); + $declared_functions = array(); + $declared_methods = array(); + $used_classes = array(); + $used_functions = array(); + $extends = array(); + $implements = array(); + $nodeps = array(); + $inquote = false; + $interface = false; + for ($i = 0; $i < sizeof($tokens); $i++) { + if (is_array($tokens[$i])) { + list($token, $data) = $tokens[$i]; + } else { + $token = $tokens[$i]; + $data = ''; + } + + if ($inquote) { + if ($token != '"' && $token != T_END_HEREDOC) { + continue; + } else { + $inquote = false; continue; } - foreach ($this->_packageInfo['dependencies'][$type] as $dtype => $deps) { - if ($dtype == 'pearinstaller' && $nopearinstaller) { - continue; + } + + switch ($token) { + case T_WHITESPACE : + continue; + case ';': + if ($interface) { + $current_function = ''; + $current_function_level = -1; } - if (!isset($deps[0])) { - $deps = array($deps); + break; + case '"': + case T_START_HEREDOC: + $inquote = true; + break; + case T_CURLY_OPEN: + case T_DOLLAR_OPEN_CURLY_BRACES: + case '{': $brace_level++; continue 2; + case '}': + $brace_level--; + if ($current_class_level == $brace_level) { + $current_class = ''; + $current_class_level = -1; } - foreach ($deps as $dep) { - if (!isset($map[$dtype])) { - // no support for arch type - continue; - } - if ($dtype == 'pearinstaller') { - $dep['name'] = 'PEAR'; - $dep['channel'] = 'pear.php.net'; - } - $s = array('type' => $map[$dtype]); - if (isset($dep['channel'])) { - $s['channel'] = $dep['channel']; - } - if (isset($dep['uri'])) { - $s['uri'] = $dep['uri']; - } - if (isset($dep['name'])) { - $s['name'] = $dep['name']; - } - if (isset($dep['conflicts'])) { - $s['rel'] = 'not'; + if ($current_function_level == $brace_level) { + $current_function = ''; + $current_function_level = -1; + } + continue 2; + case '[': $bracket_level++; continue 2; + case ']': $bracket_level--; continue 2; + case '(': $paren_level++; continue 2; + case ')': $paren_level--; continue 2; + case T_INTERFACE: + $interface = true; + case T_CLASS: + if (($current_class_level != -1) || ($current_function_level != -1)) { + if (isset($this->_stack)) { + $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), + 'Parser error: invalid PHP found in file "%file%"'); } else { - if (!isset($dep['min']) && - !isset($dep['max'])) { - $s['rel'] = 'has'; - $s['optional'] = $optional; - } elseif (isset($dep['min']) && - isset($dep['max'])) { - $s['rel'] = 'ge'; - $s1 = $s; - $s1['rel'] = 'le'; - $s['version'] = $dep['min']; - $s1['version'] = $dep['max']; - if (isset($dep['channel'])) { - $s1['channel'] = $dep['channel']; - } - if ($dtype != 'php') { - $s['name'] = $dep['name']; - $s1['name'] = $dep['name']; - } - $s['optional'] = $optional; - $s1['optional'] = $optional; - $ret[] = $s1; - } elseif (isset($dep['min'])) { - if (isset($dep['exclude']) && - $dep['exclude'] == $dep['min']) { - $s['rel'] = 'gt'; - } else { - $s['rel'] = 'ge'; - } - $s['version'] = $dep['min']; - $s['optional'] = $optional; - if ($dtype != 'php') { - $s['name'] = $dep['name']; - } - } elseif (isset($dep['max'])) { - if (isset($dep['exclude']) && - $dep['exclude'] == $dep['max']) { - $s['rel'] = 'lt'; - } else { - $s['rel'] = 'le'; - } - $s['version'] = $dep['max']; - $s['optional'] = $optional; - if ($dtype != 'php') { - $s['name'] = $dep['name']; - } + PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"", + PEAR_COMMON_ERROR_INVALIDPHP); + } + + return false; + } + case T_FUNCTION: + case T_NEW: + case T_EXTENDS: + case T_IMPLEMENTS: + $look_for = $token; + continue 2; + case T_STRING: + if (version_compare(zend_version(), '2.0', '<')) { + if (in_array(strtolower($data), + array('public', 'private', 'protected', 'abstract', + 'interface', 'implements', 'throw') + ) + ) { + if (isset($this->_stack)) { + $this->_stack->push(__FUNCTION__, 'warning', array( + 'file' => $file), + 'Error, PHP5 token encountered in %file%,' . + ' analysis should be in PHP5'); + } else { + PEAR::raiseError('Error: PHP5 token encountered in ' . $file . + 'packaging should be done in PHP 5'); + return false; } } - $ret[] = $s; } - } - } - if (count($ret)) { - return $ret; - } - } - return false; - } - - /** - * @return php|extsrc|extbin|zendextsrc|zendextbin|bundle|false - */ - function getPackageType() - { - if (isset($this->_packageInfo['phprelease'])) { - return 'php'; - } - if (isset($this->_packageInfo['extsrcrelease'])) { - return 'extsrc'; - } - if (isset($this->_packageInfo['extbinrelease'])) { - return 'extbin'; - } - if (isset($this->_packageInfo['zendextsrcrelease'])) { - return 'zendextsrc'; - } - if (isset($this->_packageInfo['zendextbinrelease'])) { - return 'zendextbin'; - } - if (isset($this->_packageInfo['bundle'])) { - return 'bundle'; - } - return false; - } - - /** - * @return array|false - */ - function getReleases() - { - $type = $this->getPackageType(); - if ($type != 'bundle') { - $type .= 'release'; - } - if ($this->getPackageType() && isset($this->_packageInfo[$type])) { - return $this->_packageInfo[$type]; - } - return false; - } - /** - * @return array - */ - function getChangelog() - { - if (isset($this->_packageInfo['changelog'])) { - return $this->_packageInfo['changelog']; - } - return false; - } + if ($look_for == T_CLASS) { + $current_class = $data; + $current_class_level = $brace_level; + $declared_classes[] = $current_class; + } elseif ($look_for == T_INTERFACE) { + $current_interface = $data; + $current_class_level = $brace_level; + $declared_interfaces[] = $current_interface; + } elseif ($look_for == T_IMPLEMENTS) { + $implements[$current_class] = $data; + } elseif ($look_for == T_EXTENDS) { + $extends[$current_class] = $data; + } elseif ($look_for == T_FUNCTION) { + if ($current_class) { + $current_function = "$current_class::$data"; + $declared_methods[$current_class][] = $data; + } elseif ($current_interface) { + $current_function = "$current_interface::$data"; + $declared_methods[$current_interface][] = $data; + } else { + $current_function = $data; + $declared_functions[] = $current_function; + } - function hasDeps() - { - return isset($this->_packageInfo['dependencies']); - } + $current_function_level = $brace_level; + $m = array(); + } elseif ($look_for == T_NEW) { + $used_classes[$data] = true; + } - function getPackagexmlVersion() - { - if (isset($this->_packageInfo['zendextsrcrelease'])) { - return '2.1'; - } - if (isset($this->_packageInfo['zendextbinrelease'])) { - return '2.1'; - } - return '2.0'; - } + $look_for = 0; + continue 2; + case T_VARIABLE: + $look_for = 0; + continue 2; + case T_DOC_COMMENT: + case T_COMMENT: + if (preg_match('!^/\*\*\s!', $data)) { + $lastphpdoc = $data; + if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m)) { + $nodeps = array_merge($nodeps, $m[1]); + } + } + continue 2; + case T_DOUBLE_COLON: + if (!($tokens[$i - 1][0] == T_WHITESPACE || $tokens[$i - 1][0] == T_STRING)) { + if (isset($this->_stack)) { + $this->_stack->push(__FUNCTION__, 'warning', array('file' => $file), + 'Parser error: invalid PHP found in file "%file%"'); + } else { + PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"", + PEAR_COMMON_ERROR_INVALIDPHP); + } - /** - * @return array|false - */ - function getSourcePackage() - { - if (isset($this->_packageInfo['extbinrelease']) || - isset($this->_packageInfo['zendextbinrelease'])) { - return array('channel' => $this->_packageInfo['srcchannel'], - 'package' => $this->_packageInfo['srcpackage']); - } - return false; - } + return false; + } - function getBundledPackages() - { - if (isset($this->_packageInfo['bundle'])) { - return $this->_packageInfo['contents']['bundledpackage']; - } - return false; - } + $class = $tokens[$i - 1][1]; + if (strtolower($class) != 'parent') { + $used_classes[$class] = true; + } - function getLastModified() - { - if (isset($this->_packageInfo['_lastmodified'])) { - return $this->_packageInfo['_lastmodified']; + continue 2; + } } - return false; + + return array( + "source_file" => $file, + "declared_classes" => $declared_classes, + "declared_interfaces" => $declared_interfaces, + "declared_methods" => $declared_methods, + "declared_functions" => $declared_functions, + "used_classes" => array_diff(array_keys($used_classes), $nodeps), + "inheritance" => $extends, + "implements" => $implements, + ); } /** - * Get the contents of a file listed within the package.xml - * @param string - * @return string + * Build a "provides" array from data returned by + * analyzeSourceCode(). The format of the built array is like + * this: + * + * array( + * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'), + * ... + * ) + * + * + * @param array $srcinfo array with information about a source file + * as returned by the analyzeSourceCode() method. + * + * @return void + * + * @access private + * */ - function getFileContents($file) + function _buildProvidesArray($srcinfo) { - if ($this->_archiveFile == $this->_packageFile) { // unpacked - $dir = dirname($this->_packageFile); - $file = $dir . DIRECTORY_SEPARATOR . $file; - $file = str_replace(array('/', '\\'), - array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), $file); - if (file_exists($file) && is_readable($file)) { - return implode('', file($file)); - } - } else { // tgz - $tar = &new Archive_Tar($this->_archiveFile); - $tar->pushErrorHandling(PEAR_ERROR_RETURN); - if ($file != 'package.xml' && $file != 'package2.xml') { - $file = $this->getPackage() . '-' . $this->getVersion() . '/' . $file; - } - $file = $tar->extractInString($file); - $tar->popErrorHandling(); - if (PEAR::isError($file)) { - return PEAR::raiseError("Cannot locate file '$file' in archive"); - } - return $file; + if (!$this->_isValid) { + return array(); } - } - function &getRW() - { - if (!class_exists('PEAR_PackageFile_v2_rw')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/v2/rw.php'; - } - $a = new PEAR_PackageFile_v2_rw; - foreach (get_object_vars($this) as $name => $unused) { - if (!isset($this->$name)) { + $providesret = array(); + $file = basename($srcinfo['source_file']); + $pn = isset($this->_pf) ? $this->_pf->getPackage() : ''; + $pnl = strlen($pn); + foreach ($srcinfo['declared_classes'] as $class) { + $key = "class;$class"; + if (isset($providesret[$key])) { continue; } - if ($name == '_config' || $name == '_logger'|| $name == '_registry' || - $name == '_stack') { - $a->$name = &$this->$name; - } else { - $a->$name = $this->$name; + + $providesret[$key] = + array('file'=> $file, 'type' => 'class', 'name' => $class); + if (isset($srcinfo['inheritance'][$class])) { + $providesret[$key]['extends'] = + $srcinfo['inheritance'][$class]; } } - return $a; - } - function &getDefaultGenerator() - { - if (!class_exists('PEAR_PackageFile_Generator_v2')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/Generator/v2.php'; - } - $a = &new PEAR_PackageFile_Generator_v2($this); - return $a; - } + foreach ($srcinfo['declared_methods'] as $class => $methods) { + foreach ($methods as $method) { + $function = "$class::$method"; + $key = "function;$function"; + if ($method{0} == '_' || !strcasecmp($method, $class) || + isset($providesret[$key])) { + continue; + } - function analyzeSourceCode($file, $string = false) - { - if (!isset($this->_v2Validator) || - !is_a($this->_v2Validator, 'PEAR_PackageFile_v2_Validator')) { - if (!class_exists('PEAR_PackageFile_v2_Validator')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/v2/Validator.php'; + $providesret[$key] = + array('file'=> $file, 'type' => 'function', 'name' => $function); } - $this->_v2Validator = new PEAR_PackageFile_v2_Validator; } - return $this->_v2Validator->analyzeSourceCode($file, $string); - } - function validate($state = PEAR_VALIDATE_NORMAL) - { - if (!isset($this->_packageInfo) || !is_array($this->_packageInfo)) { - return false; - } - if (!isset($this->_v2Validator) || - !is_a($this->_v2Validator, 'PEAR_PackageFile_v2_Validator')) { - if (!class_exists('PEAR_PackageFile_v2_Validator')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/v2/Validator.php'; + foreach ($srcinfo['declared_functions'] as $function) { + $key = "function;$function"; + if ($function{0} == '_' || isset($providesret[$key])) { + continue; } - $this->_v2Validator = new PEAR_PackageFile_v2_Validator; - } - if (isset($this->_packageInfo['xsdversion'])) { - unset($this->_packageInfo['xsdversion']); - } - return $this->_v2Validator->validate($this, $state); - } - function getTasksNs() - { - if (!isset($this->_tasksNs)) { - if (isset($this->_packageInfo['attribs'])) { - foreach ($this->_packageInfo['attribs'] as $name => $value) { - if ($value == 'http://pear.php.net/dtd/tasks-1.0') { - $this->_tasksNs = str_replace('xmlns:', '', $name); - break; - } - } + if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) { + $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\""; } - } - return $this->_tasksNs; - } - - /** - * Determine whether a task name is a valid task. Custom tasks may be defined - * using subdirectories by putting a "-" in the name, as in - * - * Note that this method will auto-load the task class file and test for the existence - * of the name with "-" replaced by "_" as in PEAR/Task/mycustom/task.php makes class - * PEAR_Task_mycustom_task - * @param string - * @return boolean - */ - function getTask($task) - { - $this->getTasksNs(); - // transform all '-' to '/' and 'tasks:' to '' so tasks:replace becomes replace - $task = str_replace(array($this->_tasksNs . ':', '-'), array('', ' '), $task); - $taskfile = str_replace(' ', '/', ucwords($task)); - $task = str_replace(array(' ', '/'), '_', ucwords($task)); - if (class_exists("PEAR_Task_$task")) { - return "PEAR_Task_$task"; - } - $fp = @fopen("phar://install-pear-nozlib.phar/PEAR/Task/$taskfile.php", 'r', true); - if ($fp) { - fclose($fp); - require_once 'phar://install-pear-nozlib.phar/' . "PEAR/Task/$taskfile.php"; - return "PEAR_Task_$task"; - } - return false; - } - - /** - * Key-friendly array_splice - * @param tagname to splice a value in before - * @param mixed the value to splice in - * @param string the new tag name - */ - function _ksplice($array, $key, $value, $newkey) - { - $offset = array_search($key, array_keys($array)); - $after = array_slice($array, $offset); - $before = array_slice($array, 0, $offset); - $before[$newkey] = $value; - return array_merge($before, $after); - } - /** - * @param array a list of possible keys, in the order they may occur - * @param mixed contents of the new package.xml tag - * @param string tag name - * @access private - */ - function _insertBefore($array, $keys, $contents, $newkey) - { - foreach ($keys as $key) { - if (isset($array[$key])) { - return $array = $this->_ksplice($array, $key, $contents, $newkey); - } + $providesret[$key] = + array('file'=> $file, 'type' => 'function', 'name' => $function); } - $array[$newkey] = $contents; - return $array; - } - /** - * @param subsection of {@link $_packageInfo} - * @param array|string tag contents - * @param array format: - *
-     * array(
-     *   tagname => array(list of tag names that follow this one),
-     *   childtagname => array(list of child tag names that follow this one),
-     * )
-     * 
- * - * This allows construction of nested tags - * @access private - */ - function _mergeTag($manip, $contents, $order) - { - if (count($order)) { - foreach ($order as $tag => $curorder) { - if (!isset($manip[$tag])) { - // ensure that the tag is set up - $manip = $this->_insertBefore($manip, $curorder, array(), $tag); - } - if (count($order) > 1) { - $manip[$tag] = $this->_mergeTag($manip[$tag], $contents, array_slice($order, 1)); - return $manip; - } - } - } else { - return $manip; - } - if (is_array($manip[$tag]) && !empty($manip[$tag]) && isset($manip[$tag][0])) { - $manip[$tag][] = $contents; - } else { - if (!count($manip[$tag])) { - $manip[$tag] = $contents; - } else { - $manip[$tag] = array($manip[$tag]); - $manip[$tag][] = $contents; - } - } - return $manip; + return $providesret; } -} -?> - + * @author Tomas V. V. Cox * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Validator.php,v 1.110 2009/03/27 19:29:31 dufuz Exp $ + * @version CVS: $Id: Registry.php 287555 2009-08-21 21:27:27Z dufuz $ * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a8 + * @since File available since Release 0.1 */ + /** - * Private validation class used by PEAR_PackageFile_v2 - do not use directly, its - * sole purpose is to split up the PEAR/PackageFile/v2.php file to make it smaller + * for PEAR_Error + */ +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR.php'; +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/DependencyDB.php'; + +define('PEAR_REGISTRY_ERROR_LOCK', -2); +define('PEAR_REGISTRY_ERROR_FORMAT', -3); +define('PEAR_REGISTRY_ERROR_FILE', -4); +define('PEAR_REGISTRY_ERROR_CONFLICT', -5); +define('PEAR_REGISTRY_ERROR_CHANNEL_FILE', -6); + +/** + * Administration class used to maintain the installed package database. * @category pear * @package PEAR + * @author Stig Bakken + * @author Tomas V. V. Cox * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a8 - * @access private + * @since Class available since Release 1.4.0a1 */ -class PEAR_PackageFile_v2_Validator +class PEAR_Registry extends PEAR { /** + * File containing all channel information. + * @var string + */ + var $channels = ''; + + /** Directory where registry files are stored. + * @var string + */ + var $statedir = ''; + + /** File where the file map is stored + * @var string + */ + var $filemap = ''; + + /** Directory where registry files for channels are stored. + * @var string + */ + var $channelsdir = ''; + + /** Name of file used for locking the registry + * @var string + */ + var $lockfile = ''; + + /** File descriptor used during locking + * @var resource + */ + var $lock_fp = null; + + /** Mode used during locking + * @var int + */ + var $lock_mode = 0; // XXX UNUSED + + /** Cache of package information. Structure: + * array( + * 'package' => array('id' => ... ), + * ... ) * @var array */ - var $_packageInfo; + var $pkginfo_cache = array(); + + /** Cache of file map. Structure: + * array( '/path/to/file' => 'package', ... ) + * @var array + */ + var $filemap_cache = array(); + /** - * @var PEAR_PackageFile_v2 + * @var false|PEAR_ChannelFile */ - var $_pf; + var $_pearChannel; + /** - * @var PEAR_ErrorStack + * @var false|PEAR_ChannelFile */ - var $_stack; + var $_peclChannel; + /** - * @var int + * @var false|PEAR_ChannelFile */ - var $_isValid = 0; + var $_docChannel; + /** - * @var int + * @var PEAR_DependencyDB */ - var $_filesValid = 0; + var $_dependencyDB; + /** - * @var int + * @var PEAR_Config */ - var $_curState = 0; + var $_config; + /** - * @param PEAR_PackageFile_v2 - * @param int + * PEAR_Registry constructor. + * + * @param string (optional) PEAR install directory (for .php files) + * @param PEAR_ChannelFile PEAR_ChannelFile object representing the PEAR channel, if + * default values are not desired. Only used the very first time a PEAR + * repository is initialized + * @param PEAR_ChannelFile PEAR_ChannelFile object representing the PECL channel, if + * default values are not desired. Only used the very first time a PEAR + * repository is initialized + * + * @access public */ - function validate(&$pf, $state = PEAR_VALIDATE_NORMAL) + function PEAR_Registry($pear_install_dir = PEAR_INSTALL_DIR, $pear_channel = false, + $pecl_channel = false) { - $this->_pf = &$pf; - $this->_curState = $state; - $this->_packageInfo = $this->_pf->getArray(); - $this->_isValid = $this->_pf->_isValid; - $this->_filesValid = $this->_pf->_filesValid; - $this->_stack = &$pf->_stack; - $this->_stack->getErrors(true); - if (($this->_isValid & $state) == $state) { - return true; - } - if (!isset($this->_packageInfo) || !is_array($this->_packageInfo)) { - return false; - } - if (!isset($this->_packageInfo['attribs']['version']) || - ($this->_packageInfo['attribs']['version'] != '2.0' && - $this->_packageInfo['attribs']['version'] != '2.1') - ) { - $this->_noPackageVersion(); - } - $structure = - array( - 'name', - 'channel|uri', - '*extends', // can't be multiple, but this works fine - 'summary', - 'description', - '+lead', // these all need content checks - '*developer', - '*contributor', - '*helper', - 'date', - '*time', - 'version', - 'stability', - 'license->?uri->?filesource', - 'notes', - 'contents', //special validation needed - '*compatible', - 'dependencies', //special validation needed - '*usesrole', - '*usestask', // reserve these for 1.4.0a1 to implement - // this will allow a package.xml to gracefully say it - // needs a certain package installed in order to implement a role or task - '*providesextension', - '*srcpackage|*srcuri', - '+phprelease|+extsrcrelease|+extbinrelease|' . - '+zendextsrcrelease|+zendextbinrelease|bundle', //special validation needed - '*changelog', - ); - $test = $this->_packageInfo; - if (isset($test['dependencies']) && - isset($test['dependencies']['required']) && - isset($test['dependencies']['required']['pearinstaller']) && - isset($test['dependencies']['required']['pearinstaller']['min']) && - version_compare('1.8.0', - $test['dependencies']['required']['pearinstaller']['min'], '<') - ) { - $this->_pearVersionTooLow($test['dependencies']['required']['pearinstaller']['min']); + parent::PEAR(); + $this->setInstallDir($pear_install_dir); + $this->_pearChannel = $pear_channel; + $this->_peclChannel = $pecl_channel; + $this->_config = false; + } + + function setInstallDir($pear_install_dir = PEAR_INSTALL_DIR) + { + $ds = DIRECTORY_SEPARATOR; + $this->install_dir = $pear_install_dir; + $this->channelsdir = $pear_install_dir.$ds.'.channels'; + $this->statedir = $pear_install_dir.$ds.'.registry'; + $this->filemap = $pear_install_dir.$ds.'.filemap'; + $this->lockfile = $pear_install_dir.$ds.'.lock'; + } + + function hasWriteAccess() + { + if (!file_exists($this->install_dir)) { + $dir = $this->install_dir; + while ($dir && $dir != '.') { + $olddir = $dir; + $dir = dirname($dir); + if ($dir != '.' && file_exists($dir)) { + if (is_writeable($dir)) { + return true; + } + + return false; + } + + if ($dir == $olddir) { // this can happen in safe mode + return @is_writable($dir); + } + } + return false; } - // ignore post-installation array fields - if (array_key_exists('filelist', $test)) { - unset($test['filelist']); + + return is_writeable($this->install_dir); + } + + function setConfig(&$config, $resetInstallDir = true) + { + $this->_config = &$config; + if ($resetInstallDir) { + $this->setInstallDir($config->get('php_dir')); } - if (array_key_exists('_lastmodified', $test)) { - unset($test['_lastmodified']); + } + + function _initializeChannelDirs() + { + static $running = false; + if (!$running) { + $running = true; + $ds = DIRECTORY_SEPARATOR; + if (!is_dir($this->channelsdir) || + !file_exists($this->channelsdir . $ds . 'pear.php.net.reg') || + !file_exists($this->channelsdir . $ds . 'pecl.php.net.reg') || + !file_exists($this->channelsdir . $ds . 'doc.php.net.reg') || + !file_exists($this->channelsdir . $ds . '__uri.reg')) { + if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) { + $pear_channel = $this->_pearChannel; + if (!is_a($pear_channel, 'PEAR_ChannelFile') || !$pear_channel->validate()) { + if (!class_exists('PEAR_ChannelFile')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/ChannelFile.php'; + } + + $pear_channel = new PEAR_ChannelFile; + $pear_channel->setAlias('pear'); + $pear_channel->setServer('pear.php.net'); + $pear_channel->setSummary('PHP Extension and Application Repository'); + $pear_channel->setDefaultPEARProtocols(); + $pear_channel->setBaseURL('REST1.0', 'http://pear.php.net/rest/'); + $pear_channel->setBaseURL('REST1.1', 'http://pear.php.net/rest/'); + $pear_channel->setBaseURL('REST1.3', 'http://pear.php.net/rest/'); + //$pear_channel->setBaseURL('REST1.4', 'http://pear.php.net/rest/'); + } else { + $pear_channel->setServer('pear.php.net'); + $pear_channel->setAlias('pear'); + } + + $pear_channel->validate(); + $this->_addChannel($pear_channel); + } + + if (!file_exists($this->channelsdir . $ds . 'pecl.php.net.reg')) { + $pecl_channel = $this->_peclChannel; + if (!is_a($pecl_channel, 'PEAR_ChannelFile') || !$pecl_channel->validate()) { + if (!class_exists('PEAR_ChannelFile')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/ChannelFile.php'; + } + + $pecl_channel = new PEAR_ChannelFile; + $pecl_channel->setAlias('pecl'); + $pecl_channel->setServer('pecl.php.net'); + $pecl_channel->setSummary('PHP Extension Community Library'); + $pecl_channel->setDefaultPEARProtocols(); + $pecl_channel->setBaseURL('REST1.0', 'http://pecl.php.net/rest/'); + $pecl_channel->setBaseURL('REST1.1', 'http://pecl.php.net/rest/'); + $pecl_channel->setValidationPackage('PEAR_Validator_PECL', '1.0'); + } else { + $pecl_channel->setServer('pecl.php.net'); + $pecl_channel->setAlias('pecl'); + } + + $pecl_channel->validate(); + $this->_addChannel($pecl_channel); + } + + if (!file_exists($this->channelsdir . $ds . 'doc.php.net.reg')) { + $doc_channel = $this->_docChannel; + if (!is_a($doc_channel, 'PEAR_ChannelFile') || !$doc_channel->validate()) { + if (!class_exists('PEAR_ChannelFile')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/ChannelFile.php'; + } + + $doc_channel = new PEAR_ChannelFile; + $doc_channel->setAlias('phpdocs'); + $doc_channel->setServer('doc.php.net'); + $doc_channel->setSummary('PHP Documentation Team'); + $doc_channel->setDefaultPEARProtocols(); + $doc_channel->setBaseURL('REST1.0', 'http://doc.php.net/rest/'); + $doc_channel->setBaseURL('REST1.1', 'http://doc.php.net/rest/'); + $doc_channel->setBaseURL('REST1.3', 'http://doc.php.net/rest/'); + } else { + $doc_channel->setServer('doc.php.net'); + $doc_channel->setAlias('doc'); + } + + $doc_channel->validate(); + $this->_addChannel($doc_channel); + } + + if (!file_exists($this->channelsdir . $ds . '__uri.reg')) { + if (!class_exists('PEAR_ChannelFile')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/ChannelFile.php'; + } + + $private = new PEAR_ChannelFile; + $private->setName('__uri'); + $private->setDefaultPEARProtocols(); + $private->setBaseURL('REST1.0', '****'); + $private->setSummary('Pseudo-channel for static packages'); + $this->_addChannel($private); + } + $this->_rebuildFileMap(); + } + + $running = false; } - if (array_key_exists('#binarypackage', $test)) { - unset($test['#binarypackage']); + } + + function _initializeDirs() + { + $ds = DIRECTORY_SEPARATOR; + // XXX Compatibility code should be removed in the future + // rename all registry files if any to lowercase + if (!OS_WINDOWS && file_exists($this->statedir) && is_dir($this->statedir) && + $handle = opendir($this->statedir)) { + $dest = $this->statedir . $ds; + while (false !== ($file = readdir($handle))) { + if (preg_match('/^.*[A-Z].*\.reg\\z/', $file)) { + rename($dest . $file, $dest . strtolower($file)); + } + } + closedir($handle); } - if (array_key_exists('old', $test)) { - unset($test['old']); + + $this->_initializeChannelDirs(); + if (!file_exists($this->filemap)) { + $this->_rebuildFileMap(); } - if (array_key_exists('_lastversion', $test)) { - unset($test['_lastversion']); + $this->_initializeDepDB(); + } + + function _initializeDepDB() + { + if (!isset($this->_dependencyDB)) { + static $initializing = false; + if (!$initializing) { + $initializing = true; + if (!$this->_config) { // never used? + $file = OS_WINDOWS ? 'pear.ini' : '.pearrc'; + $this->_config = &new PEAR_Config($this->statedir . DIRECTORY_SEPARATOR . + $file); + $this->_config->setRegistry($this); + $this->_config->set('php_dir', $this->install_dir); + } + + $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->_config); + if (PEAR::isError($this->_dependencyDB)) { + // attempt to recover by removing the dep db + if (file_exists($this->_config->get('php_dir', null, 'pear.php.net') . + DIRECTORY_SEPARATOR . '.depdb')) { + @unlink($this->_config->get('php_dir', null, 'pear.php.net') . + DIRECTORY_SEPARATOR . '.depdb'); + } + + $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->_config); + if (PEAR::isError($this->_dependencyDB)) { + echo $this->_dependencyDB->getMessage(); + echo 'Unrecoverable error'; + exit(1); + } + } + + $initializing = false; + } } - if (!$this->_stupidSchemaValidate($structure, $test, '')) { - return false; + } + + /** + * PEAR_Registry destructor. Makes sure no locks are forgotten. + * + * @access private + */ + function _PEAR_Registry() + { + parent::_PEAR(); + if (is_resource($this->lock_fp)) { + $this->_unlock(); } - if (empty($this->_packageInfo['name'])) { - $this->_tagCannotBeEmpty('name'); + } + + /** + * Make sure the directory where we keep registry files exists. + * + * @return bool TRUE if directory exists, FALSE if it could not be + * created + * + * @access private + */ + function _assertStateDir($channel = false) + { + if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') { + return $this->_assertChannelStateDir($channel); } - $test = isset($this->_packageInfo['uri']) ? 'uri' :'channel'; - if (empty($this->_packageInfo[$test])) { - $this->_tagCannotBeEmpty($test); + + static $init = false; + if (!file_exists($this->statedir)) { + if (!$this->hasWriteAccess()) { + return false; + } + + require_once 'phar://install-pear-nozlib.phar/' . 'System.php'; + if (!System::mkdir(array('-p', $this->statedir))) { + return $this->raiseError("could not create directory '{$this->statedir}'"); + } + $init = true; + } elseif (!is_dir($this->statedir)) { + return $this->raiseError('Cannot create directory ' . $this->statedir . ', ' . + 'it already exists and is not a directory'); } - if (is_array($this->_packageInfo['license']) && - (!isset($this->_packageInfo['license']['_content']) || - empty($this->_packageInfo['license']['_content']))) { - $this->_tagCannotBeEmpty('license'); - } elseif (empty($this->_packageInfo['license'])) { - $this->_tagCannotBeEmpty('license'); + + $ds = DIRECTORY_SEPARATOR; + if (!file_exists($this->channelsdir)) { + if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg') || + !file_exists($this->channelsdir . $ds . 'pecl.php.net.reg') || + !file_exists($this->channelsdir . $ds . 'doc.php.net.reg') || + !file_exists($this->channelsdir . $ds . '__uri.reg')) { + $init = true; + } + } elseif (!is_dir($this->channelsdir)) { + return $this->raiseError('Cannot create directory ' . $this->channelsdir . ', ' . + 'it already exists and is not a directory'); } - if (empty($this->_packageInfo['summary'])) { - $this->_tagCannotBeEmpty('summary'); + + if ($init) { + static $running = false; + if (!$running) { + $running = true; + $this->_initializeDirs(); + $running = false; + $init = false; + } + } else { + $this->_initializeDepDB(); } - if (empty($this->_packageInfo['description'])) { - $this->_tagCannotBeEmpty('description'); + + return true; + } + + /** + * Make sure the directory where we keep registry files exists for a non-standard channel. + * + * @param string channel name + * @return bool TRUE if directory exists, FALSE if it could not be + * created + * + * @access private + */ + function _assertChannelStateDir($channel) + { + $ds = DIRECTORY_SEPARATOR; + if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') { + if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) { + $this->_initializeChannelDirs(); + } + return $this->_assertStateDir($channel); } - if (empty($this->_packageInfo['date'])) { - $this->_tagCannotBeEmpty('date'); + + $channelDir = $this->_channelDirectoryName($channel); + if (!is_dir($this->channelsdir) || + !file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) { + $this->_initializeChannelDirs(); } - if (empty($this->_packageInfo['notes'])) { - $this->_tagCannotBeEmpty('notes'); + + if (!file_exists($channelDir)) { + if (!$this->hasWriteAccess()) { + return false; + } + + require_once 'phar://install-pear-nozlib.phar/' . 'System.php'; + if (!System::mkdir(array('-p', $channelDir))) { + return $this->raiseError("could not create directory '" . $channelDir . + "'"); + } + } elseif (!is_dir($channelDir)) { + return $this->raiseError("could not create directory '" . $channelDir . + "', already exists and is not a directory"); } - if (isset($this->_packageInfo['time']) && empty($this->_packageInfo['time'])) { - $this->_tagCannotBeEmpty('time'); + + return true; + } + + /** + * Make sure the directory where we keep registry files for channels exists + * + * @return bool TRUE if directory exists, FALSE if it could not be + * created + * + * @access private + */ + function _assertChannelDir() + { + if (!file_exists($this->channelsdir)) { + if (!$this->hasWriteAccess()) { + return false; + } + + require_once 'phar://install-pear-nozlib.phar/' . 'System.php'; + if (!System::mkdir(array('-p', $this->channelsdir))) { + return $this->raiseError("could not create directory '{$this->channelsdir}'"); + } + } elseif (!is_dir($this->channelsdir)) { + return $this->raiseError("could not create directory '{$this->channelsdir}" . + "', it already exists and is not a directory"); } - if (isset($this->_packageInfo['dependencies'])) { - $this->_validateDependencies(); + + if (!file_exists($this->channelsdir . DIRECTORY_SEPARATOR . '.alias')) { + if (!$this->hasWriteAccess()) { + return false; + } + + require_once 'phar://install-pear-nozlib.phar/' . 'System.php'; + if (!System::mkdir(array('-p', $this->channelsdir . DIRECTORY_SEPARATOR . '.alias'))) { + return $this->raiseError("could not create directory '{$this->channelsdir}/.alias'"); + } + } elseif (!is_dir($this->channelsdir . DIRECTORY_SEPARATOR . '.alias')) { + return $this->raiseError("could not create directory '{$this->channelsdir}" . + "/.alias', it already exists and is not a directory"); } - if (isset($this->_packageInfo['compatible'])) { - $this->_validateCompatible(); + + return true; + } + + /** + * Get the name of the file where data for a given package is stored. + * + * @param string channel name, or false if this is a PEAR package + * @param string package name + * + * @return string registry file name + * + * @access public + */ + function _packageFileName($package, $channel = false) + { + if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') { + return $this->_channelDirectoryName($channel) . DIRECTORY_SEPARATOR . + strtolower($package) . '.reg'; } - if (!isset($this->_packageInfo['bundle'])) { - if (empty($this->_packageInfo['contents'])) { - $this->_tagCannotBeEmpty('contents'); + + return $this->statedir . DIRECTORY_SEPARATOR . strtolower($package) . '.reg'; + } + + /** + * Get the name of the file where data for a given channel is stored. + * @param string channel name + * @return string registry file name + */ + function _channelFileName($channel, $noaliases = false) + { + if (!$noaliases) { + if (file_exists($this->_getChannelAliasFileName($channel))) { + $channel = implode('', file($this->_getChannelAliasFileName($channel))); } - if (!isset($this->_packageInfo['contents']['dir'])) { - $this->_filelistMustContainDir('contents'); - return false; + } + return $this->channelsdir . DIRECTORY_SEPARATOR . str_replace('/', '_', + strtolower($channel)) . '.reg'; + } + + /** + * @param string + * @return string + */ + function _getChannelAliasFileName($alias) + { + return $this->channelsdir . DIRECTORY_SEPARATOR . '.alias' . + DIRECTORY_SEPARATOR . str_replace('/', '_', strtolower($alias)) . '.txt'; + } + + /** + * Get the name of a channel from its alias + */ + function _getChannelFromAlias($channel) + { + if (!$this->_channelExists($channel)) { + if ($channel == 'pear.php.net') { + return 'pear.php.net'; } - if (isset($this->_packageInfo['contents']['file'])) { - $this->_filelistCannotContainFile('contents'); - return false; + + if ($channel == 'pecl.php.net') { + return 'pecl.php.net'; } - } - $this->_validateMaintainers(); - $this->_validateStabilityVersion(); - $fail = false; - if (array_key_exists('usesrole', $this->_packageInfo)) { - $roles = $this->_packageInfo['usesrole']; - if (!is_array($roles) || !isset($roles[0])) { - $roles = array($roles); + + if ($channel == 'doc.php.net') { + return 'doc.php.net'; } - foreach ($roles as $role) { - if (!isset($role['role'])) { - $this->_usesroletaskMustHaveRoleTask('usesrole', 'role'); - $fail = true; - } else { - if (!isset($role['channel'])) { - if (!isset($role['uri'])) { - $this->_usesroletaskMustHaveChannelOrUri($role['role'], 'usesrole'); - $fail = true; - } - } elseif (!isset($role['package'])) { - $this->_usesroletaskMustHavePackage($role['role'], 'usesrole'); - $fail = true; - } - } + + if ($channel == '__uri') { + return '__uri'; } + + return false; } - if (array_key_exists('usestask', $this->_packageInfo)) { - $roles = $this->_packageInfo['usestask']; - if (!is_array($roles) || !isset($roles[0])) { - $roles = array($roles); + + $channel = strtolower($channel); + if (file_exists($this->_getChannelAliasFileName($channel))) { + // translate an alias to an actual channel + return implode('', file($this->_getChannelAliasFileName($channel))); + } + + return $channel; + } + + /** + * Get the alias of a channel from its alias or its name + */ + function _getAlias($channel) + { + if (!$this->_channelExists($channel)) { + if ($channel == 'pear.php.net') { + return 'pear'; } - foreach ($roles as $role) { - if (!isset($role['task'])) { - $this->_usesroletaskMustHaveRoleTask('usestask', 'task'); - $fail = true; - } else { - if (!isset($role['channel'])) { - if (!isset($role['uri'])) { - $this->_usesroletaskMustHaveChannelOrUri($role['task'], 'usestask'); - $fail = true; - } - } elseif (!isset($role['package'])) { - $this->_usesroletaskMustHavePackage($role['task'], 'usestask'); - $fail = true; - } - } + + if ($channel == 'pecl.php.net') { + return 'pecl'; + } + + if ($channel == 'doc.php.net') { + return 'phpdocs'; } - } - if ($fail) { return false; } - $list = $this->_packageInfo['contents']; - if (isset($list['dir']) && is_array($list['dir']) && isset($list['dir'][0])) { - $this->_multipleToplevelDirNotAllowed(); - return $this->_isValid = 0; + $channel = $this->_getChannel($channel); + if (PEAR::isError($channel)) { + return $channel; } - $this->_validateFilelist(); - $this->_validateRelease(); - if (!$this->_stack->hasErrors()) { - $chan = $this->_pf->_registry->getChannel($this->_pf->getChannel(), true); - if (PEAR::isError($chan)) { - $this->_unknownChannel($this->_pf->getChannel()); - } else { - $valpack = $chan->getValidationPackage(); - // for channel validator packages, always use the default PEAR validator. - // otherwise, they can't be installed or packaged - $validator = $chan->getValidationObject($this->_pf->getPackage()); - if (!$validator) { - $this->_stack->push(__FUNCTION__, 'error', - array_merge( - array('channel' => $chan->getName(), - 'package' => $this->_pf->getPackage()), - $valpack - ), - 'package "%channel%/%package%" cannot be properly validated without ' . - 'validation package "%channel%/%name%-%version%"'); - return $this->_isValid = 0; - } - $validator->setPackageFile($this->_pf); - $validator->validate($state); - $failures = $validator->getFailures(); - foreach ($failures['errors'] as $error) { - $this->_stack->push(__FUNCTION__, 'error', $error, - 'Channel validator error: field "%field%" - %reason%'); - } - foreach ($failures['warnings'] as $warning) { - $this->_stack->push(__FUNCTION__, 'warning', $warning, - 'Channel validator warning: field "%field%" - %reason%'); - } - } + return $channel->getAlias(); + } + + /** + * Get the name of the file where data for a given package is stored. + * + * @param string channel name, or false if this is a PEAR package + * @param string package name + * + * @return string registry file name + * + * @access public + */ + function _channelDirectoryName($channel) + { + if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') { + return $this->statedir; } - $this->_pf->_isValid = $this->_isValid = !$this->_stack->hasErrors('error'); - if ($this->_isValid && $state == PEAR_VALIDATE_PACKAGING && !$this->_filesValid) { - if ($this->_pf->getPackageType() == 'bundle') { - if ($this->_analyzeBundledPackages()) { - $this->_filesValid = $this->_pf->_filesValid = true; - } else { - $this->_pf->_isValid = $this->_isValid = 0; - } - } else { - if (!$this->_analyzePhpFiles()) { - $this->_pf->_isValid = $this->_isValid = 0; - } else { - $this->_filesValid = $this->_pf->_filesValid = true; - } - } + $ch = $this->_getChannelFromAlias($channel); + if (!$ch) { + $ch = $channel; } - if ($this->_isValid) { - return $this->_pf->_isValid = $this->_isValid = $state; + return $this->statedir . DIRECTORY_SEPARATOR . strtolower('.channel.' . + str_replace('/', '_', $ch)); + } + + function _openPackageFile($package, $mode, $channel = false) + { + if (!$this->_assertStateDir($channel)) { + return null; } - return $this->_pf->_isValid = $this->_isValid = 0; + if (!in_array($mode, array('r', 'rb')) && !$this->hasWriteAccess()) { + return null; + } + + $file = $this->_packageFileName($package, $channel); + if (!file_exists($file) && $mode == 'r' || $mode == 'rb') { + return null; + } + + $fp = @fopen($file, $mode); + if (!$fp) { + return null; + } + + return $fp; } - function _stupidSchemaValidate($structure, $xml, $root) + function _closePackageFile($fp) { - if (!is_array($xml)) { - $xml = array(); + fclose($fp); + } + + function _openChannelFile($channel, $mode) + { + if (!$this->_assertChannelDir()) { + return null; } - $keys = array_keys($xml); - reset($keys); - $key = current($keys); - while ($key == 'attribs' || $key == '_contents') { - $key = next($keys); + + if (!in_array($mode, array('r', 'rb')) && !$this->hasWriteAccess()) { + return null; } - $unfoundtags = $optionaltags = array(); - $ret = true; - $mismatch = false; - foreach ($structure as $struc) { - if ($key) { - $tag = $xml[$key]; - } - $test = $this->_processStructure($struc); - if (isset($test['choices'])) { - $loose = true; - foreach ($test['choices'] as $choice) { - if ($key == $choice['tag']) { - $key = next($keys); - while ($key == 'attribs' || $key == '_contents') { - $key = next($keys); - } - $unfoundtags = $optionaltags = array(); - $mismatch = false; - if ($key && $key != $choice['tag'] && isset($choice['multiple'])) { - $unfoundtags[] = $choice['tag']; - $optionaltags[] = $choice['tag']; - if ($key) { - $mismatch = true; - } - } - $ret &= $this->_processAttribs($choice, $tag, $root); - continue 2; - } else { - $unfoundtags[] = $choice['tag']; - $mismatch = true; + + $file = $this->_channelFileName($channel); + if (!file_exists($file) && $mode == 'r' || $mode == 'rb') { + return null; + } + + $fp = @fopen($file, $mode); + if (!$fp) { + return null; + } + + return $fp; + } + + function _closeChannelFile($fp) + { + fclose($fp); + } + + function _rebuildFileMap() + { + if (!class_exists('PEAR_Installer_Role')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Installer/Role.php'; + } + + $channels = $this->_listAllPackages(); + $files = array(); + foreach ($channels as $channel => $packages) { + foreach ($packages as $package) { + $version = $this->_packageInfo($package, 'version', $channel); + $filelist = $this->_packageInfo($package, 'filelist', $channel); + if (!is_array($filelist)) { + continue; + } + + foreach ($filelist as $name => $attrs) { + if (isset($attrs['attribs'])) { + $attrs = $attrs['attribs']; } - if (!isset($choice['multiple']) || $choice['multiple'] != '*') { - $loose = false; + + // it is possible for conflicting packages in different channels to + // conflict with data files/doc files + if ($name == 'dirtree') { + continue; + } + + if (isset($attrs['role']) && !in_array($attrs['role'], + PEAR_Installer_Role::getInstallableRoles())) { + // these are not installed + continue; + } + + if (isset($attrs['role']) && !in_array($attrs['role'], + PEAR_Installer_Role::getBaseinstallRoles())) { + $attrs['baseinstalldir'] = $package; + } + + if (isset($attrs['baseinstalldir'])) { + $file = $attrs['baseinstalldir'].DIRECTORY_SEPARATOR.$name; } else { - $optionaltags[] = $choice['tag']; + $file = $name; } - } - if (!$loose) { - $this->_invalidTagOrder($unfoundtags, $key, $root); - return false; - } - } else { - if ($key != $test['tag']) { - if (isset($test['multiple']) && $test['multiple'] != '*') { - $unfoundtags[] = $test['tag']; - $this->_invalidTagOrder($unfoundtags, $key, $root); - return false; + + $file = preg_replace(',^/+,', '', $file); + if ($channel != 'pear.php.net') { + if (!isset($files[$attrs['role']])) { + $files[$attrs['role']] = array(); + } + $files[$attrs['role']][$file] = array(strtolower($channel), + strtolower($package)); } else { - if ($key) { - $mismatch = true; + if (!isset($files[$attrs['role']])) { + $files[$attrs['role']] = array(); } - $unfoundtags[] = $test['tag']; - $optionaltags[] = $test['tag']; - } - if (!isset($test['multiple'])) { - $this->_invalidTagOrder($unfoundtags, $key, $root); - return false; + $files[$attrs['role']][$file] = strtolower($package); } - continue; - } else { - $unfoundtags = $optionaltags = array(); - $mismatch = false; - } - $key = next($keys); - while ($key == 'attribs' || $key == '_contents') { - $key = next($keys); - } - if ($key && $key != $test['tag'] && isset($test['multiple'])) { - $unfoundtags[] = $test['tag']; - $optionaltags[] = $test['tag']; - $mismatch = true; } - $ret &= $this->_processAttribs($test, $tag, $root); - continue; } } - if (!$mismatch && count($optionaltags)) { - // don't error out on any optional tags - $unfoundtags = array_diff($unfoundtags, $optionaltags); + + + $this->_assertStateDir(); + if (!$this->hasWriteAccess()) { + return false; } - if (count($unfoundtags)) { - $this->_invalidTagOrder($unfoundtags, $key, $root); - } elseif ($key) { - // unknown tags - $this->_invalidTagOrder('*no tags allowed here*', $key, $root); - while ($key = next($keys)) { - $this->_invalidTagOrder('*no tags allowed here*', $key, $root); - } + + $fp = @fopen($this->filemap, 'wb'); + if (!$fp) { + return false; } - return $ret; + + $this->filemap_cache = $files; + fwrite($fp, serialize($files)); + fclose($fp); + return true; } - function _processAttribs($choice, $tag, $context) + function _readFileMap() { - if (isset($choice['attribs'])) { - if (!is_array($tag)) { - $tag = array($tag); + if (!file_exists($this->filemap)) { + return array(); + } + + $fp = @fopen($this->filemap, 'r'); + if (!$fp) { + return $this->raiseError('PEAR_Registry: could not open filemap "' . $this->filemap . '"', PEAR_REGISTRY_ERROR_FILE, null, null, $php_errormsg); + } + + clearstatcache(); + $rt = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + $fsize = filesize($this->filemap); + fclose($fp); + $data = file_get_contents($this->filemap); + set_magic_quotes_runtime($rt); + $tmp = unserialize($data); + if (!$tmp && $fsize > 7) { + return $this->raiseError('PEAR_Registry: invalid filemap data', PEAR_REGISTRY_ERROR_FORMAT, null, null, $data); + } + + $this->filemap_cache = $tmp; + return true; + } + + /** + * Lock the registry. + * + * @param integer lock mode, one of LOCK_EX, LOCK_SH or LOCK_UN. + * See flock manual for more information. + * + * @return bool TRUE on success, FALSE if locking failed, or a + * PEAR error if some other error occurs (such as the + * lock file not being writable). + * + * @access private + */ + function _lock($mode = LOCK_EX) + { + if (stristr(php_uname(), 'Windows 9')) { + return true; + } + + if ($mode != LOCK_UN && is_resource($this->lock_fp)) { + // XXX does not check type of lock (LOCK_SH/LOCK_EX) + return true; + } + + if (!$this->_assertStateDir()) { + if ($mode == LOCK_EX) { + return $this->raiseError('Registry directory is not writeable by the current user'); } - $tags = $tag; - if (!isset($tags[0])) { - $tags = array($tags); + + return true; + } + + $open_mode = 'w'; + // XXX People reported problems with LOCK_SH and 'w' + if ($mode === LOCK_SH || $mode === LOCK_UN) { + if (!file_exists($this->lockfile)) { + touch($this->lockfile); } - $ret = true; - foreach ($tags as $i => $tag) { - if (!is_array($tag) || !isset($tag['attribs'])) { - foreach ($choice['attribs'] as $attrib) { - if ($attrib{0} != '?') { - $ret &= $this->_tagHasNoAttribs($choice['tag'], - $context); - continue 2; - } - } - } - foreach ($choice['attribs'] as $attrib) { - if ($attrib{0} != '?') { - if (!isset($tag['attribs'][$attrib])) { - $ret &= $this->_tagMissingAttribute($choice['tag'], - $attrib, $context); - } - } - } + $open_mode = 'r'; + } + + if (!is_resource($this->lock_fp)) { + $this->lock_fp = @fopen($this->lockfile, $open_mode); + } + + if (!is_resource($this->lock_fp)) { + $this->lock_fp = null; + return $this->raiseError("could not create lock file" . + (isset($php_errormsg) ? ": " . $php_errormsg : "")); + } + + if (!(int)flock($this->lock_fp, $mode)) { + switch ($mode) { + case LOCK_SH: $str = 'shared'; break; + case LOCK_EX: $str = 'exclusive'; break; + case LOCK_UN: $str = 'unlock'; break; + default: $str = 'unknown'; break; } - return $ret; + + //is resource at this point, close it on error. + fclose($this->lock_fp); + $this->lock_fp = null; + return $this->raiseError("could not acquire $str lock ($this->lockfile)", + PEAR_REGISTRY_ERROR_LOCK); } + return true; } - function _processStructure($key) + function _unlock() { - $ret = array(); - if (count($pieces = explode('|', $key)) > 1) { - $ret['choices'] = array(); - foreach ($pieces as $piece) { - $ret['choices'][] = $this->_processStructure($piece); - } - return $ret; - } - $multi = $key{0}; - if ($multi == '+' || $multi == '*') { - $ret['multiple'] = $key{0}; - $key = substr($key, 1); - } - if (count($attrs = explode('->', $key)) > 1) { - $ret['tag'] = array_shift($attrs); - $ret['attribs'] = $attrs; - } else { - $ret['tag'] = $key; + $ret = $this->_lock(LOCK_UN); + if (is_resource($this->lock_fp)) { + fclose($this->lock_fp); } + + $this->lock_fp = null; return $ret; } - function _validateStabilityVersion() + function _packageExists($package, $channel = false) { - $structure = array('release', 'api'); - $a = $this->_stupidSchemaValidate($structure, $this->_packageInfo['version'], ''); - $a &= $this->_stupidSchemaValidate($structure, $this->_packageInfo['stability'], ''); - if ($a) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $this->_packageInfo['version']['release'])) { - $this->_invalidVersion('release', $this->_packageInfo['version']['release']); - } - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $this->_packageInfo['version']['api'])) { - $this->_invalidVersion('api', $this->_packageInfo['version']['api']); - } - if (!in_array($this->_packageInfo['stability']['release'], - array('snapshot', 'devel', 'alpha', 'beta', 'stable'))) { - $this->_invalidState('release', $this->_packageInfo['stability']['release']); - } - if (!in_array($this->_packageInfo['stability']['api'], - array('devel', 'alpha', 'beta', 'stable'))) { - $this->_invalidState('api', $this->_packageInfo['stability']['api']); - } - } + return file_exists($this->_packageFileName($package, $channel)); } - function _validateMaintainers() + /** + * Determine whether a channel exists in the registry + * + * @param string Channel name + * @param bool if true, then aliases will be ignored + * @return boolean + */ + function _channelExists($channel, $noaliases = false) { - $structure = - array( - 'name', - 'user', - 'email', - 'active', - ); - foreach (array('lead', 'developer', 'contributor', 'helper') as $type) { - if (!isset($this->_packageInfo[$type])) { - continue; - } - if (isset($this->_packageInfo[$type][0])) { - foreach ($this->_packageInfo[$type] as $lead) { - $this->_stupidSchemaValidate($structure, $lead, '<' . $type . '>'); - } - } else { - $this->_stupidSchemaValidate($structure, $this->_packageInfo[$type], - '<' . $type . '>'); - } + $a = file_exists($this->_channelFileName($channel, $noaliases)); + if (!$a && $channel == 'pear.php.net') { + return true; + } + + if (!$a && $channel == 'pecl.php.net') { + return true; + } + + if (!$a && $channel == 'doc.php.net') { + return true; } + + return $a; } - function _validatePhpDep($dep, $installcondition = false) + /** + * Determine whether a mirror exists within the deafult channel in the registry + * + * @param string Channel name + * @param string Mirror name + * + * @return boolean + */ + function _mirrorExists($channel, $mirror) { - $structure = array( - 'min', - '*max', - '*exclude', - ); - $type = $installcondition ? '' : ''; - $this->_stupidSchemaValidate($structure, $dep, $type); - if (isset($dep['min'])) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/', - $dep['min'])) { - $this->_invalidVersion($type . '', $dep['min']); - } - } - if (isset($dep['max'])) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/', - $dep['max'])) { - $this->_invalidVersion($type . '', $dep['max']); - } + $data = $this->_channelInfo($channel); + if (!isset($data['servers']['mirror'])) { + return false; } - if (isset($dep['exclude'])) { - if (!is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); - } - foreach ($dep['exclude'] as $exclude) { - if (!preg_match( - '/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/', - $exclude)) { - $this->_invalidVersion($type . '', $exclude); - } + + foreach ($data['servers']['mirror'] as $m) { + if ($m['attribs']['host'] == $mirror) { + return true; } } + + return false; } - function _validatePearinstallerDep($dep) + /** + * @param PEAR_ChannelFile Channel object + * @param donotuse + * @param string Last-Modified HTTP tag from remote request + * @return boolean|PEAR_Error True on creation, false if it already exists + */ + function _addChannel($channel, $update = false, $lastmodified = false) { - $structure = array( - 'min', - '*max', - '*recommended', - '*exclude', - ); - $this->_stupidSchemaValidate($structure, $dep, ''); - if (isset($dep['min'])) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $dep['min'])) { - $this->_invalidVersion('', - $dep['min']); - } - } - if (isset($dep['max'])) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $dep['max'])) { - $this->_invalidVersion('', - $dep['max']); - } + if (!is_a($channel, 'PEAR_ChannelFile')) { + return false; } - if (isset($dep['recommended'])) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $dep['recommended'])) { - $this->_invalidVersion('', - $dep['recommended']); - } + + if (!$channel->validate()) { + return false; } - if (isset($dep['exclude'])) { - if (!is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); + + if (file_exists($this->_channelFileName($channel->getName()))) { + if (!$update) { + return false; } - foreach ($dep['exclude'] as $exclude) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $exclude)) { - $this->_invalidVersion('', - $exclude); - } + + $checker = $this->_getChannel($channel->getName()); + if (PEAR::isError($checker)) { + return $checker; } - } - } - function _validatePackageDep($dep, $group, $type = '') - { - if (isset($dep['uri'])) { - if (isset($dep['conflicts'])) { - $structure = array( - 'name', - 'uri', - 'conflicts', - '*providesextension', - ); - } else { - $structure = array( - 'name', - 'uri', - '*providesextension', - ); + if ($channel->getAlias() != $checker->getAlias()) { + if (file_exists($this->_getChannelAliasFileName($checker->getAlias()))) { + @unlink($this->_getChannelAliasFileName($checker->getAlias())); + } } } else { - if (isset($dep['conflicts'])) { - $structure = array( - 'name', - 'channel', - '*min', - '*max', - '*exclude', - 'conflicts', - '*providesextension', - ); - } else { - $structure = array( - 'name', - 'channel', - '*min', - '*max', - '*recommended', - '*exclude', - '*nodefault', - '*providesextension', - ); + if ($update && !in_array($channel->getName(), array('pear.php.net', 'pecl.php.net', 'doc.php.net'))) { + return false; } } - if (isset($dep['name'])) { - $type .= '' . $dep['name'] . ''; - } - $this->_stupidSchemaValidate($structure, $dep, '' . $group . $type); - if (isset($dep['uri']) && (isset($dep['min']) || isset($dep['max']) || - isset($dep['recommended']) || isset($dep['exclude']))) { - $this->_uriDepsCannotHaveVersioning('' . $group . $type); + + $ret = $this->_assertChannelDir(); + if (PEAR::isError($ret)) { + return $ret; } - if (isset($dep['channel']) && strtolower($dep['channel']) == '__uri') { - $this->_DepchannelCannotBeUri('' . $group . $type); + + $ret = $this->_assertChannelStateDir($channel->getName()); + if (PEAR::isError($ret)) { + return $ret; } - if (isset($dep['min'])) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $dep['min'])) { - $this->_invalidVersion('' . $group . $type . '', $dep['min']); + + if ($channel->getAlias() != $channel->getName()) { + if (file_exists($this->_getChannelAliasFileName($channel->getAlias())) && + $this->_getChannelFromAlias($channel->getAlias()) != $channel->getName()) { + $channel->setAlias($channel->getName()); } - } - if (isset($dep['max'])) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $dep['max'])) { - $this->_invalidVersion('' . $group . $type . '', $dep['max']); + + if (!$this->hasWriteAccess()) { + return false; } - } - if (isset($dep['recommended'])) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $dep['recommended'])) { - $this->_invalidVersion('' . $group . $type . '', - $dep['recommended']); + + $fp = @fopen($this->_getChannelAliasFileName($channel->getAlias()), 'w'); + if (!$fp) { + return false; } + + fwrite($fp, $channel->getName()); + fclose($fp); } - if (isset($dep['exclude'])) { - if (!is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); - } - foreach ($dep['exclude'] as $exclude) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $exclude)) { - $this->_invalidVersion('' . $group . $type . '', - $exclude); - } - } + + if (!$this->hasWriteAccess()) { + return false; } - } - function _validateSubpackageDep($dep, $group) - { - $this->_validatePackageDep($dep, $group, ''); - if (isset($dep['providesextension'])) { - $this->_subpackageCannotProvideExtension(isset($dep['name']) ? $dep['name'] : ''); + $fp = @fopen($this->_channelFileName($channel->getName()), 'wb'); + if (!$fp) { + return false; } - if (isset($dep['conflicts'])) { - $this->_subpackagesCannotConflict(isset($dep['name']) ? $dep['name'] : ''); + + $info = $channel->toArray(); + if ($lastmodified) { + $info['_lastmodified'] = $lastmodified; + } else { + $info['_lastmodified'] = date('r'); } + + fwrite($fp, serialize($info)); + fclose($fp); + return true; } - function _validateExtensionDep($dep, $group = false, $installcondition = false) + /** + * Deletion fails if there are any packages installed from the channel + * @param string|PEAR_ChannelFile channel name + * @return boolean|PEAR_Error True on deletion, false if it doesn't exist + */ + function _deleteChannel($channel) { - if (isset($dep['conflicts'])) { - $structure = array( - 'name', - '*min', - '*max', - '*exclude', - 'conflicts', - ); - } else { - $structure = array( - 'name', - '*min', - '*max', - '*recommended', - '*exclude', - ); - } - if ($installcondition) { - $type = ''; - } else { - $type = '' . $group . ''; - } - if (isset($dep['name'])) { - $type .= '' . $dep['name'] . ''; - } - $this->_stupidSchemaValidate($structure, $dep, $type); - if (isset($dep['min'])) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $dep['min'])) { - $this->_invalidVersion(substr($type, 1) . '_invalidVersion(substr($type, 1) . 'validate()) { + return false; } + $channel = $channel->getName(); } - if (isset($dep['recommended'])) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $dep['recommended'])) { - $this->_invalidVersion(substr($type, 1) . '_getChannelFromAlias($channel) == '__uri') { + return false; } - if (isset($dep['exclude'])) { - if (!is_array($dep['exclude'])) { - $dep['exclude'] = array($dep['exclude']); - } - foreach ($dep['exclude'] as $exclude) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $exclude)) { - $this->_invalidVersion(substr($type, 1) . '_getChannelFromAlias($channel) == 'pecl.php.net') { + return false; } - } - function _validateOsDep($dep, $installcondition = false) - { - $structure = array( - 'name', - '*conflicts', - ); - $type = $installcondition ? '' : ''; - if ($this->_stupidSchemaValidate($structure, $dep, $type)) { - if ($dep['name'] == '*') { - if (array_key_exists('conflicts', $dep)) { - $this->_cannotConflictWithAllOs($type); - } - } + if ($this->_getChannelFromAlias($channel) == 'doc.php.net') { + return false; } - } - function _validateArchDep($dep, $installcondition = false) - { - $structure = array( - 'pattern', - '*conflicts', - ); - $type = $installcondition ? '' : ''; - $this->_stupidSchemaValidate($structure, $dep, $type); - } + if (!$this->_channelExists($channel)) { + return false; + } - function _validateInstallConditions($cond, $release) - { - $structure = array( - '*php', - '*extension', - '*os', - '*arch', - ); - if (!$this->_stupidSchemaValidate($structure, - $cond, $release)) { + if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') { return false; } - foreach (array('php', 'extension', 'os', 'arch') as $type) { - if (isset($cond[$type])) { - $iter = $cond[$type]; - if (!is_array($iter) || !isset($iter[0])) { - $iter = array($iter); - } - foreach ($iter as $package) { - if ($type == 'extension') { - $this->{"_validate{$type}Dep"}($package, false, true); - } else { - $this->{"_validate{$type}Dep"}($package, true); - } - } - } + + $channel = $this->_getChannelFromAlias($channel); + if ($channel == 'pear.php.net') { + return false; } - } - function _validateDependencies() - { - $structure = array( - 'required', - '*optional', - '*group->name->hint' - ); - if (!$this->_stupidSchemaValidate($structure, - $this->_packageInfo['dependencies'], '')) { + $test = $this->_listChannelPackages($channel); + if (count($test)) { return false; } - foreach (array('required', 'optional') as $simpledep) { - if (isset($this->_packageInfo['dependencies'][$simpledep])) { - if ($simpledep == 'optional') { - $structure = array( - '*package', - '*subpackage', - '*extension', - ); - } else { - $structure = array( - 'php', - 'pearinstaller', - '*package', - '*subpackage', - '*extension', - '*os', - '*arch', - ); - } - if ($this->_stupidSchemaValidate($structure, - $this->_packageInfo['dependencies'][$simpledep], - "<$simpledep>")) { - foreach (array('package', 'subpackage', 'extension') as $type) { - if (isset($this->_packageInfo['dependencies'][$simpledep][$type])) { - $iter = $this->_packageInfo['dependencies'][$simpledep][$type]; - if (!isset($iter[0])) { - $iter = array($iter); - } - foreach ($iter as $package) { - if ($type != 'extension') { - if (isset($package['uri'])) { - if (isset($package['channel'])) { - $this->_UrlOrChannel($type, - $package['name']); - } - } else { - if (!isset($package['channel'])) { - $this->_NoChannel($type, $package['name']); - } - } - } - $this->{"_validate{$type}Dep"}($package, "<$simpledep>"); - } - } - } - if ($simpledep == 'optional') { - continue; - } - foreach (array('php', 'pearinstaller', 'os', 'arch') as $type) { - if (isset($this->_packageInfo['dependencies'][$simpledep][$type])) { - $iter = $this->_packageInfo['dependencies'][$simpledep][$type]; - if (!isset($iter[0])) { - $iter = array($iter); - } - foreach ($iter as $package) { - $this->{"_validate{$type}Dep"}($package); - } - } - } - } - } + + $test = @rmdir($this->_channelDirectoryName($channel)); + if (!$test) { + return false; } - if (isset($this->_packageInfo['dependencies']['group'])) { - $groups = $this->_packageInfo['dependencies']['group']; - if (!isset($groups[0])) { - $groups = array($groups); + + $file = $this->_getChannelAliasFileName($this->_getAlias($channel)); + if (file_exists($file)) { + $test = @unlink($file); + if (!$test) { + return false; } - $structure = array( - '*package', - '*subpackage', - '*extension', - ); - foreach ($groups as $group) { - if ($this->_stupidSchemaValidate($structure, $group, '')) { - if (!PEAR_Validate::validGroupName($group['attribs']['name'])) { - $this->_invalidDepGroupName($group['attribs']['name']); - } - foreach (array('package', 'subpackage', 'extension') as $type) { - if (isset($group[$type])) { - $iter = $group[$type]; - if (!isset($iter[0])) { - $iter = array($iter); - } - foreach ($iter as $package) { - if ($type != 'extension') { - if (isset($package['uri'])) { - if (isset($package['channel'])) { - $this->_UrlOrChannelGroup($type, - $package['name'], - $group['name']); - } - } else { - if (!isset($package['channel'])) { - $this->_NoChannelGroup($type, - $package['name'], - $group['name']); - } - } - } - $this->{"_validate{$type}Dep"}($package, ''); - } - } + } + + $file = $this->_channelFileName($channel); + $ret = true; + if (file_exists($file)) { + $ret = @unlink($file); + } + + return $ret; + } + + /** + * Determine whether a channel exists in the registry + * @param string Channel Alias + * @return boolean + */ + function _isChannelAlias($alias) + { + return file_exists($this->_getChannelAliasFileName($alias)); + } + + /** + * @param string|null + * @param string|null + * @param string|null + * @return array|null + * @access private + */ + function _packageInfo($package = null, $key = null, $channel = 'pear.php.net') + { + if ($package === null) { + if ($channel === null) { + $channels = $this->_listChannels(); + $ret = array(); + foreach ($channels as $channel) { + $channel = strtolower($channel); + $ret[$channel] = array(); + $packages = $this->_listPackages($channel); + foreach ($packages as $package) { + $ret[$channel][] = $this->_packageInfo($package, null, $channel); } } + + return $ret; + } + + $ps = $this->_listPackages($channel); + if (!count($ps)) { + return array(); } + return array_map(array(&$this, '_packageInfo'), + $ps, array_fill(0, count($ps), null), + array_fill(0, count($ps), $channel)); + } + + $fp = $this->_openPackageFile($package, 'r', $channel); + if ($fp === null) { + return null; + } + + $rt = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + clearstatcache(); + $this->_closePackageFile($fp); + $data = file_get_contents($this->_packageFileName($package, $channel)); + set_magic_quotes_runtime($rt); + $data = unserialize($data); + if ($key === null) { + return $data; + } + + // compatibility for package.xml version 2.0 + if (isset($data['old'][$key])) { + return $data['old'][$key]; + } + + if (isset($data[$key])) { + return $data[$key]; } + + return null; } - function _validateCompatible() + /** + * @param string Channel name + * @param bool whether to strictly retrieve info of channels, not just aliases + * @return array|null + */ + function _channelInfo($channel, $noaliases = false) { - $compat = $this->_packageInfo['compatible']; - if (!isset($compat[0])) { - $compat = array($compat); + if (!$this->_channelExists($channel, $noaliases)) { + return null; } - $required = array('name', 'channel', 'min', 'max', '*exclude'); - foreach ($compat as $package) { - $type = ''; - if (is_array($package) && array_key_exists('name', $package)) { - $type .= '' . $package['name'] . ''; - } - $this->_stupidSchemaValidate($required, $package, $type); - if (is_array($package) && array_key_exists('min', $package)) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $package['min'])) { - $this->_invalidVersion(substr($type, 1) . '_invalidVersion(substr($type, 1) . '_openChannelFile($channel, 'r'); + if ($fp === null) { + return null; + } + + $rt = get_magic_quotes_runtime(); + set_magic_quotes_runtime(0); + clearstatcache(); + $this->_closeChannelFile($fp); + $data = file_get_contents($this->_channelFileName($channel)); + set_magic_quotes_runtime($rt); + $data = unserialize($data); + return $data; + } + + function _listChannels() + { + $channellist = array(); + if (!file_exists($this->channelsdir) || !is_dir($this->channelsdir)) { + return array('pear.php.net', 'pecl.php.net', 'doc.php.net', '__uri'); + } + + $dp = opendir($this->channelsdir); + while ($ent = readdir($dp)) { + if ($ent{0} == '.' || substr($ent, -4) != '.reg') { + continue; } - if (is_array($package) && array_key_exists('exclude', $package)) { - if (!is_array($package['exclude'])) { - $package['exclude'] = array($package['exclude']); - } - foreach ($package['exclude'] as $exclude) { - if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/', - $exclude)) { - $this->_invalidVersion(substr($type, 1) . '_NoBundledPackages(); + if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') { + return $this->_listChannelPackages($channel); } - if (!is_array($list['bundledpackage']) || !isset($list['bundledpackage'][0])) { - return $this->_AtLeast2BundledPackages(); + + if (!file_exists($this->statedir) || !is_dir($this->statedir)) { + return array(); } - foreach ($list['bundledpackage'] as $package) { - if (!is_string($package)) { - $this->_bundledPackagesMustBeFilename(); + + $pkglist = array(); + $dp = opendir($this->statedir); + if (!$dp) { + return $pkglist; + } + + while ($ent = readdir($dp)) { + if ($ent{0} == '.' || substr($ent, -4) != '.reg') { + continue; } + + $pkglist[] = substr($ent, 0, -4); } + closedir($dp); + return $pkglist; } - function _validateFilelist($list = false, $allowignore = false, $dirs = '') + function _listChannelPackages($channel) { - $iscontents = false; - if (!$list) { - $iscontents = true; - $list = $this->_packageInfo['contents']; - if (isset($this->_packageInfo['bundle'])) { - return $this->_validateBundle($list); - } + $pkglist = array(); + if (!file_exists($this->_channelDirectoryName($channel)) || + !is_dir($this->_channelDirectoryName($channel))) { + return array(); } - if ($allowignore) { - $struc = array( - '*install->name->as', - '*ignore->name' - ); - } else { - $struc = array( - '*dir->name->?baseinstalldir', - '*file->name->role->?baseinstalldir->?md5sum' - ); - if (isset($list['dir']) && isset($list['file'])) { - // stave off validation errors without requiring a set order. - $_old = $list; - if (isset($list['attribs'])) { - $list = array('attribs' => $_old['attribs']); - } - $list['dir'] = $_old['dir']; - $list['file'] = $_old['file']; - } + + $dp = opendir($this->_channelDirectoryName($channel)); + if (!$dp) { + return $pkglist; } - if (!isset($list['attribs']) || !isset($list['attribs']['name'])) { - $unknown = $allowignore ? '' : ''; - $dirname = $iscontents ? '' : $unknown; - } else { - $dirname = ''; - if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~', - str_replace('\\', '/', $list['attribs']['name']))) { - // file contains .. parent directory or . cur directory - $this->_invalidDirName($list['attribs']['name']); + + while ($ent = readdir($dp)) { + if ($ent{0} == '.' || substr($ent, -4) != '.reg') { + continue; } + $pkglist[] = substr($ent, 0, -4); } - $res = $this->_stupidSchemaValidate($struc, $list, $dirname); - if ($allowignore && $res) { - $ignored_or_installed = array(); - $this->_pf->getFilelist(); - $fcontents = $this->_pf->getContents(); - $filelist = array(); - if (!isset($fcontents['dir']['file'][0])) { - $fcontents['dir']['file'] = array($fcontents['dir']['file']); - } - foreach ($fcontents['dir']['file'] as $file) { - $filelist[$file['attribs']['name']] = true; - } - if (isset($list['install'])) { - if (!isset($list['install'][0])) { - $list['install'] = array($list['install']); - } - foreach ($list['install'] as $file) { - if (!isset($filelist[$file['attribs']['name']])) { - $this->_notInContents($file['attribs']['name'], 'install'); - continue; - } - if (array_key_exists($file['attribs']['name'], $ignored_or_installed)) { - $this->_multipleInstallAs($file['attribs']['name']); - } - if (!isset($ignored_or_installed[$file['attribs']['name']])) { - $ignored_or_installed[$file['attribs']['name']] = array(); - } - $ignored_or_installed[$file['attribs']['name']][] = 1; - if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~', - str_replace('\\', '/', $file['attribs']['as']))) { - // file contains .. parent directory or . cur directory references - $this->_invalidFileInstallAs($file['attribs']['name'], - $file['attribs']['as']); - } - } - } - if (isset($list['ignore'])) { - if (!isset($list['ignore'][0])) { - $list['ignore'] = array($list['ignore']); - } - foreach ($list['ignore'] as $file) { - if (!isset($filelist[$file['attribs']['name']])) { - $this->_notInContents($file['attribs']['name'], 'ignore'); - continue; - } - if (array_key_exists($file['attribs']['name'], $ignored_or_installed)) { - $this->_ignoreAndInstallAs($file['attribs']['name']); - } - } - } + + closedir($dp); + return $pkglist; + } + + function _listAllPackages() + { + $ret = array(); + foreach ($this->_listChannels() as $channel) { + $ret[$channel] = $this->_listPackages($channel); } - if (!$allowignore && isset($list['file'])) { - if (is_string($list['file'])) { - $this->_oldStyleFileNotAllowed(); - return false; - } - if (!isset($list['file'][0])) { - // single file - $list['file'] = array($list['file']); - } - foreach ($list['file'] as $i => $file) - { - if (isset($file['attribs']) && isset($file['attribs']['name'])) { - if ($file['attribs']['name']{0} == '.' && - $file['attribs']['name']{1} == '/') { - // name is something like "./doc/whatever.txt" - $this->_invalidFileName($file['attribs']['name'], $dirname); - } - if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~', - str_replace('\\', '/', $file['attribs']['name']))) { - // file contains .. parent directory or . cur directory - $this->_invalidFileName($file['attribs']['name'], $dirname); - } - } - if (isset($file['attribs']) && isset($file['attribs']['role'])) { - if (!$this->_validateRole($file['attribs']['role'])) { - if (isset($this->_packageInfo['usesrole'])) { - $roles = $this->_packageInfo['usesrole']; - if (!isset($roles[0])) { - $roles = array($roles); - } - foreach ($roles as $role) { - if ($role['role'] = $file['attribs']['role']) { - $msg = 'This package contains role "%role%" and requires ' . - 'package "%package%" to be used'; - if (isset($role['uri'])) { - $params = array('role' => $role['role'], - 'package' => $role['uri']); - } else { - $params = array('role' => $role['role'], - 'package' => $this->_pf->_registry-> - parsedPackageNameToString(array('package' => - $role['package'], 'channel' => $role['channel']), - true)); - } - $this->_stack->push('_mustInstallRole', 'error', $params, $msg); - } - } - } - $this->_invalidFileRole($file['attribs']['name'], - $dirname, $file['attribs']['role']); - } - } - if (!isset($file['attribs'])) { - continue; - } - $save = $file['attribs']; - if ($dirs) { - $save['name'] = $dirs . '/' . $save['name']; - } - unset($file['attribs']); - if (count($file) && $this->_curState != PEAR_VALIDATE_DOWNLOADING) { // has tasks - foreach ($file as $task => $value) { - if ($tagClass = $this->_pf->getTask($task)) { - if (!is_array($value) || !isset($value[0])) { - $value = array($value); - } - foreach ($value as $v) { - $ret = call_user_func(array($tagClass, 'validateXml'), - $this->_pf, $v, $this->_pf->_config, $save); - if (is_array($ret)) { - $this->_invalidTask($task, $ret, isset($save['name']) ? - $save['name'] : ''); - } - } - } else { - if (isset($this->_packageInfo['usestask'])) { - $roles = $this->_packageInfo['usestask']; - if (!isset($roles[0])) { - $roles = array($roles); - } - foreach ($roles as $role) { - if ($role['task'] = $task) { - $msg = 'This package contains task "%task%" and requires ' . - 'package "%package%" to be used'; - if (isset($role['uri'])) { - $params = array('task' => $role['task'], - 'package' => $role['uri']); - } else { - $params = array('task' => $role['task'], - 'package' => $this->_pf->_registry-> - parsedPackageNameToString(array('package' => - $role['package'], 'channel' => $role['channel']), - true)); - } - $this->_stack->push('_mustInstallTask', 'error', - $params, $msg); - } - } - } - $this->_unknownTask($task, $save['name']); - } - } - } - } + + return $ret; + } + + /** + * Add an installed package to the registry + * @param string package name + * @param array package info (parsed by PEAR_Common::infoFrom*() methods) + * @return bool success of saving + * @access private + */ + function _addPackage($package, $info) + { + if ($this->_packageExists($package)) { + return false; } - if (isset($list['ignore'])) { - if (!$allowignore) { - $this->_ignoreNotAllowed('ignore'); - } + + $fp = $this->_openPackageFile($package, 'wb'); + if ($fp === null) { + return false; } - if (isset($list['install'])) { - if (!$allowignore) { - $this->_ignoreNotAllowed('install'); - } + + $info['_lastmodified'] = time(); + fwrite($fp, serialize($info)); + $this->_closePackageFile($fp); + if (isset($info['filelist'])) { + $this->_rebuildFileMap(); } - if (isset($list['file'])) { - if ($allowignore) { - $this->_fileNotAllowed('file'); - } + + return true; + } + + /** + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @return bool + * @access private + */ + function _addPackage2($info) + { + if (!is_a($info, 'PEAR_PackageFile_v1') && !is_a($info, 'PEAR_PackageFile_v2')) { + return false; } - if (isset($list['dir'])) { - if ($allowignore) { - $this->_fileNotAllowed('dir'); - } else { - if (!isset($list['dir'][0])) { - $list['dir'] = array($list['dir']); - } - foreach ($list['dir'] as $dir) { - if (isset($dir['attribs']) && isset($dir['attribs']['name'])) { - if ($dir['attribs']['name'] == '/' || - !isset($this->_packageInfo['contents']['dir']['dir'])) { - // always use nothing if the filelist has already been flattened - $newdirs = ''; - } elseif ($dirs == '') { - $newdirs = $dir['attribs']['name']; - } else { - $newdirs = $dirs . '/' . $dir['attribs']['name']; - } - } else { - $newdirs = $dirs; + + if (!$info->validate()) { + if (class_exists('PEAR_Common')) { + $ui = PEAR_Frontend::singleton(); + if ($ui) { + foreach ($info->getValidationWarnings() as $err) { + $ui->log($err['message'], true); } - $this->_validateFilelist($dir, $allowignore, $newdirs); } } + return false; } + + $channel = $info->getChannel(); + $package = $info->getPackage(); + $save = $info; + if ($this->_packageExists($package, $channel)) { + return false; + } + + if (!$this->_channelExists($channel, true)) { + return false; + } + + $info = $info->toArray(true); + if (!$info) { + return false; + } + + $fp = $this->_openPackageFile($package, 'wb', $channel); + if ($fp === null) { + return false; + } + + $info['_lastmodified'] = time(); + fwrite($fp, serialize($info)); + $this->_closePackageFile($fp); + $this->_rebuildFileMap(); + return true; } - function _validateRelease() + /** + * @param string Package name + * @param array parsed package.xml 1.0 + * @param bool this parameter is only here for BC. Don't use it. + * @access private + */ + function _updatePackage($package, $info, $merge = true) { - if (isset($this->_packageInfo['phprelease'])) { - $release = 'phprelease'; - if (isset($this->_packageInfo['providesextension'])) { - $this->_cannotProvideExtension($release); - } - if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) { - $this->_cannotHaveSrcpackage($release); - } - $releases = $this->_packageInfo['phprelease']; - if (!is_array($releases)) { - return true; - } - if (!isset($releases[0])) { - $releases = array($releases); - } - foreach ($releases as $rel) { - $this->_stupidSchemaValidate(array( - '*installconditions', - '*filelist', - ), $rel, ''); - } + $oldinfo = $this->_packageInfo($package); + if (empty($oldinfo)) { + return false; } - foreach (array('', 'zend') as $prefix) { - $releasetype = $prefix . 'extsrcrelease'; - if (isset($this->_packageInfo[$releasetype])) { - $release = $releasetype; - if (!isset($this->_packageInfo['providesextension'])) { - $this->_mustProvideExtension($release); - } - if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) { - $this->_cannotHaveSrcpackage($release); - } - $releases = $this->_packageInfo[$releasetype]; - if (!is_array($releases)) { - return true; - } - if (!isset($releases[0])) { - $releases = array($releases); - } - foreach ($releases as $rel) { - $this->_stupidSchemaValidate(array( - '*installconditions', - '*configureoption->name->prompt->?default', - '*binarypackage', - '*filelist', - ), $rel, '<' . $releasetype . '>'); - if (isset($rel['binarypackage'])) { - if (!is_array($rel['binarypackage']) || !isset($rel['binarypackage'][0])) { - $rel['binarypackage'] = array($rel['binarypackage']); - } - foreach ($rel['binarypackage'] as $bin) { - if (!is_string($bin)) { - $this->_binaryPackageMustBePackagename(); - } - } - } - } - } - $releasetype = 'extbinrelease'; - if (isset($this->_packageInfo[$releasetype])) { - $release = $releasetype; - if (!isset($this->_packageInfo['providesextension'])) { - $this->_mustProvideExtension($release); - } - if (isset($this->_packageInfo['channel']) && - !isset($this->_packageInfo['srcpackage'])) { - $this->_mustSrcPackage($release); - } - if (isset($this->_packageInfo['uri']) && !isset($this->_packageInfo['srcuri'])) { - $this->_mustSrcuri($release); - } - $releases = $this->_packageInfo[$releasetype]; - if (!is_array($releases)) { - return true; - } - if (!isset($releases[0])) { - $releases = array($releases); - } - foreach ($releases as $rel) { - $this->_stupidSchemaValidate(array( - '*installconditions', - '*filelist', - ), $rel, '<' . $releasetype . '>'); - } - } + + $fp = $this->_openPackageFile($package, 'w'); + if ($fp === null) { + return false; } - if (isset($this->_packageInfo['bundle'])) { - $release = 'bundle'; - if (isset($this->_packageInfo['providesextension'])) { - $this->_cannotProvideExtension($release); - } - if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) { - $this->_cannotHaveSrcpackage($release); - } - $releases = $this->_packageInfo['bundle']; - if (!is_array($releases) || !isset($releases[0])) { - $releases = array($releases); - } - foreach ($releases as $rel) { - $this->_stupidSchemaValidate(array( - '*installconditions', - '*filelist', - ), $rel, ''); - } + + if (is_object($info)) { + $info = $info->toArray(); + } + $info['_lastmodified'] = time(); + + $newinfo = $info; + if ($merge) { + $info = array_merge($oldinfo, $info); + } else { + $diff = $info; } - foreach ($releases as $rel) { - if (is_array($rel) && array_key_exists('installconditions', $rel)) { - $this->_validateInstallConditions($rel['installconditions'], - "<$release>"); - } - if (is_array($rel) && array_key_exists('filelist', $rel)) { - if ($rel['filelist']) { - $this->_validateFilelist($rel['filelist'], true); - } - } + fwrite($fp, serialize($info)); + $this->_closePackageFile($fp); + if (isset($newinfo['filelist'])) { + $this->_rebuildFileMap(); } + + return true; } /** - * This is here to allow role extension through plugins - * @param string + * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 + * @return bool + * @access private */ - function _validateRole($role) - { - return in_array($role, PEAR_Installer_Role::getValidRoles($this->_pf->getPackageType())); - } - - function _pearVersionTooLow($version) + function _updatePackage2($info) { - $this->_stack->push(__FUNCTION__, 'error', - array('version' => $version), - 'This package.xml requires PEAR version %version% to parse properly, we are ' . - 'version 1.8.0'); - } + if (!$this->_packageExists($info->getPackage(), $info->getChannel())) { + return false; + } - function _invalidTagOrder($oktags, $actual, $root) - { - $this->_stack->push(__FUNCTION__, 'error', - array('oktags' => $oktags, 'actual' => $actual, 'root' => $root), - 'Invalid tag order in %root%, found <%actual%> expected one of "%oktags%"'); - } + $fp = $this->_openPackageFile($info->getPackage(), 'w', $info->getChannel()); + if ($fp === null) { + return false; + } - function _ignoreNotAllowed($type) - { - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type), - '<%type%> is not allowed inside global , only inside ' . - '//, use and only'); + $save = $info; + $info = $save->getArray(true); + $info['_lastmodified'] = time(); + fwrite($fp, serialize($info)); + $this->_closePackageFile($fp); + $this->_rebuildFileMap(); + return true; } - function _fileNotAllowed($type) + /** + * @param string Package name + * @param string Channel name + * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|null + * @access private + */ + function &_getPackage($package, $channel = 'pear.php.net') { - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type), - '<%type%> is not allowed inside release , only inside ' . - ', use and only'); - } + $info = $this->_packageInfo($package, null, $channel); + if ($info === null) { + return $info; + } - function _oldStyleFileNotAllowed() - { - $this->_stack->push(__FUNCTION__, 'error', array(), - 'Old-style name is not allowed. Use' . - ''); - } + $a = $this->_config; + if (!$a) { + $this->_config = &new PEAR_Config; + $this->_config->set('php_dir', $this->statedir); + } - function _tagMissingAttribute($tag, $attr, $context) - { - $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag, - 'attribute' => $attr, 'context' => $context), - 'tag <%tag%> in context "%context%" has no attribute "%attribute%"'); - } + if (!class_exists('PEAR_PackageFile')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile.php'; + } - function _tagHasNoAttribs($tag, $context) - { - $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag, - 'context' => $context), - 'tag <%tag%> has no attributes in context "%context%"'); + $pkg = &new PEAR_PackageFile($this->_config); + $pf = &$pkg->fromArray($info); + return $pf; } - function _invalidInternalStructure() + /** + * @param string channel name + * @param bool whether to strictly retrieve channel names + * @return PEAR_ChannelFile|PEAR_Error + * @access private + */ + function &_getChannel($channel, $noaliases = false) { - $this->_stack->push(__FUNCTION__, 'exception', array(), - 'internal array was not generated by compatible parser, or extreme parser error, cannot continue'); - } + $ch = false; + if ($this->_channelExists($channel, $noaliases)) { + $chinfo = $this->_channelInfo($channel, $noaliases); + if ($chinfo) { + if (!class_exists('PEAR_ChannelFile')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/ChannelFile.php'; + } - function _invalidFileRole($file, $dir, $role) - { - $this->_stack->push(__FUNCTION__, 'error', array( - 'file' => $file, 'dir' => $dir, 'role' => $role, - 'roles' => PEAR_Installer_Role::getValidRoles($this->_pf->getPackageType())), - 'File "%file%" in directory "%dir%" has invalid role "%role%", should be one of %roles%'); - } + $ch = &PEAR_ChannelFile::fromArrayWithErrors($chinfo); + } + } - function _invalidFileName($file, $dir) - { - $this->_stack->push(__FUNCTION__, 'error', array( - 'file' => $file), - 'File "%file%" in directory "%dir%" cannot begin with "./" or contain ".."'); - } + if ($ch) { + if ($ch->validate()) { + return $ch; + } - function _invalidFileInstallAs($file, $as) - { - $this->_stack->push(__FUNCTION__, 'error', array( - 'file' => $file, 'as' => $as), - 'File "%file%" cannot contain "./" or contain ".."'); - } + foreach ($ch->getErrors(true) as $err) { + $message = $err['message'] . "\n"; + } - function _invalidDirName($dir) - { - $this->_stack->push(__FUNCTION__, 'error', array( - 'dir' => $file), - 'Directory "%dir%" cannot begin with "./" or contain ".."'); - } + $ch = PEAR::raiseError($message); + return $ch; + } - function _filelistCannotContainFile($filelist) - { - $this->_stack->push(__FUNCTION__, 'error', array('tag' => $filelist), - '<%tag%> can only contain , contains . Use ' . - ' as the first dir element'); - } + if ($this->_getChannelFromAlias($channel) == 'pear.php.net') { + // the registry is not properly set up, so use defaults + if (!class_exists('PEAR_ChannelFile')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/ChannelFile.php'; + } - function _filelistMustContainDir($filelist) - { - $this->_stack->push(__FUNCTION__, 'error', array('tag' => $filelist), - '<%tag%> must contain . Use as the ' . - 'first dir element'); - } + $pear_channel = new PEAR_ChannelFile; + $pear_channel->setServer('pear.php.net'); + $pear_channel->setAlias('pear'); + $pear_channel->setSummary('PHP Extension and Application Repository'); + $pear_channel->setDefaultPEARProtocols(); + $pear_channel->setBaseURL('REST1.0', 'http://pear.php.net/rest/'); + $pear_channel->setBaseURL('REST1.1', 'http://pear.php.net/rest/'); + $pear_channel->setBaseURL('REST1.3', 'http://pear.php.net/rest/'); + return $pear_channel; + } - function _tagCannotBeEmpty($tag) - { - $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag), - '<%tag%> cannot be empty (<%tag%/>)'); - } + if ($this->_getChannelFromAlias($channel) == 'pecl.php.net') { + // the registry is not properly set up, so use defaults + if (!class_exists('PEAR_ChannelFile')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/ChannelFile.php'; + } + $pear_channel = new PEAR_ChannelFile; + $pear_channel->setServer('pecl.php.net'); + $pear_channel->setAlias('pecl'); + $pear_channel->setSummary('PHP Extension Community Library'); + $pear_channel->setDefaultPEARProtocols(); + $pear_channel->setBaseURL('REST1.0', 'http://pecl.php.net/rest/'); + $pear_channel->setBaseURL('REST1.1', 'http://pecl.php.net/rest/'); + $pear_channel->setValidationPackage('PEAR_Validator_PECL', '1.0'); + return $pear_channel; + } - function _UrlOrChannel($type, $name) - { - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, - 'name' => $name), - 'Required dependency <%type%> "%name%" can have either url OR ' . - 'channel attributes, and not both'); - } + if ($this->_getChannelFromAlias($channel) == 'doc.php.net') { + // the registry is not properly set up, so use defaults + if (!class_exists('PEAR_ChannelFile')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/ChannelFile.php'; + } - function _NoChannel($type, $name) - { - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, - 'name' => $name), - 'Required dependency <%type%> "%name%" must have either url OR ' . - 'channel attributes'); - } + $doc_channel = new PEAR_ChannelFile; + $doc_channel->setServer('doc.php.net'); + $doc_channel->setAlias('phpdocs'); + $doc_channel->setSummary('PHP Documentation Team'); + $doc_channel->setDefaultPEARProtocols(); + $doc_channel->setBaseURL('REST1.0', 'http://doc.php.net/rest/'); + $doc_channel->setBaseURL('REST1.1', 'http://doc.php.net/rest/'); + $doc_channel->setBaseURL('REST1.3', 'http://doc.php.net/rest/'); + return $doc_channel; + } - function _UrlOrChannelGroup($type, $name, $group) - { - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, - 'name' => $name, 'group' => $group), - 'Group "%group%" dependency <%type%> "%name%" can have either url OR ' . - 'channel attributes, and not both'); - } - function _NoChannelGroup($type, $name, $group) - { - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, - 'name' => $name, 'group' => $group), - 'Group "%group%" dependency <%type%> "%name%" must have either url OR ' . - 'channel attributes'); - } + if ($this->_getChannelFromAlias($channel) == '__uri') { + // the registry is not properly set up, so use defaults + if (!class_exists('PEAR_ChannelFile')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/ChannelFile.php'; + } - function _unknownChannel($channel) - { - $this->_stack->push(__FUNCTION__, 'error', array('channel' => $channel), - 'Unknown channel "%channel%"'); - } + $private = new PEAR_ChannelFile; + $private->setName('__uri'); + $private->setDefaultPEARProtocols(); + $private->setBaseURL('REST1.0', '****'); + $private->setSummary('Pseudo-channel for static packages'); + return $private; + } - function _noPackageVersion() - { - $this->_stack->push(__FUNCTION__, 'error', array(), - 'package.xml tag has no version attribute, or version is not 2.0'); + return $ch; } - function _NoBundledPackages() + /** + * @param string Package name + * @param string Channel name + * @return bool + */ + function packageExists($package, $channel = 'pear.php.net') { - $this->_stack->push(__FUNCTION__, 'error', array(), - 'No tag was found in , required for bundle packages'); + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_packageExists($package, $channel); + $this->_unlock(); + return $ret; } - function _AtLeast2BundledPackages() - { - $this->_stack->push(__FUNCTION__, 'error', array(), - 'At least 2 packages must be bundled in a bundle package'); - } + // }}} - function _ChannelOrUri($name) - { - $this->_stack->push(__FUNCTION__, 'error', array('name' => $name), - 'Bundled package "%name%" can have either a uri or a channel, not both'); - } + // {{{ channelExists() - function _noChildTag($child, $tag) + /** + * @param string channel name + * @param bool if true, then aliases will be ignored + * @return bool + */ + function channelExists($channel, $noaliases = false) { - $this->_stack->push(__FUNCTION__, 'error', array('child' => $child, 'tag' => $tag), - 'Tag <%tag%> is missing child tag <%child%>'); + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_channelExists($channel, $noaliases); + $this->_unlock(); + return $ret; } - function _invalidVersion($type, $value) - { - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, 'value' => $value), - 'Version type <%type%> is not a valid version (%value%)'); - } + // }}} - function _invalidState($type, $value) + /** + * @param string channel name mirror is in + * @param string mirror name + * + * @return bool + */ + function mirrorExists($channel, $mirror) { - $states = array('stable', 'beta', 'alpha', 'devel'); - if ($type != 'api') { - $states[] = 'snapshot'; - } - if (strtolower($value) == 'rc') { - $this->_stack->push(__FUNCTION__, 'error', - array('version' => $this->_packageInfo['version']['release']), - 'RC is not a state, it is a version postfix, try %version%RC1, stability beta'); + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; } - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, 'value' => $value, - 'types' => $states), - 'Stability type <%type%> is not a valid stability (%value%), must be one of ' . - '%types%'); - } - function _invalidTask($task, $ret, $file) - { - switch ($ret[0]) { - case PEAR_TASK_ERROR_MISSING_ATTRIB : - $info = array('attrib' => $ret[1], 'task' => $task, 'file' => $file); - $msg = 'task <%task%> is missing attribute "%attrib%" in file %file%'; - break; - case PEAR_TASK_ERROR_NOATTRIBS : - $info = array('task' => $task, 'file' => $file); - $msg = 'task <%task%> has no attributes in file %file%'; - break; - case PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE : - $info = array('attrib' => $ret[1], 'values' => $ret[3], - 'was' => $ret[2], 'task' => $task, 'file' => $file); - $msg = 'task <%task%> attribute "%attrib%" has the wrong value "%was%" '. - 'in file %file%, expecting one of "%values%"'; - break; - case PEAR_TASK_ERROR_INVALID : - $info = array('reason' => $ret[1], 'task' => $task, 'file' => $file); - $msg = 'task <%task%> in file %file% is invalid because of "%reason%"'; - break; - } - $this->_stack->push(__FUNCTION__, 'error', $info, $msg); + $ret = $this->_mirrorExists($channel, $mirror); + $this->_unlock(); + return $ret; } - function _unknownTask($task, $file) - { - $this->_stack->push(__FUNCTION__, 'error', array('task' => $task, 'file' => $file), - 'Unknown task "%task%" passed in file '); - } + // {{{ isAlias() - function _subpackageCannotProvideExtension($name) + /** + * Determines whether the parameter is an alias of a channel + * @param string + * @return bool + */ + function isAlias($alias) { - $this->_stack->push(__FUNCTION__, 'error', array('name' => $name), - 'Subpackage dependency "%name%" cannot use , ' . - 'only package dependencies can use this tag'); + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_isChannelAlias($alias); + $this->_unlock(); + return $ret; } - function _subpackagesCannotConflict($name) - { - $this->_stack->push(__FUNCTION__, 'error', array('name' => $name), - 'Subpackage dependency "%name%" cannot use , ' . - 'only package dependencies can use this tag'); - } + // }}} + // {{{ packageInfo() - function _cannotProvideExtension($release) + /** + * @param string|null + * @param string|null + * @param string + * @return array|null + */ + function packageInfo($package = null, $key = null, $channel = 'pear.php.net') { - $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), - '<%release%> packages cannot use , only extbinrelease, extsrcrelease, zendextsrcrelease, and zendextbinrelease can provide a PHP extension'); + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_packageInfo($package, $key, $channel); + $this->_unlock(); + return $ret; } - function _mustProvideExtension($release) - { - $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), - '<%release%> packages must use to indicate which PHP extension is provided'); - } + // }}} + // {{{ channelInfo() - function _cannotHaveSrcpackage($release) + /** + * Retrieve a raw array of channel data. + * + * Do not use this, instead use {@link getChannel()} for normal + * operations. Array structure is undefined in this method + * @param string channel name + * @param bool whether to strictly retrieve information only on non-aliases + * @return array|null|PEAR_Error + */ + function channelInfo($channel = null, $noaliases = false) { - $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), - '<%release%> packages cannot specify a source code package, only extension binaries may use the tag'); + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_channelInfo($channel, $noaliases); + $this->_unlock(); + return $ret; } - function _mustSrcPackage($release) - { - $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), - '/ packages must specify a source code package with '); - } + // }}} - function _mustSrcuri($release) + /** + * @param string + */ + function channelName($channel) { - $this->_stack->push(__FUNCTION__, 'error', array('release' => $release), - '/ packages must specify a source code package with '); + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_getChannelFromAlias($channel); + $this->_unlock(); + return $ret; } - function _uriDepsCannotHaveVersioning($type) + /** + * @param string + */ + function channelAlias($channel) { - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type), - '%type%: dependencies with a tag cannot have any versioning information'); + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_getAlias($channel); + $this->_unlock(); + return $ret; } + // {{{ listPackages() - function _conflictingDepsCannotHaveVersioning($type) + function listPackages($channel = false) { - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type), - '%type%: conflicting dependencies cannot have versioning info, use to ' . - 'exclude specific versions of a dependency'); + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_listPackages($channel); + $this->_unlock(); + return $ret; } - function _DepchannelCannotBeUri($type) - { - $this->_stack->push(__FUNCTION__, 'error', array('type' => $type), - '%type%: channel cannot be __uri, this is a pseudo-channel reserved for uri ' . - 'dependencies only'); - } + // }}} + // {{{ listAllPackages() - function _bundledPackagesMustBeFilename() + function listAllPackages() { - $this->_stack->push(__FUNCTION__, 'error', array(), - ' tags must contain only the filename of a package release ' . - 'in the bundle'); + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_listAllPackages(); + $this->_unlock(); + return $ret; } - function _binaryPackageMustBePackagename() - { - $this->_stack->push(__FUNCTION__, 'error', array(), - ' tags must contain the name of a package that is ' . - 'a compiled version of this extsrc/zendextsrc package'); - } + // }}} + // {{{ listChannel() - function _fileNotFound($file) + function listChannels() { - $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), - 'File "%file%" in package.xml does not exist'); + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $ret = $this->_listChannels(); + $this->_unlock(); + return $ret; } - function _notInContents($file, $tag) - { - $this->_stack->push(__FUNCTION__, 'error', array('file' => $file, 'tag' => $tag), - '<%tag% name="%file%"> is invalid, file is not in '); - } + // }}} + // {{{ addPackage() - function _cannotValidateNoPathSet() + /** + * Add an installed package to the registry + * @param string|PEAR_PackageFile_v1|PEAR_PackageFile_v2 package name or object + * that will be passed to {@link addPackage2()} + * @param array package info (parsed by PEAR_Common::infoFrom*() methods) + * @return bool success of saving + */ + function addPackage($package, $info) { - $this->_stack->push(__FUNCTION__, 'error', array(), - 'Cannot validate files, no path to package file is set (use setPackageFile())'); + if (is_object($info)) { + return $this->addPackage2($info); + } + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; + } + $ret = $this->_addPackage($package, $info); + $this->_unlock(); + if ($ret) { + if (!class_exists('PEAR_PackageFile_v1')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/v1.php'; + } + $pf = new PEAR_PackageFile_v1; + $pf->setConfig($this->_config); + $pf->fromArray($info); + $this->_dependencyDB->uninstallPackage($pf); + $this->_dependencyDB->installPackage($pf); + } + return $ret; } - function _usesroletaskMustHaveChannelOrUri($role, $tag) - { - $this->_stack->push(__FUNCTION__, 'error', array('role' => $role, 'tag' => $tag), - '<%tag%> for role "%role%" must contain either , or and '); - } + // }}} + // {{{ addPackage2() - function _usesroletaskMustHavePackage($role, $tag) + function addPackage2($info) { - $this->_stack->push(__FUNCTION__, 'error', array('role' => $role, 'tag' => $tag), - '<%tag%> for role "%role%" must contain '); + if (!is_object($info)) { + return $this->addPackage($info['package'], $info); + } + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; + } + $ret = $this->_addPackage2($info); + $this->_unlock(); + if ($ret) { + $this->_dependencyDB->uninstallPackage($info); + $this->_dependencyDB->installPackage($info); + } + return $ret; } - function _usesroletaskMustHaveRoleTask($tag, $type) - { - $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag, 'type' => $type), - '<%tag%> must contain <%type%> defining the %type% to be used'); - } + // }}} + // {{{ updateChannel() - function _cannotConflictWithAllOs($type) + /** + * For future expandibility purposes, separate this + * @param PEAR_ChannelFile + */ + function updateChannel($channel, $lastmodified = null) { - $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag), - '%tag% cannot conflict with all OSes'); + if ($channel->getName() == '__uri') { + return false; + } + return $this->addChannel($channel, $lastmodified, true); } - function _invalidDepGroupName($name) - { - $this->_stack->push(__FUNCTION__, 'error', array('name' => $name), - 'Invalid dependency group name "%name%"'); - } + // }}} + // {{{ deleteChannel() - function _multipleToplevelDirNotAllowed() + /** + * Deletion fails if there are any packages installed from the channel + * @param string|PEAR_ChannelFile channel name + * @return boolean|PEAR_Error True on deletion, false if it doesn't exist + */ + function deleteChannel($channel) { - $this->_stack->push(__FUNCTION__, 'error', array(), - 'Multiple top-level tags are not allowed. Enclose them ' . - 'in a '); - } + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; + } - function _multipleInstallAs($file) - { - $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), - 'Only one tag is allowed for file "%file%"'); - } + $ret = $this->_deleteChannel($channel); + $this->_unlock(); + if ($ret && is_a($this->_config, 'PEAR_Config')) { + $this->_config->setChannels($this->listChannels()); + } - function _ignoreAndInstallAs($file) - { - $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), - 'Cannot have both and tags for file "%file%"'); + return $ret; } - function _analyzeBundledPackages() + // }}} + // {{{ addChannel() + + /** + * @param PEAR_ChannelFile Channel object + * @param string Last-Modified header from HTTP for caching + * @return boolean|PEAR_Error True on creation, false if it already exists + */ + function addChannel($channel, $lastmodified = false, $update = false) { - if (!$this->_isValid) { - return false; - } - if (!$this->_pf->getPackageType() == 'bundle') { - return false; - } - if (!isset($this->_pf->_packageFile)) { + if (!is_a($channel, 'PEAR_ChannelFile') || !$channel->validate()) { return false; } - $dir_prefix = dirname($this->_pf->_packageFile); - $common = new PEAR_Common; - $log = isset($this->_pf->_logger) ? array(&$this->_pf->_logger, 'log') : - array($common, 'log'); - $info = $this->_pf->getContents(); - $info = $info['bundledpackage']; - if (!is_array($info)) { - $info = array($info); + + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; } - $pkg = &new PEAR_PackageFile($this->_pf->_config); - foreach ($info as $package) { - if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $package)) { - $this->_fileNotFound($dir_prefix . DIRECTORY_SEPARATOR . $package); - $this->_isValid = 0; - continue; - } - call_user_func_array($log, array(1, "Analyzing bundled package $package")); - PEAR::pushErrorHandling(PEAR_ERROR_RETURN); - $ret = $pkg->fromAnyFile($dir_prefix . DIRECTORY_SEPARATOR . $package, - PEAR_VALIDATE_NORMAL); - PEAR::popErrorHandling(); - if (PEAR::isError($ret)) { - call_user_func_array($log, array(0, "ERROR: package $package is not a valid " . - 'package')); - $inf = $ret->getUserInfo(); - if (is_array($inf)) { - foreach ($inf as $err) { - call_user_func_array($log, array(1, $err['message'])); - } - } - return false; - } + + $ret = $this->_addChannel($channel, $update, $lastmodified); + $this->_unlock(); + if (!$update && $ret && is_a($this->_config, 'PEAR_Config')) { + $this->_config->setChannels($this->listChannels()); } - return true; + + return $ret; } - function _analyzePhpFiles() + // }}} + // {{{ deletePackage() + + function deletePackage($package, $channel = 'pear.php.net') { - if (!$this->_isValid) { - return false; - } - if (!isset($this->_pf->_packageFile)) { - $this->_cannotValidateNoPathSet(); - return false; - } - $dir_prefix = dirname($this->_pf->_packageFile); - $common = new PEAR_Common; - $log = isset($this->_pf->_logger) ? array(&$this->_pf->_logger, 'log') : - array(&$common, 'log'); - $info = $this->_pf->getContents(); - if (!$info || !isset($info['dir']['file'])) { - $this->_tagCannotBeEmpty('contents>_lock(LOCK_EX))) { + return $e; } - $info = $info['dir']['file']; - if (isset($info['attribs'])) { - $info = array($info); + + $file = $this->_packageFileName($package, $channel); + $ret = file_exists($file) ? @unlink($file) : false; + $this->_rebuildFileMap(); + $this->_unlock(); + $p = array('channel' => $channel, 'package' => $package); + $this->_dependencyDB->uninstallPackage($p); + return $ret; + } + + // }}} + // {{{ updatePackage() + + function updatePackage($package, $info, $merge = true) + { + if (is_object($info)) { + return $this->updatePackage2($info, $merge); } - $provides = array(); - foreach ($info as $fa) { - $fa = $fa['attribs']; - $file = $fa['name']; - if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $file)) { - $this->_fileNotFound($dir_prefix . DIRECTORY_SEPARATOR . $file); - $this->_isValid = 0; - continue; - } - if (in_array($fa['role'], PEAR_Installer_Role::getPhpRoles()) && $dir_prefix) { - call_user_func_array($log, array(1, "Analyzing $file")); - $srcinfo = $this->analyzeSourceCode($dir_prefix . DIRECTORY_SEPARATOR . $file); - if ($srcinfo) { - $provides = array_merge($provides, $this->_buildProvidesArray($srcinfo)); - } - } + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; } - $this->_packageName = $pn = $this->_pf->getPackage(); - $pnl = strlen($pn); - foreach ($provides as $key => $what) { - if (isset($what['explicit']) || !$what) { - // skip conformance checks if the provides entry is - // specified in the package.xml file - continue; - } - extract($what); - if ($type == 'class') { - if (!strncasecmp($name, $pn, $pnl)) { - continue; - } - $this->_stack->push(__FUNCTION__, 'warning', - array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn), - 'in %file%: %type% "%name%" not prefixed with package name "%package%"'); - } elseif ($type == 'function') { - if (strstr($name, '::') || !strncasecmp($name, $pn, $pnl)) { - continue; - } - $this->_stack->push(__FUNCTION__, 'warning', - array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn), - 'in %file%: %type% "%name%" not prefixed with package name "%package%"'); + $ret = $this->_updatePackage($package, $info, $merge); + $this->_unlock(); + if ($ret) { + if (!class_exists('PEAR_PackageFile_v1')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/v1.php'; } + $pf = new PEAR_PackageFile_v1; + $pf->setConfig($this->_config); + $pf->fromArray($this->packageInfo($package)); + $this->_dependencyDB->uninstallPackage($pf); + $this->_dependencyDB->installPackage($pf); } - return $this->_isValid; + return $ret; } - /** - * Analyze the source code of the given PHP file - * - * @param string Filename of the PHP file - * @param boolean whether to analyze $file as the file contents - * @return mixed - */ - function analyzeSourceCode($file, $string = false) + // }}} + // {{{ updatePackage2() + + function updatePackage2($info) { - if (!function_exists("token_get_all")) { - $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), - 'Parser error: token_get_all() function must exist to analyze source code, PHP may have been compiled with --disable-tokenizer'); + + if (!is_object($info)) { + return $this->updatePackage($info['package'], $info, $merge); + } + + if (!$info->validate(PEAR_VALIDATE_DOWNLOADING)) { return false; } - if (!defined('T_DOC_COMMENT')) { - define('T_DOC_COMMENT', T_COMMENT); + if (PEAR::isError($e = $this->_lock(LOCK_EX))) { + return $e; } - if (!defined('T_INTERFACE')) { - define('T_INTERFACE', -1); + $ret = $this->_updatePackage2($info); + $this->_unlock(); + if ($ret) { + $this->_dependencyDB->uninstallPackage($info); + $this->_dependencyDB->installPackage($info); } - if (!defined('T_IMPLEMENTS')) { - define('T_IMPLEMENTS', -1); + return $ret; + } + + // }}} + // {{{ getChannel() + /** + * @param string channel name + * @param bool whether to strictly return raw channels (no aliases) + * @return PEAR_ChannelFile|PEAR_Error + */ + function &getChannel($channel, $noaliases = false) + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; } + $ret = &$this->_getChannel($channel, $noaliases); + $this->_unlock(); + if (!$ret) { + return PEAR::raiseError('Unknown channel: ' . $channel); + } + return $ret; + } - if ($string) { - $contents = $file; - } else { - if (!$fp = @fopen($file, "r")) { - return false; - } - fclose($fp); - $contents = file_get_contents($file); + // }}} + // {{{ getPackage() + /** + * @param string package name + * @param string channel name + * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|null + */ + function &getPackage($package, $channel = 'pear.php.net') + { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; } + $pf = &$this->_getPackage($package, $channel); + $this->_unlock(); + return $pf; + } - // Silence this function so we can catch PHP Warnings and show our own custom message - $tokens = @token_get_all($contents); - if (isset($php_errormsg)) { - if (isset($this->_stack)) { - $pn = $this->_pf->getPackage(); - $this->_stack->push(__FUNCTION__, 'warning', - array('file' => $file, 'package' => $pn), - 'in %file%: Could not process file for unkown reasons,' . - ' possibly a PHP parse error in %file% from %package%'); + // }}} + + /** + * Get PEAR_PackageFile_v[1/2] objects representing the contents of + * a dependency group that are installed. + * + * This is used at uninstall-time + * @param array + * @return array|false + */ + function getInstalledGroup($group) + { + $ret = array(); + if (isset($group['package'])) { + if (!isset($group['package'][0])) { + $group['package'] = array($group['package']); } - } -/* - for ($i = 0; $i < sizeof($tokens); $i++) { - @list($token, $data) = $tokens[$i]; - if (is_string($token)) { - var_dump($token); - } else { - print token_name($token) . ' '; - var_dump(rtrim($data)); + foreach ($group['package'] as $package) { + $depchannel = isset($package['channel']) ? $package['channel'] : '__uri'; + $p = &$this->getPackage($package['name'], $depchannel); + if ($p) { + $save = &$p; + $ret[] = &$save; + } } } -*/ - $look_for = 0; - $paren_level = 0; - $bracket_level = 0; - $brace_level = 0; - $lastphpdoc = ''; - $current_class = ''; - $current_interface = ''; - $current_class_level = -1; - $current_function = ''; - $current_function_level = -1; - $declared_classes = array(); - $declared_interfaces = array(); - $declared_functions = array(); - $declared_methods = array(); - $used_classes = array(); - $used_functions = array(); - $extends = array(); - $implements = array(); - $nodeps = array(); - $inquote = false; - $interface = false; - for ($i = 0; $i < sizeof($tokens); $i++) { - if (is_array($tokens[$i])) { - list($token, $data) = $tokens[$i]; - } else { - $token = $tokens[$i]; - $data = ''; + if (isset($group['subpackage'])) { + if (!isset($group['subpackage'][0])) { + $group['subpackage'] = array($group['subpackage']); } - - if ($inquote) { - if ($token != '"' && $token != T_END_HEREDOC) { - continue; - } else { - $inquote = false; - continue; + foreach ($group['subpackage'] as $package) { + $depchannel = isset($package['channel']) ? $package['channel'] : '__uri'; + $p = &$this->getPackage($package['name'], $depchannel); + if ($p) { + $save = &$p; + $ret[] = &$save; } } + } + if (!count($ret)) { + return false; + } + return $ret; + } - switch ($token) { - case T_WHITESPACE : - continue; - case ';': - if ($interface) { - $current_function = ''; - $current_function_level = -1; - } - break; - case '"': - case T_START_HEREDOC: - $inquote = true; - break; - case T_CURLY_OPEN: - case T_DOLLAR_OPEN_CURLY_BRACES: - case '{': $brace_level++; continue 2; - case '}': - $brace_level--; - if ($current_class_level == $brace_level) { - $current_class = ''; - $current_class_level = -1; - } - if ($current_function_level == $brace_level) { - $current_function = ''; - $current_function_level = -1; - } - continue 2; - case '[': $bracket_level++; continue 2; - case ']': $bracket_level--; continue 2; - case '(': $paren_level++; continue 2; - case ')': $paren_level--; continue 2; - case T_INTERFACE: - $interface = true; - case T_CLASS: - if (($current_class_level != -1) || ($current_function_level != -1)) { - if (isset($this->_stack)) { - $this->_stack->push(__FUNCTION__, 'error', array('file' => $file), - 'Parser error: invalid PHP found in file "%file%"'); - } else { - PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"", - PEAR_COMMON_ERROR_INVALIDPHP); - } - - return false; - } - case T_FUNCTION: - case T_NEW: - case T_EXTENDS: - case T_IMPLEMENTS: - $look_for = $token; - continue 2; - case T_STRING: - if (version_compare(zend_version(), '2.0', '<')) { - if (in_array(strtolower($data), - array('public', 'private', 'protected', 'abstract', - 'interface', 'implements', 'throw') - ) - ) { - if (isset($this->_stack)) { - $this->_stack->push(__FUNCTION__, 'warning', array( - 'file' => $file), - 'Error, PHP5 token encountered in %file%,' . - ' analysis should be in PHP5'); - } else { - PEAR::raiseError('Error: PHP5 token encountered in ' . $file . - 'packaging should be done in PHP 5'); - return false; - } - } - } + // {{{ getChannelValidator() + /** + * @param string channel name + * @return PEAR_Validate|false + */ + function &getChannelValidator($channel) + { + $chan = $this->getChannel($channel); + if (PEAR::isError($chan)) { + return $chan; + } + $val = $chan->getValidationObject(); + return $val; + } + // }}} + // {{{ getChannels() + /** + * @param string channel name + * @return array an array of PEAR_ChannelFile objects representing every installed channel + */ + function &getChannels() + { + $ret = array(); + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + foreach ($this->_listChannels() as $channel) { + $e = &$this->_getChannel($channel); + if (!$e || PEAR::isError($e)) { + continue; + } + $ret[] = $e; + } + $this->_unlock(); + return $ret; + } - if ($look_for == T_CLASS) { - $current_class = $data; - $current_class_level = $brace_level; - $declared_classes[] = $current_class; - } elseif ($look_for == T_INTERFACE) { - $current_interface = $data; - $current_class_level = $brace_level; - $declared_interfaces[] = $current_interface; - } elseif ($look_for == T_IMPLEMENTS) { - $implements[$current_class] = $data; - } elseif ($look_for == T_EXTENDS) { - $extends[$current_class] = $data; - } elseif ($look_for == T_FUNCTION) { - if ($current_class) { - $current_function = "$current_class::$data"; - $declared_methods[$current_class][] = $data; - } elseif ($current_interface) { - $current_function = "$current_interface::$data"; - $declared_methods[$current_interface][] = $data; - } else { - $current_function = $data; - $declared_functions[] = $current_function; - } + // }}} + // {{{ checkFileMap() - $current_function_level = $brace_level; - $m = array(); - } elseif ($look_for == T_NEW) { - $used_classes[$data] = true; + /** + * Test whether a file or set of files belongs to a package. + * + * If an array is passed in + * @param string|array file path, absolute or relative to the pear + * install dir + * @param string|array name of PEAR package or array('package' => name, 'channel' => + * channel) of a package that will be ignored + * @param string API version - 1.1 will exclude any files belonging to a package + * @param array private recursion variable + * @return array|false which package and channel the file belongs to, or an empty + * string if the file does not belong to an installed package, + * or belongs to the second parameter's package + */ + function checkFileMap($path, $package = false, $api = '1.0', $attrs = false) + { + if (is_array($path)) { + static $notempty; + if (empty($notempty)) { + if (!class_exists('PEAR_Installer_Role')) { + require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Installer/Role.php'; + } + $notempty = create_function('$a','return !empty($a);'); + } + $package = is_array($package) ? array(strtolower($package[0]), strtolower($package[1])) + : strtolower($package); + $pkgs = array(); + foreach ($path as $name => $attrs) { + if (is_array($attrs)) { + if (isset($attrs['install-as'])) { + $name = $attrs['install-as']; } - - $look_for = 0; - continue 2; - case T_VARIABLE: - $look_for = 0; - continue 2; - case T_DOC_COMMENT: - case T_COMMENT: - if (preg_match('!^/\*\*\s!', $data)) { - $lastphpdoc = $data; - if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m)) { - $nodeps = array_merge($nodeps, $m[1]); - } + if (!in_array($attrs['role'], PEAR_Installer_Role::getInstallableRoles())) { + // these are not installed + continue; } - continue 2; - case T_DOUBLE_COLON: - if (!($tokens[$i - 1][0] == T_WHITESPACE || $tokens[$i - 1][0] == T_STRING)) { - if (isset($this->_stack)) { - $this->_stack->push(__FUNCTION__, 'warning', array('file' => $file), - 'Parser error: invalid PHP found in file "%file%"'); - } else { - PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"", - PEAR_COMMON_ERROR_INVALIDPHP); - } - - return false; + if (!in_array($attrs['role'], PEAR_Installer_Role::getBaseinstallRoles())) { + $attrs['baseinstalldir'] = is_array($package) ? $package[1] : $package; } - - $class = $tokens[$i - 1][1]; - if (strtolower($class) != 'parent') { - $used_classes[$class] = true; + if (isset($attrs['baseinstalldir'])) { + $name = $attrs['baseinstalldir'] . DIRECTORY_SEPARATOR . $name; } - - continue 2; + } + $pkgs[$name] = $this->checkFileMap($name, $package, $api, $attrs); + if (PEAR::isError($pkgs[$name])) { + return $pkgs[$name]; + } + } + return array_filter($pkgs, $notempty); + } + if (empty($this->filemap_cache)) { + if (PEAR::isError($e = $this->_lock(LOCK_SH))) { + return $e; + } + $err = $this->_readFileMap(); + $this->_unlock(); + if (PEAR::isError($err)) { + return $err; + } + } + if (!$attrs) { + $attrs = array('role' => 'php'); // any old call would be for PHP role only + } + if (isset($this->filemap_cache[$attrs['role']][$path])) { + if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path] == $package) { + return false; + } + return $this->filemap_cache[$attrs['role']][$path]; + } + $l = strlen($this->install_dir); + if (substr($path, 0, $l) == $this->install_dir) { + $path = preg_replace('!^'.DIRECTORY_SEPARATOR.'+!', '', substr($path, $l)); + } + if (isset($this->filemap_cache[$attrs['role']][$path])) { + if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path] == $package) { + return false; } + return $this->filemap_cache[$attrs['role']][$path]; } + return false; + } - return array( - "source_file" => $file, - "declared_classes" => $declared_classes, - "declared_interfaces" => $declared_interfaces, - "declared_methods" => $declared_methods, - "declared_functions" => $declared_functions, - "used_classes" => array_diff(array_keys($used_classes), $nodeps), - "inheritance" => $extends, - "implements" => $implements, - ); + // }}} + // {{{ flush() + /** + * Force a reload of the filemap + * @since 1.5.0RC3 + */ + function flushFileMap() + { + $this->filemap_cache = null; + clearstatcache(); // ensure that the next read gets the full, current filemap } + // }}} + // {{{ apiVersion() /** - * Build a "provides" array from data returned by - * analyzeSourceCode(). The format of the built array is like - * this: - * - * array( - * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'), - * ... - * ) - * - * - * @param array $srcinfo array with information about a source file - * as returned by the analyzeSourceCode() method. - * - * @return void - * - * @access private - * + * Get the expected API version. Channels API is version 1.1, as it is backwards + * compatible with 1.0 + * @return string */ - function _buildProvidesArray($srcinfo) + function apiVersion() { - if (!$this->_isValid) { - return array(); - } + return '1.1'; + } + // }}} - $providesret = array(); - $file = basename($srcinfo['source_file']); - $pn = isset($this->_pf) ? $this->_pf->getPackage() : ''; - $pnl = strlen($pn); - foreach ($srcinfo['declared_classes'] as $class) { - $key = "class;$class"; - if (isset($providesret[$key])) { - continue; + + /** + * Parse a package name, or validate a parsed package name array + * @param string|array pass in an array of format + * array( + * 'package' => 'pname', + * ['channel' => 'channame',] + * ['version' => 'version',] + * ['state' => 'state',] + * ['group' => 'groupname']) + * or a string of format + * [channel://][channame/]pname[-version|-state][/group=groupname] + * @return array|PEAR_Error + */ + function parsePackageName($param, $defaultchannel = 'pear.php.net') + { + $saveparam = $param; + if (is_array($param)) { + // convert to string for error messages + $saveparam = $this->parsedPackageNameToString($param); + // process the array + if (!isset($param['package'])) { + return PEAR::raiseError('parsePackageName(): array $param ' . + 'must contain a valid package name in index "param"', + 'package', null, null, $param); + } + if (!isset($param['uri'])) { + if (!isset($param['channel'])) { + $param['channel'] = $defaultchannel; + } + } else { + $param['channel'] = '__uri'; + } + } else { + $components = @parse_url((string) $param); + if (isset($components['scheme'])) { + if ($components['scheme'] == 'http') { + // uri package + $param = array('uri' => $param, 'channel' => '__uri'); + } elseif($components['scheme'] != 'channel') { + return PEAR::raiseError('parsePackageName(): only channel:// uris may ' . + 'be downloaded, not "' . $param . '"', 'invalid', null, null, $param); + } + } + if (!isset($components['path'])) { + return PEAR::raiseError('parsePackageName(): array $param ' . + 'must contain a valid package name in "' . $param . '"', + 'package', null, null, $param); + } + if (isset($components['host'])) { + // remove the leading "/" + $components['path'] = substr($components['path'], 1); + } + if (!isset($components['scheme'])) { + if (strpos($components['path'], '/') !== false) { + if ($components['path']{0} == '/') { + return PEAR::raiseError('parsePackageName(): this is not ' . + 'a package name, it begins with "/" in "' . $param . '"', + 'invalid', null, null, $param); + } + $parts = explode('/', $components['path']); + $components['host'] = array_shift($parts); + if (count($parts) > 1) { + $components['path'] = array_pop($parts); + $components['host'] .= '/' . implode('/', $parts); + } else { + $components['path'] = implode('/', $parts); + } + } else { + $components['host'] = $defaultchannel; + } + } else { + if (strpos($components['path'], '/')) { + $parts = explode('/', $components['path']); + $components['path'] = array_pop($parts); + $components['host'] .= '/' . implode('/', $parts); + } } - $providesret[$key] = - array('file'=> $file, 'type' => 'class', 'name' => $class); - if (isset($srcinfo['inheritance'][$class])) { - $providesret[$key]['extends'] = - $srcinfo['inheritance'][$class]; + if (is_array($param)) { + $param['package'] = $components['path']; + } else { + $param = array( + 'package' => $components['path'] + ); + if (isset($components['host'])) { + $param['channel'] = $components['host']; + } + } + if (isset($components['fragment'])) { + $param['group'] = $components['fragment']; + } + if (isset($components['user'])) { + $param['user'] = $components['user']; + } + if (isset($components['pass'])) { + $param['pass'] = $components['pass']; + } + if (isset($components['query'])) { + parse_str($components['query'], $param['opts']); + } + // check for extension + $pathinfo = pathinfo($param['package']); + if (isset($pathinfo['extension']) && + in_array(strtolower($pathinfo['extension']), array('tgz', 'tar'))) { + $param['extension'] = $pathinfo['extension']; + $param['package'] = substr($pathinfo['basename'], 0, + strlen($pathinfo['basename']) - 4); + } + // check for version + if (strpos($param['package'], '-')) { + $test = explode('-', $param['package']); + if (count($test) != 2) { + return PEAR::raiseError('parsePackageName(): only one version/state ' . + 'delimiter "-" is allowed in "' . $saveparam . '"', + 'version', null, null, $param); + } + list($param['package'], $param['version']) = $test; } } - - foreach ($srcinfo['declared_methods'] as $class => $methods) { - foreach ($methods as $method) { - $function = "$class::$method"; - $key = "function;$function"; - if ($method{0} == '_' || !strcasecmp($method, $class) || - isset($providesret[$key])) { - continue; + // validation + $info = $this->channelExists($param['channel']); + if (PEAR::isError($info)) { + return $info; + } + if (!$info) { + return PEAR::raiseError('unknown channel "' . $param['channel'] . + '" in "' . $saveparam . '"', 'channel', null, null, $param); + } + $chan = $this->getChannel($param['channel']); + if (PEAR::isError($chan)) { + return $chan; + } + if (!$chan) { + return PEAR::raiseError("Exception: corrupt registry, could not " . + "retrieve channel " . $param['channel'] . " information", + 'registry', null, null, $param); + } + $param['channel'] = $chan->getName(); + $validate = $chan->getValidationObject(); + $vpackage = $chan->getValidationPackage(); + // validate package name + if (!$validate->validPackageName($param['package'], $vpackage['_content'])) { + return PEAR::raiseError('parsePackageName(): invalid package name "' . + $param['package'] . '" in "' . $saveparam . '"', + 'package', null, null, $param); + } + if (isset($param['group'])) { + if (!PEAR_Validate::validGroupName($param['group'])) { + return PEAR::raiseError('parsePackageName(): dependency group "' . $param['group'] . + '" is not a valid group name in "' . $saveparam . '"', 'group', null, null, + $param); + } + } + if (isset($param['state'])) { + if (!in_array(strtolower($param['state']), $validate->getValidStates())) { + return PEAR::raiseError('parsePackageName(): state "' . $param['state'] + . '" is not a valid state in "' . $saveparam . '"', + 'state', null, null, $param); + } + } + if (isset($param['version'])) { + if (isset($param['state'])) { + return PEAR::raiseError('parsePackageName(): cannot contain both ' . + 'a version and a stability (state) in "' . $saveparam . '"', + 'version/state', null, null, $param); + } + // check whether version is actually a state + if (in_array(strtolower($param['version']), $validate->getValidStates())) { + $param['state'] = strtolower($param['version']); + unset($param['version']); + } else { + if (!$validate->validVersion($param['version'])) { + return PEAR::raiseError('parsePackageName(): "' . $param['version'] . + '" is neither a valid version nor a valid state in "' . + $saveparam . '"', 'version/state', null, null, $param); } - - $providesret[$key] = - array('file'=> $file, 'type' => 'function', 'name' => $function); } } + return $param; + } - foreach ($srcinfo['declared_functions'] as $function) { - $key = "function;$function"; - if ($function{0} == '_' || isset($providesret[$key])) { - continue; + /** + * @param array + * @return string + */ + function parsedPackageNameToString($parsed, $brief = false) + { + if (is_string($parsed)) { + return $parsed; + } + if (is_object($parsed)) { + $p = $parsed; + $parsed = array( + 'package' => $p->getPackage(), + 'channel' => $p->getChannel(), + 'version' => $p->getVersion(), + ); + } + if (isset($parsed['uri'])) { + return $parsed['uri']; + } + if ($brief) { + if ($channel = $this->channelAlias($parsed['channel'])) { + return $channel . '/' . $parsed['package']; } - - if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) { - $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\""; + } + $upass = ''; + if (isset($parsed['user'])) { + $upass = $parsed['user']; + if (isset($parsed['pass'])) { + $upass .= ':' . $parsed['pass']; } - - $providesret[$key] = - array('file'=> $file, 'type' => 'function', 'name' => $function); + $upass = "$upass@"; } - - return $providesret; + $ret = 'channel://' . $upass . $parsed['channel'] . '/' . $parsed['package']; + if (isset($parsed['version']) || isset($parsed['state'])) { + $ver = isset($parsed['version']) ? $parsed['version'] : ''; + $ver .= isset($parsed['state']) ? $parsed['state'] : ''; + $ret .= '-' . $ver; + } + if (isset($parsed['extension'])) { + $ret .= '.' . $parsed['extension']; + } + if (isset($parsed['opts'])) { + $ret .= '?'; + foreach ($parsed['opts'] as $name => $value) { + $parsed['opts'][$name] = "$name=$value"; + } + $ret .= implode('&', $parsed['opts']); + } + if (isset($parsed['group'])) { + $ret .= '#' . $parsed['group']; + } + return $ret; } -} - * @author Tomas V. V. Cox - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Registry.php,v 1.179 2009/04/10 19:42:18 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/** - * for PEAR_Error - */ -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR.php'; -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/DependencyDB.php'; - -define('PEAR_REGISTRY_ERROR_LOCK', -2); -define('PEAR_REGISTRY_ERROR_FORMAT', -3); -define('PEAR_REGISTRY_ERROR_FILE', -4); -define('PEAR_REGISTRY_ERROR_CONFLICT', -5); -define('PEAR_REGISTRY_ERROR_CHANNEL_FILE', -6); - -/** - * Administration class used to maintain the installed package database. - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Tomas V. V. Cox - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a1 - */ -class PEAR_Registry extends PEAR -{ - /** - * File containing all channel information. - * @var string - */ - var $channels = ''; - - /** Directory where registry files are stored. - * @var string - */ - var $statedir = ''; - - /** File where the file map is stored - * @var string - */ - var $filemap = ''; - - /** Directory where registry files for channels are stored. - * @var string - */ - var $channelsdir = ''; - - /** Name of file used for locking the registry - * @var string - */ - var $lockfile = ''; - - /** File descriptor used during locking - * @var resource - */ - var $lock_fp = null; - - /** Mode used during locking - * @var int - */ - var $lock_mode = 0; // XXX UNUSED - - /** Cache of package information. Structure: - * array( - * 'package' => array('id' => ... ), - * ... ) - * @var array - */ - var $pkginfo_cache = array(); - - /** Cache of file map. Structure: - * array( '/path/to/file' => 'package', ... ) - * @var array - */ - var $filemap_cache = array(); - - /** - * @var false|PEAR_ChannelFile - */ - var $_pearChannel; - - /** - * @var false|PEAR_ChannelFile - */ - var $_peclChannel; - - /** - * @var false|PEAR_ChannelFile - */ - var $_docChannel; - - /** - * @var PEAR_DependencyDB - */ - var $_dependencyDB; - - /** - * @var PEAR_Config - */ - var $_config; - - /** - * PEAR_Registry constructor. - * - * @param string (optional) PEAR install directory (for .php files) - * @param PEAR_ChannelFile PEAR_ChannelFile object representing the PEAR channel, if - * default values are not desired. Only used the very first time a PEAR - * repository is initialized - * @param PEAR_ChannelFile PEAR_ChannelFile object representing the PECL channel, if - * default values are not desired. Only used the very first time a PEAR - * repository is initialized - * - * @access public - */ - function PEAR_Registry($pear_install_dir = PEAR_INSTALL_DIR, $pear_channel = false, - $pecl_channel = false) - { - parent::PEAR(); - $this->setInstallDir($pear_install_dir); - $this->_pearChannel = $pear_channel; - $this->_peclChannel = $pecl_channel; - $this->_config = false; - } - - function setInstallDir($pear_install_dir = PEAR_INSTALL_DIR) - { - $ds = DIRECTORY_SEPARATOR; - $this->install_dir = $pear_install_dir; - $this->channelsdir = $pear_install_dir.$ds.'.channels'; - $this->statedir = $pear_install_dir.$ds.'.registry'; - $this->filemap = $pear_install_dir.$ds.'.filemap'; - $this->lockfile = $pear_install_dir.$ds.'.lock'; - } - - function hasWriteAccess() - { - if (!file_exists($this->install_dir)) { - $dir = $this->install_dir; - while ($dir && $dir != '.') { - $olddir = $dir; - $dir = dirname($dir); - if ($dir != '.' && file_exists($dir)) { - if (is_writeable($dir)) { - return true; - } - - return false; - } - - if ($dir == $olddir) { // this can happen in safe mode - return @is_writable($dir); - } - } - - return false; - } - - return is_writeable($this->install_dir); - } - - function setConfig(&$config, $resetInstallDir = true) - { - $this->_config = &$config; - if ($resetInstallDir) { - $this->setInstallDir($config->get('php_dir')); - } - } - - function _initializeChannelDirs() - { - static $running = false; - if (!$running) { - $running = true; - $ds = DIRECTORY_SEPARATOR; - if (!is_dir($this->channelsdir) || - !file_exists($this->channelsdir . $ds . 'pear.php.net.reg') || - !file_exists($this->channelsdir . $ds . 'pecl.php.net.reg') || - !file_exists($this->channelsdir . $ds . 'doc.php.net.reg') || - !file_exists($this->channelsdir . $ds . '__uri.reg')) { - if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) { - $pear_channel = $this->_pearChannel; - if (!is_a($pear_channel, 'PEAR_ChannelFile') || !$pear_channel->validate()) { - if (!class_exists('PEAR_ChannelFile')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/ChannelFile.php'; - } - - $pear_channel = new PEAR_ChannelFile; - $pear_channel->setName('pear.php.net'); - $pear_channel->setAlias('pear'); - $pear_channel->setServer('pear.php.net'); - $pear_channel->setSummary('PHP Extension and Application Repository'); - $pear_channel->setDefaultPEARProtocols(); - $pear_channel->setBaseURL('REST1.0', 'http://pear.php.net/rest/'); - $pear_channel->setBaseURL('REST1.1', 'http://pear.php.net/rest/'); - } else { - $pear_channel->setName('pear.php.net'); - $pear_channel->setAlias('pear'); - } - - $pear_channel->validate(); - $this->_addChannel($pear_channel); - } - - if (!file_exists($this->channelsdir . $ds . 'pecl.php.net.reg')) { - $pecl_channel = $this->_peclChannel; - if (!is_a($pecl_channel, 'PEAR_ChannelFile') || !$pecl_channel->validate()) { - if (!class_exists('PEAR_ChannelFile')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/ChannelFile.php'; - } - - $pecl_channel = new PEAR_ChannelFile; - $pecl_channel->setName('pecl.php.net'); - $pecl_channel->setAlias('pecl'); - $pecl_channel->setServer('pecl.php.net'); - $pecl_channel->setSummary('PHP Extension Community Library'); - $pecl_channel->setDefaultPEARProtocols(); - $pecl_channel->setBaseURL('REST1.0', 'http://pecl.php.net/rest/'); - $pecl_channel->setBaseURL('REST1.1', 'http://pecl.php.net/rest/'); - $pecl_channel->setValidationPackage('PEAR_Validator_PECL', '1.0'); - } else { - $pecl_channel->setName('pecl.php.net'); - $pecl_channel->setAlias('pecl'); - } - - $pecl_channel->validate(); - $this->_addChannel($pecl_channel); - } - - if (!file_exists($this->channelsdir . $ds . 'doc.php.net.reg')) { - $doc_channel = $this->_docChannel; - if (!is_a($doc_channel, 'PEAR_ChannelFile') || !$doc_channel->validate()) { - if (!class_exists('PEAR_ChannelFile')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/ChannelFile.php'; - } - - $doc_channel = new PEAR_ChannelFile; - $doc_channel->setName('doc.php.net'); - $doc_channel->setAlias('phpdocs'); - $doc_channel->setServer('doc.php.net'); - $doc_channel->setSummary('PHP Documentation Team'); - $doc_channel->setDefaultPEARProtocols(); - $doc_channel->setBaseURL('REST1.0', 'http://doc.php.net/Chiara_PEAR_Server_REST/'); - $doc_channel->setBaseURL('REST1.1', 'http://doc.php.net/Chiara_PEAR_Server_REST/'); - } else { - $doc_channel->setName('doc.php.net'); - $doc_channel->setAlias('doc'); - } - - $doc_channel->validate(); - $this->_addChannel($doc_channel); - } - - if (!file_exists($this->channelsdir . $ds . '__uri.reg')) { - if (!class_exists('PEAR_ChannelFile')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/ChannelFile.php'; - } - - $private = new PEAR_ChannelFile; - $private->setName('__uri'); - $private->setDefaultPEARProtocols(); - $private->setBaseURL('REST1.0', '****'); - $private->setSummary('Pseudo-channel for static packages'); - $this->_addChannel($private); - } - $this->_rebuildFileMap(); - } - - $running = false; - } - } - - function _initializeDirs() - { - $ds = DIRECTORY_SEPARATOR; - // XXX Compatibility code should be removed in the future - // rename all registry files if any to lowercase - if (!OS_WINDOWS && file_exists($this->statedir) && is_dir($this->statedir) && - $handle = opendir($this->statedir)) { - $dest = $this->statedir . $ds; - while (false !== ($file = readdir($handle))) { - if (preg_match('/^.*[A-Z].*\.reg\\z/', $file)) { - rename($dest . $file, $dest . strtolower($file)); - } - } - closedir($handle); - } - - $this->_initializeChannelDirs(); - if (!file_exists($this->filemap)) { - $this->_rebuildFileMap(); - } - $this->_initializeDepDB(); - } - - function _initializeDepDB() - { - if (!isset($this->_dependencyDB)) { - static $initializing = false; - if (!$initializing) { - $initializing = true; - if (!$this->_config) { // never used? - $file = OS_WINDOWS ? 'pear.ini' : '.pearrc'; - $this->_config = &new PEAR_Config($this->statedir . DIRECTORY_SEPARATOR . - $file); - $this->_config->setRegistry($this); - $this->_config->set('php_dir', $this->install_dir); - } - - $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->_config); - if (PEAR::isError($this->_dependencyDB)) { - // attempt to recover by removing the dep db - if (file_exists($this->_config->get('php_dir', null, 'pear.php.net') . - DIRECTORY_SEPARATOR . '.depdb')) { - @unlink($this->_config->get('php_dir', null, 'pear.php.net') . - DIRECTORY_SEPARATOR . '.depdb'); - } - - $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->_config); - if (PEAR::isError($this->_dependencyDB)) { - echo $this->_dependencyDB->getMessage(); - echo 'Unrecoverable error'; - exit(1); - } - } - - $initializing = false; - } - } - } - - /** - * PEAR_Registry destructor. Makes sure no locks are forgotten. - * - * @access private - */ - function _PEAR_Registry() - { - parent::_PEAR(); - if (is_resource($this->lock_fp)) { - $this->_unlock(); - } - } - - /** - * Make sure the directory where we keep registry files exists. - * - * @return bool TRUE if directory exists, FALSE if it could not be - * created - * - * @access private - */ - function _assertStateDir($channel = false) - { - if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') { - return $this->_assertChannelStateDir($channel); - } - - static $init = false; - if (!file_exists($this->statedir)) { - if (!$this->hasWriteAccess()) { - return false; - } - - require_once 'phar://install-pear-nozlib.phar/' . 'System.php'; - if (!System::mkdir(array('-p', $this->statedir))) { - return $this->raiseError("could not create directory '{$this->statedir}'"); - } - $init = true; - } elseif (!is_dir($this->statedir)) { - return $this->raiseError('Cannot create directory ' . $this->statedir . ', ' . - 'it already exists and is not a directory'); - } - - $ds = DIRECTORY_SEPARATOR; - if (!file_exists($this->channelsdir)) { - if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg') || - !file_exists($this->channelsdir . $ds . 'pecl.php.net.reg') || - !file_exists($this->channelsdir . $ds . 'doc.php.net.reg') || - !file_exists($this->channelsdir . $ds . '__uri.reg')) { - $init = true; - } - } elseif (!is_dir($this->channelsdir)) { - return $this->raiseError('Cannot create directory ' . $this->channelsdir . ', ' . - 'it already exists and is not a directory'); - } - - if ($init) { - static $running = false; - if (!$running) { - $running = true; - $this->_initializeDirs(); - $running = false; - $init = false; - } - } else { - $this->_initializeDepDB(); - } - - return true; - } - - /** - * Make sure the directory where we keep registry files exists for a non-standard channel. - * - * @param string channel name - * @return bool TRUE if directory exists, FALSE if it could not be - * created - * - * @access private - */ - function _assertChannelStateDir($channel) - { - $ds = DIRECTORY_SEPARATOR; - if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') { - if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) { - $this->_initializeChannelDirs(); - } - return $this->_assertStateDir($channel); - } - - $channelDir = $this->_channelDirectoryName($channel); - if (!is_dir($this->channelsdir) || - !file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) { - $this->_initializeChannelDirs(); - } - - if (!file_exists($channelDir)) { - if (!$this->hasWriteAccess()) { - return false; - } - - require_once 'phar://install-pear-nozlib.phar/' . 'System.php'; - if (!System::mkdir(array('-p', $channelDir))) { - return $this->raiseError("could not create directory '" . $channelDir . - "'"); - } - } elseif (!is_dir($channelDir)) { - return $this->raiseError("could not create directory '" . $channelDir . - "', already exists and is not a directory"); - } - - return true; - } - - /** - * Make sure the directory where we keep registry files for channels exists - * - * @return bool TRUE if directory exists, FALSE if it could not be - * created - * - * @access private - */ - function _assertChannelDir() - { - if (!file_exists($this->channelsdir)) { - if (!$this->hasWriteAccess()) { - return false; - } - - require_once 'phar://install-pear-nozlib.phar/' . 'System.php'; - if (!System::mkdir(array('-p', $this->channelsdir))) { - return $this->raiseError("could not create directory '{$this->channelsdir}'"); - } - } elseif (!is_dir($this->channelsdir)) { - return $this->raiseError("could not create directory '{$this->channelsdir}" . - "', it already exists and is not a directory"); - } - - if (!file_exists($this->channelsdir . DIRECTORY_SEPARATOR . '.alias')) { - if (!$this->hasWriteAccess()) { - return false; - } - - require_once 'phar://install-pear-nozlib.phar/' . 'System.php'; - if (!System::mkdir(array('-p', $this->channelsdir . DIRECTORY_SEPARATOR . '.alias'))) { - return $this->raiseError("could not create directory '{$this->channelsdir}/.alias'"); - } - } elseif (!is_dir($this->channelsdir . DIRECTORY_SEPARATOR . '.alias')) { - return $this->raiseError("could not create directory '{$this->channelsdir}" . - "/.alias', it already exists and is not a directory"); - } - - return true; - } - - /** - * Get the name of the file where data for a given package is stored. - * - * @param string channel name, or false if this is a PEAR package - * @param string package name - * - * @return string registry file name - * - * @access public - */ - function _packageFileName($package, $channel = false) - { - if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') { - return $this->_channelDirectoryName($channel) . DIRECTORY_SEPARATOR . - strtolower($package) . '.reg'; - } - - return $this->statedir . DIRECTORY_SEPARATOR . strtolower($package) . '.reg'; - } - - /** - * Get the name of the file where data for a given channel is stored. - * @param string channel name - * @return string registry file name - */ - function _channelFileName($channel, $noaliases = false) - { - if (!$noaliases) { - if (file_exists($this->_getChannelAliasFileName($channel))) { - $channel = implode('', file($this->_getChannelAliasFileName($channel))); - } - } - return $this->channelsdir . DIRECTORY_SEPARATOR . str_replace('/', '_', - strtolower($channel)) . '.reg'; - } - - /** - * @param string - * @return string - */ - function _getChannelAliasFileName($alias) - { - return $this->channelsdir . DIRECTORY_SEPARATOR . '.alias' . - DIRECTORY_SEPARATOR . str_replace('/', '_', strtolower($alias)) . '.txt'; - } - - /** - * Get the name of a channel from its alias - */ - function _getChannelFromAlias($channel) - { - if (!$this->_channelExists($channel)) { - if ($channel == 'pear.php.net') { - return 'pear.php.net'; - } - - if ($channel == 'pecl.php.net') { - return 'pecl.php.net'; - } - - if ($channel == 'doc.php.net') { - return 'doc.php.net'; - } - - if ($channel == '__uri') { - return '__uri'; - } - - return false; - } - - $channel = strtolower($channel); - if (file_exists($this->_getChannelAliasFileName($channel))) { - // translate an alias to an actual channel - return implode('', file($this->_getChannelAliasFileName($channel))); - } - - return $channel; - } - - /** - * Get the alias of a channel from its alias or its name - */ - function _getAlias($channel) - { - if (!$this->_channelExists($channel)) { - if ($channel == 'pear.php.net') { - return 'pear'; - } - - if ($channel == 'pecl.php.net') { - return 'pecl'; - } - - if ($channel == 'doc.php.net') { - return 'phpdocs'; - } - - return false; - } - - $channel = $this->_getChannel($channel); - if (PEAR::isError($channel)) { - return $channel; - } - - return $channel->getAlias(); - } - - /** - * Get the name of the file where data for a given package is stored. - * - * @param string channel name, or false if this is a PEAR package - * @param string package name - * - * @return string registry file name - * - * @access public - */ - function _channelDirectoryName($channel) - { - if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') { - return $this->statedir; - } - - $ch = $this->_getChannelFromAlias($channel); - if (!$ch) { - $ch = $channel; - } - - return $this->statedir . DIRECTORY_SEPARATOR . strtolower('.channel.' . - str_replace('/', '_', $ch)); - } - - function _openPackageFile($package, $mode, $channel = false) - { - if (!$this->_assertStateDir($channel)) { - return null; - } - - if (!in_array($mode, array('r', 'rb')) && !$this->hasWriteAccess()) { - return null; - } - - $file = $this->_packageFileName($package, $channel); - if (!file_exists($file) && $mode == 'r' || $mode == 'rb') { - return null; - } - - $fp = @fopen($file, $mode); - if (!$fp) { - return null; - } - - return $fp; - } - - function _closePackageFile($fp) - { - fclose($fp); - } - - function _openChannelFile($channel, $mode) - { - if (!$this->_assertChannelDir()) { - return null; - } - - if (!in_array($mode, array('r', 'rb')) && !$this->hasWriteAccess()) { - return null; - } - - $file = $this->_channelFileName($channel); - if (!file_exists($file) && $mode == 'r' || $mode == 'rb') { - return null; - } - - $fp = @fopen($file, $mode); - if (!$fp) { - return null; - } - - return $fp; - } - - function _closeChannelFile($fp) - { - fclose($fp); - } - - function _rebuildFileMap() - { - if (!class_exists('PEAR_Installer_Role')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Installer/Role.php'; - } - - $channels = $this->_listAllPackages(); - $files = array(); - foreach ($channels as $channel => $packages) { - foreach ($packages as $package) { - $version = $this->_packageInfo($package, 'version', $channel); - $filelist = $this->_packageInfo($package, 'filelist', $channel); - if (!is_array($filelist)) { - continue; - } - - foreach ($filelist as $name => $attrs) { - if (isset($attrs['attribs'])) { - $attrs = $attrs['attribs']; - } - - // it is possible for conflicting packages in different channels to - // conflict with data files/doc files - if ($name == 'dirtree') { - continue; - } - - if (isset($attrs['role']) && !in_array($attrs['role'], - PEAR_Installer_Role::getInstallableRoles())) { - // these are not installed - continue; - } - - if (isset($attrs['role']) && !in_array($attrs['role'], - PEAR_Installer_Role::getBaseinstallRoles())) { - $attrs['baseinstalldir'] = $package; - } - - if (isset($attrs['baseinstalldir'])) { - $file = $attrs['baseinstalldir'].DIRECTORY_SEPARATOR.$name; - } else { - $file = $name; - } - - $file = preg_replace(',^/+,', '', $file); - if ($channel != 'pear.php.net') { - if (!isset($files[$attrs['role']])) { - $files[$attrs['role']] = array(); - } - $files[$attrs['role']][$file] = array(strtolower($channel), - strtolower($package)); - } else { - if (!isset($files[$attrs['role']])) { - $files[$attrs['role']] = array(); - } - $files[$attrs['role']][$file] = strtolower($package); - } - } - } - } - - - $this->_assertStateDir(); - if (!$this->hasWriteAccess()) { - return false; - } - - $fp = @fopen($this->filemap, 'wb'); - if (!$fp) { - return false; - } - - $this->filemap_cache = $files; - fwrite($fp, serialize($files)); - fclose($fp); - return true; - } - - function _readFileMap() - { - if (!file_exists($this->filemap)) { - return array(); - } - - $fp = @fopen($this->filemap, 'r'); - if (!$fp) { - return $this->raiseError('PEAR_Registry: could not open filemap "' . $this->filemap . '"', PEAR_REGISTRY_ERROR_FILE, null, null, $php_errormsg); - } - - clearstatcache(); - $rt = get_magic_quotes_runtime(); - set_magic_quotes_runtime(0); - $fsize = filesize($this->filemap); - fclose($fp); - $data = file_get_contents($this->filemap); - set_magic_quotes_runtime($rt); - $tmp = unserialize($data); - if (!$tmp && $fsize > 7) { - return $this->raiseError('PEAR_Registry: invalid filemap data', PEAR_REGISTRY_ERROR_FORMAT, null, null, $data); - } - - $this->filemap_cache = $tmp; - return true; - } - - /** - * Lock the registry. - * - * @param integer lock mode, one of LOCK_EX, LOCK_SH or LOCK_UN. - * See flock manual for more information. - * - * @return bool TRUE on success, FALSE if locking failed, or a - * PEAR error if some other error occurs (such as the - * lock file not being writable). - * - * @access private - */ - function _lock($mode = LOCK_EX) - { - if (stristr(php_uname(), 'Windows 9')) { - return true; - } - - if ($mode != LOCK_UN && is_resource($this->lock_fp)) { - // XXX does not check type of lock (LOCK_SH/LOCK_EX) - return true; - } - - if (!$this->_assertStateDir()) { - if ($mode == LOCK_EX) { - return $this->raiseError('Registry directory is not writeable by the current user'); - } - - return true; - } - - $open_mode = 'w'; - // XXX People reported problems with LOCK_SH and 'w' - if ($mode === LOCK_SH || $mode === LOCK_UN) { - if (!file_exists($this->lockfile)) { - touch($this->lockfile); - } - $open_mode = 'r'; - } - - if (!is_resource($this->lock_fp)) { - $this->lock_fp = @fopen($this->lockfile, $open_mode); - } - - if (!is_resource($this->lock_fp)) { - $this->lock_fp = null; - return $this->raiseError("could not create lock file" . - (isset($php_errormsg) ? ": " . $php_errormsg : "")); - } - - if (!(int)flock($this->lock_fp, $mode)) { - switch ($mode) { - case LOCK_SH: $str = 'shared'; break; - case LOCK_EX: $str = 'exclusive'; break; - case LOCK_UN: $str = 'unlock'; break; - default: $str = 'unknown'; break; - } - - //is resource at this point, close it on error. - fclose($this->lock_fp); - $this->lock_fp = null; - return $this->raiseError("could not acquire $str lock ($this->lockfile)", - PEAR_REGISTRY_ERROR_LOCK); - } - - return true; - } - - function _unlock() - { - $ret = $this->_lock(LOCK_UN); - if (is_resource($this->lock_fp)) { - fclose($this->lock_fp); - } - - $this->lock_fp = null; - return $ret; - } - - function _packageExists($package, $channel = false) - { - return file_exists($this->_packageFileName($package, $channel)); - } - - /** - * Determine whether a channel exists in the registry - * @param string Channel name - * @param bool if true, then aliases will be ignored - * @return boolean - */ - function _channelExists($channel, $noaliases = false) - { - $a = file_exists($this->_channelFileName($channel, $noaliases)); - if (!$a && $channel == 'pear.php.net') { - return true; - } - - if (!$a && $channel == 'pecl.php.net') { - return true; - } - - if (!$a && $channel == 'doc.php.net') { - return true; - } - - return $a; - } - - /** - * @param PEAR_ChannelFile Channel object - * @param donotuse - * @param string Last-Modified HTTP tag from remote request - * @return boolean|PEAR_Error True on creation, false if it already exists - */ - function _addChannel($channel, $update = false, $lastmodified = false) - { - if (!is_a($channel, 'PEAR_ChannelFile')) { - return false; - } - - if (!$channel->validate()) { - return false; - } - - if (file_exists($this->_channelFileName($channel->getName()))) { - if (!$update) { - return false; - } - - $checker = $this->_getChannel($channel->getName()); - if (PEAR::isError($checker)) { - return $checker; - } - - if ($channel->getAlias() != $checker->getAlias()) { - if (file_exists($this->_getChannelAliasFileName($checker->getAlias()))) { - @unlink($this->_getChannelAliasFileName($checker->getAlias())); - } - } - } else { - if ($update && !in_array($channel->getName(), array('pear.php.net', 'pecl.php.net', 'doc.php.net'))) { - return false; - } - } - - $ret = $this->_assertChannelDir(); - if (PEAR::isError($ret)) { - return $ret; - } - - $ret = $this->_assertChannelStateDir($channel->getName()); - if (PEAR::isError($ret)) { - return $ret; - } - - if ($channel->getAlias() != $channel->getName()) { - if (file_exists($this->_getChannelAliasFileName($channel->getAlias())) && - $this->_getChannelFromAlias($channel->getAlias()) != $channel->getName()) { - $channel->setAlias($channel->getName()); - } - - if (!$this->hasWriteAccess()) { - return false; - } - - $fp = @fopen($this->_getChannelAliasFileName($channel->getAlias()), 'w'); - if (!$fp) { - return false; - } - - fwrite($fp, $channel->getName()); - fclose($fp); - } - - if (!$this->hasWriteAccess()) { - return false; - } - - $fp = @fopen($this->_channelFileName($channel->getName()), 'wb'); - if (!$fp) { - return false; - } - - $info = $channel->toArray(); - if ($lastmodified) { - $info['_lastmodified'] = $lastmodified; - } else { - $info['_lastmodified'] = date('r'); - } - - fwrite($fp, serialize($info)); - fclose($fp); - return true; - } - - /** - * Deletion fails if there are any packages installed from the channel - * @param string|PEAR_ChannelFile channel name - * @return boolean|PEAR_Error True on deletion, false if it doesn't exist - */ - function _deleteChannel($channel) - { - if (!is_string($channel)) { - if (!is_a($channel, 'PEAR_ChannelFile')) { - return false; - } - - if (!$channel->validate()) { - return false; - } - $channel = $channel->getName(); - } - - if ($this->_getChannelFromAlias($channel) == '__uri') { - return false; - } - - if ($this->_getChannelFromAlias($channel) == 'pecl.php.net') { - return false; - } - - if ($this->_getChannelFromAlias($channel) == 'doc.php.net') { - return false; - } - - if (!$this->_channelExists($channel)) { - return false; - } - - if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') { - return false; - } - - $channel = $this->_getChannelFromAlias($channel); - if ($channel == 'pear.php.net') { - return false; - } - - $test = $this->_listChannelPackages($channel); - if (count($test)) { - return false; - } - - $test = @rmdir($this->_channelDirectoryName($channel)); - if (!$test) { - return false; - } - - $file = $this->_getChannelAliasFileName($this->_getAlias($channel)); - if (file_exists($file)) { - $test = @unlink($file); - if (!$test) { - return false; - } - } - - $file = $this->_channelFileName($channel); - $ret = true; - if (file_exists($file)) { - $ret = @unlink($file); - } - - return $ret; - } - - /** - * Determine whether a channel exists in the registry - * @param string Channel Alias - * @return boolean - */ - function _isChannelAlias($alias) - { - return file_exists($this->_getChannelAliasFileName($alias)); - } - - /** - * @param string|null - * @param string|null - * @param string|null - * @return array|null - * @access private - */ - function _packageInfo($package = null, $key = null, $channel = 'pear.php.net') - { - if ($package === null) { - if ($channel === null) { - $channels = $this->_listChannels(); - $ret = array(); - foreach ($channels as $channel) { - $channel = strtolower($channel); - $ret[$channel] = array(); - $packages = $this->_listPackages($channel); - foreach ($packages as $package) { - $ret[$channel][] = $this->_packageInfo($package, null, $channel); - } - } - - return $ret; - } - - $ps = $this->_listPackages($channel); - if (!count($ps)) { - return array(); - } - return array_map(array(&$this, '_packageInfo'), - $ps, array_fill(0, count($ps), null), - array_fill(0, count($ps), $channel)); - } - - $fp = $this->_openPackageFile($package, 'r', $channel); - if ($fp === null) { - return null; - } - - $rt = get_magic_quotes_runtime(); - set_magic_quotes_runtime(0); - clearstatcache(); - $this->_closePackageFile($fp); - $data = file_get_contents($this->_packageFileName($package, $channel)); - set_magic_quotes_runtime($rt); - $data = unserialize($data); - if ($key === null) { - return $data; - } - - // compatibility for package.xml version 2.0 - if (isset($data['old'][$key])) { - return $data['old'][$key]; - } - - if (isset($data[$key])) { - return $data[$key]; - } - - return null; - } - - /** - * @param string Channel name - * @param bool whether to strictly retrieve info of channels, not just aliases - * @return array|null - */ - function _channelInfo($channel, $noaliases = false) - { - if (!$this->_channelExists($channel, $noaliases)) { - return null; - } - - $fp = $this->_openChannelFile($channel, 'r'); - if ($fp === null) { - return null; - } - - $rt = get_magic_quotes_runtime(); - set_magic_quotes_runtime(0); - clearstatcache(); - $this->_closeChannelFile($fp); - $data = file_get_contents($this->_channelFileName($channel)); - set_magic_quotes_runtime($rt); - $data = unserialize($data); - return $data; - } - - function _listChannels() - { - $channellist = array(); - if (!file_exists($this->channelsdir) || !is_dir($this->channelsdir)) { - return array('pear.php.net', 'pecl.php.net', 'doc.php.net', '__uri'); - } - - $dp = opendir($this->channelsdir); - while ($ent = readdir($dp)) { - if ($ent{0} == '.' || substr($ent, -4) != '.reg') { - continue; - } - - if ($ent == '__uri.reg') { - $channellist[] = '__uri'; - continue; - } - - $channellist[] = str_replace('_', '/', substr($ent, 0, -4)); - } - - closedir($dp); - if (!in_array('pear.php.net', $channellist)) { - $channellist[] = 'pear.php.net'; - } - - if (!in_array('pecl.php.net', $channellist)) { - $channellist[] = 'pecl.php.net'; - } - - if (!in_array('doc.php.net', $channellist)) { - $channellist[] = 'doc.php.net'; - } - - - if (!in_array('__uri', $channellist)) { - $channellist[] = '__uri'; - } - - natsort($channellist); - return $channellist; - } - - function _listPackages($channel = false) - { - if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') { - return $this->_listChannelPackages($channel); - } - - if (!file_exists($this->statedir) || !is_dir($this->statedir)) { - return array(); - } - - $pkglist = array(); - $dp = opendir($this->statedir); - if (!$dp) { - return $pkglist; - } - - while ($ent = readdir($dp)) { - if ($ent{0} == '.' || substr($ent, -4) != '.reg') { - continue; - } - - $pkglist[] = substr($ent, 0, -4); - } - closedir($dp); - return $pkglist; - } - - function _listChannelPackages($channel) - { - $pkglist = array(); - if (!file_exists($this->_channelDirectoryName($channel)) || - !is_dir($this->_channelDirectoryName($channel))) { - return array(); - } - - $dp = opendir($this->_channelDirectoryName($channel)); - if (!$dp) { - return $pkglist; - } - - while ($ent = readdir($dp)) { - if ($ent{0} == '.' || substr($ent, -4) != '.reg') { - continue; - } - $pkglist[] = substr($ent, 0, -4); - } - - closedir($dp); - return $pkglist; - } - - function _listAllPackages() - { - $ret = array(); - foreach ($this->_listChannels() as $channel) { - $ret[$channel] = $this->_listPackages($channel); - } - - return $ret; - } - - /** - * Add an installed package to the registry - * @param string package name - * @param array package info (parsed by PEAR_Common::infoFrom*() methods) - * @return bool success of saving - * @access private - */ - function _addPackage($package, $info) - { - if ($this->_packageExists($package)) { - return false; - } - - $fp = $this->_openPackageFile($package, 'wb'); - if ($fp === null) { - return false; - } - - $info['_lastmodified'] = time(); - fwrite($fp, serialize($info)); - $this->_closePackageFile($fp); - if (isset($info['filelist'])) { - $this->_rebuildFileMap(); - } - - return true; - } - - /** - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @return bool - * @access private - */ - function _addPackage2($info) - { - if (!is_a($info, 'PEAR_PackageFile_v1') && !is_a($info, 'PEAR_PackageFile_v2')) { - return false; - } - - if (!$info->validate()) { - if (class_exists('PEAR_Common')) { - $ui = PEAR_Frontend::singleton(); - if ($ui) { - foreach ($info->getValidationWarnings() as $err) { - $ui->log($err['message'], true); - } - } - } - return false; - } - - $channel = $info->getChannel(); - $package = $info->getPackage(); - $save = $info; - if ($this->_packageExists($package, $channel)) { - return false; - } - - if (!$this->_channelExists($channel, true)) { - return false; - } - - $info = $info->toArray(true); - if (!$info) { - return false; - } - - $fp = $this->_openPackageFile($package, 'wb', $channel); - if ($fp === null) { - return false; - } - - $info['_lastmodified'] = time(); - fwrite($fp, serialize($info)); - $this->_closePackageFile($fp); - $this->_rebuildFileMap(); - return true; - } - - /** - * @param string Package name - * @param array parsed package.xml 1.0 - * @param bool this parameter is only here for BC. Don't use it. - * @access private - */ - function _updatePackage($package, $info, $merge = true) - { - $oldinfo = $this->_packageInfo($package); - if (empty($oldinfo)) { - return false; - } - - $fp = $this->_openPackageFile($package, 'w'); - if ($fp === null) { - return false; - } - - if (is_object($info)) { - $info = $info->toArray(); - } - $info['_lastmodified'] = time(); - - $newinfo = $info; - if ($merge) { - $info = array_merge($oldinfo, $info); - } else { - $diff = $info; - } - - fwrite($fp, serialize($info)); - $this->_closePackageFile($fp); - if (isset($newinfo['filelist'])) { - $this->_rebuildFileMap(); - } - - return true; - } - - /** - * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 - * @return bool - * @access private - */ - function _updatePackage2($info) - { - if (!$this->_packageExists($info->getPackage(), $info->getChannel())) { - return false; - } - - $fp = $this->_openPackageFile($info->getPackage(), 'w', $info->getChannel()); - if ($fp === null) { - return false; - } - - $save = $info; - $info = $save->getArray(true); - $info['_lastmodified'] = time(); - fwrite($fp, serialize($info)); - $this->_closePackageFile($fp); - $this->_rebuildFileMap(); - return true; - } - - /** - * @param string Package name - * @param string Channel name - * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|null - * @access private - */ - function &_getPackage($package, $channel = 'pear.php.net') - { - $info = $this->_packageInfo($package, null, $channel); - if ($info === null) { - return $info; - } - - $a = $this->_config; - if (!$a) { - $this->_config = &new PEAR_Config; - $this->_config->set('php_dir', $this->statedir); - } - - if (!class_exists('PEAR_PackageFile')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile.php'; - } - - $pkg = &new PEAR_PackageFile($this->_config); - $pf = &$pkg->fromArray($info); - return $pf; - } - - /** - * @param string channel name - * @param bool whether to strictly retrieve channel names - * @return PEAR_ChannelFile|PEAR_Error - * @access private - */ - function &_getChannel($channel, $noaliases = false) - { - $ch = false; - if ($this->_channelExists($channel, $noaliases)) { - $chinfo = $this->_channelInfo($channel, $noaliases); - if ($chinfo) { - if (!class_exists('PEAR_ChannelFile')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/ChannelFile.php'; - } - - $ch = &PEAR_ChannelFile::fromArrayWithErrors($chinfo); - } - } - - if ($ch) { - if ($ch->validate()) { - return $ch; - } - - foreach ($ch->getErrors(true) as $err) { - $message = $err['message'] . "\n"; - } - - $ch = PEAR::raiseError($message); - return $ch; - } - - if ($this->_getChannelFromAlias($channel) == 'pear.php.net') { - // the registry is not properly set up, so use defaults - if (!class_exists('PEAR_ChannelFile')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/ChannelFile.php'; - } - - $pear_channel = new PEAR_ChannelFile; - $pear_channel->setName('pear.php.net'); - $pear_channel->setAlias('pear'); - $pear_channel->setSummary('PHP Extension and Application Repository'); - $pear_channel->setDefaultPEARProtocols(); - $pear_channel->setBaseURL('REST1.0', 'http://pear.php.net/rest/'); - $pear_channel->setBaseURL('REST1.1', 'http://pear.php.net/rest/'); - return $pear_channel; - } - - if ($this->_getChannelFromAlias($channel) == 'pecl.php.net') { - // the registry is not properly set up, so use defaults - if (!class_exists('PEAR_ChannelFile')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/ChannelFile.php'; - } - $pear_channel = new PEAR_ChannelFile; - $pear_channel->setName('pecl.php.net'); - $pear_channel->setAlias('pecl'); - $pear_channel->setSummary('PHP Extension Community Library'); - $pear_channel->setDefaultPEARProtocols(); - $pear_channel->setBaseURL('REST1.0', 'http://pecl.php.net/rest/'); - $pear_channel->setBaseURL('REST1.1', 'http://pecl.php.net/rest/'); - $pear_channel->setValidationPackage('PEAR_Validator_PECL', '1.0'); - return $pear_channel; - } - - if ($this->_getChannelFromAlias($channel) == 'doc.php.net') { - // the registry is not properly set up, so use defaults - if (!class_exists('PEAR_ChannelFile')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/ChannelFile.php'; - } - - $doc_channel = new PEAR_ChannelFile; - $doc_channel->setName('doc.php.net'); - $doc_channel->setAlias('phpdocs'); - $doc_channel->setSummary('PHP Documentation Team'); - $doc_channel->setDefaultPEARProtocols(); - $doc_channel->setBaseURL('REST1.0', 'http://doc.php.net/Chiara_PEAR_Server_REST/'); - $doc_channel->setBaseURL('REST1.1', 'http://doc.php.net/Chiara_PEAR_Server_REST/'); - return $doc_channel; - } - - - if ($this->_getChannelFromAlias($channel) == '__uri') { - // the registry is not properly set up, so use defaults - if (!class_exists('PEAR_ChannelFile')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/ChannelFile.php'; - } - - $private = new PEAR_ChannelFile; - $private->setName('__uri'); - $private->setDefaultPEARProtocols(); - $private->setBaseURL('REST1.0', '****'); - $private->setSummary('Pseudo-channel for static packages'); - return $private; - } - - return $ch; - } - - /** - * @param string Package name - * @param string Channel name - * @return bool - */ - function packageExists($package, $channel = 'pear.php.net') - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_packageExists($package, $channel); - $this->_unlock(); - return $ret; - } - - // }}} - - // {{{ channelExists() - - /** - * @param string channel name - * @param bool if true, then aliases will be ignored - * @return bool - */ - function channelExists($channel, $noaliases = false) - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_channelExists($channel, $noaliases); - $this->_unlock(); - return $ret; - } - - // }}} - - // {{{ isAlias() - - /** - * Determines whether the parameter is an alias of a channel - * @param string - * @return bool - */ - function isAlias($alias) - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_isChannelAlias($alias); - $this->_unlock(); - return $ret; - } - - // }}} - // {{{ packageInfo() - - /** - * @param string|null - * @param string|null - * @param string - * @return array|null - */ - function packageInfo($package = null, $key = null, $channel = 'pear.php.net') - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_packageInfo($package, $key, $channel); - $this->_unlock(); - return $ret; - } - - // }}} - // {{{ channelInfo() - - /** - * Retrieve a raw array of channel data. - * - * Do not use this, instead use {@link getChannel()} for normal - * operations. Array structure is undefined in this method - * @param string channel name - * @param bool whether to strictly retrieve information only on non-aliases - * @return array|null|PEAR_Error - */ - function channelInfo($channel = null, $noaliases = false) - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_channelInfo($channel, $noaliases); - $this->_unlock(); - return $ret; - } - - // }}} - - /** - * @param string - */ - function channelName($channel) - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_getChannelFromAlias($channel); - $this->_unlock(); - return $ret; - } - - /** - * @param string - */ - function channelAlias($channel) - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_getAlias($channel); - $this->_unlock(); - return $ret; - } - // {{{ listPackages() - - function listPackages($channel = false) - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_listPackages($channel); - $this->_unlock(); - return $ret; - } - - // }}} - // {{{ listAllPackages() - - function listAllPackages() - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_listAllPackages(); - $this->_unlock(); - return $ret; - } - - // }}} - // {{{ listChannel() - - function listChannels() - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = $this->_listChannels(); - $this->_unlock(); - return $ret; - } - - // }}} - // {{{ addPackage() - - /** - * Add an installed package to the registry - * @param string|PEAR_PackageFile_v1|PEAR_PackageFile_v2 package name or object - * that will be passed to {@link addPackage2()} - * @param array package info (parsed by PEAR_Common::infoFrom*() methods) - * @return bool success of saving - */ - function addPackage($package, $info) - { - if (is_object($info)) { - return $this->addPackage2($info); - } - if (PEAR::isError($e = $this->_lock(LOCK_EX))) { - return $e; - } - $ret = $this->_addPackage($package, $info); - $this->_unlock(); - if ($ret) { - if (!class_exists('PEAR_PackageFile_v1')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/v1.php'; - } - $pf = new PEAR_PackageFile_v1; - $pf->setConfig($this->_config); - $pf->fromArray($info); - $this->_dependencyDB->uninstallPackage($pf); - $this->_dependencyDB->installPackage($pf); - } - return $ret; - } - - // }}} - // {{{ addPackage2() - - function addPackage2($info) - { - if (!is_object($info)) { - return $this->addPackage($info['package'], $info); - } - if (PEAR::isError($e = $this->_lock(LOCK_EX))) { - return $e; - } - $ret = $this->_addPackage2($info); - $this->_unlock(); - if ($ret) { - $this->_dependencyDB->uninstallPackage($info); - $this->_dependencyDB->installPackage($info); - } - return $ret; - } - - // }}} - // {{{ updateChannel() - - /** - * For future expandibility purposes, separate this - * @param PEAR_ChannelFile - */ - function updateChannel($channel, $lastmodified = null) - { - if ($channel->getName() == '__uri') { - return false; - } - return $this->addChannel($channel, $lastmodified, true); - } - - // }}} - // {{{ deleteChannel() - - /** - * Deletion fails if there are any packages installed from the channel - * @param string|PEAR_ChannelFile channel name - * @return boolean|PEAR_Error True on deletion, false if it doesn't exist - */ - function deleteChannel($channel) - { - if (PEAR::isError($e = $this->_lock(LOCK_EX))) { - return $e; - } - $ret = $this->_deleteChannel($channel); - $this->_unlock(); - if ($ret && is_a($this->_config, 'PEAR_Config')) { - $this->_config->setChannels($this->listChannels()); - } - return $ret; - } - - // }}} - // {{{ addChannel() - - /** - * @param PEAR_ChannelFile Channel object - * @param string Last-Modified header from HTTP for caching - * @return boolean|PEAR_Error True on creation, false if it already exists - */ - function addChannel($channel, $lastmodified = false, $update = false) - { - if (!is_a($channel, 'PEAR_ChannelFile')) { - return false; - } - if (!$channel->validate()) { - return false; - } - if (PEAR::isError($e = $this->_lock(LOCK_EX))) { - return $e; - } - $ret = $this->_addChannel($channel, $update, $lastmodified); - $this->_unlock(); - if (!$update && $ret && is_a($this->_config, 'PEAR_Config')) { - $this->_config->setChannels($this->listChannels()); - } - return $ret; - } - - // }}} - // {{{ deletePackage() - - function deletePackage($package, $channel = 'pear.php.net') - { - if (PEAR::isError($e = $this->_lock(LOCK_EX))) { - return $e; - } - $file = $this->_packageFileName($package, $channel); - if (file_exists($file)) { - $ret = @unlink($file); - } else { - $ret = false; - } - $this->_rebuildFileMap(); - $this->_unlock(); - $p = array('channel' => $channel, 'package' => $package); - $this->_dependencyDB->uninstallPackage($p); - return $ret; - } - - // }}} - // {{{ updatePackage() - - function updatePackage($package, $info, $merge = true) - { - if (is_object($info)) { - return $this->updatePackage2($info, $merge); - } - if (PEAR::isError($e = $this->_lock(LOCK_EX))) { - return $e; - } - $ret = $this->_updatePackage($package, $info, $merge); - $this->_unlock(); - if ($ret) { - if (!class_exists('PEAR_PackageFile_v1')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/PackageFile/v1.php'; - } - $pf = new PEAR_PackageFile_v1; - $pf->setConfig($this->_config); - $pf->fromArray($this->packageInfo($package)); - $this->_dependencyDB->uninstallPackage($pf); - $this->_dependencyDB->installPackage($pf); - } - return $ret; - } - - // }}} - // {{{ updatePackage2() - - function updatePackage2($info) - { - - if (!is_object($info)) { - return $this->updatePackage($info['package'], $info, $merge); - } - - if (!$info->validate(PEAR_VALIDATE_DOWNLOADING)) { - return false; - } - - if (PEAR::isError($e = $this->_lock(LOCK_EX))) { - return $e; - } - - $ret = $this->_updatePackage2($info); - $this->_unlock(); - if ($ret) { - $this->_dependencyDB->uninstallPackage($info); - $this->_dependencyDB->installPackage($info); - } - - return $ret; - } - - // }}} - // {{{ getChannel() - /** - * @param string channel name - * @param bool whether to strictly return raw channels (no aliases) - * @return PEAR_ChannelFile|PEAR_Error - */ - function &getChannel($channel, $noaliases = false) - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $ret = &$this->_getChannel($channel, $noaliases); - $this->_unlock(); - if (!$ret) { - return PEAR::raiseError('Unknown channel: ' . $channel); - } - return $ret; - } - - // }}} - // {{{ getPackage() - /** - * @param string package name - * @param string channel name - * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|null - */ - function &getPackage($package, $channel = 'pear.php.net') - { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $pf = &$this->_getPackage($package, $channel); - $this->_unlock(); - return $pf; - } - - // }}} - - /** - * Get PEAR_PackageFile_v[1/2] objects representing the contents of - * a dependency group that are installed. - * - * This is used at uninstall-time - * @param array - * @return array|false - */ - function getInstalledGroup($group) - { - $ret = array(); - if (isset($group['package'])) { - if (!isset($group['package'][0])) { - $group['package'] = array($group['package']); - } - foreach ($group['package'] as $package) { - $depchannel = isset($package['channel']) ? $package['channel'] : '__uri'; - $p = &$this->getPackage($package['name'], $depchannel); - if ($p) { - $save = &$p; - $ret[] = &$save; - } - } - } - if (isset($group['subpackage'])) { - if (!isset($group['subpackage'][0])) { - $group['subpackage'] = array($group['subpackage']); - } - foreach ($group['subpackage'] as $package) { - $depchannel = isset($package['channel']) ? $package['channel'] : '__uri'; - $p = &$this->getPackage($package['name'], $depchannel); - if ($p) { - $save = &$p; - $ret[] = &$save; - } - } - } - if (!count($ret)) { - return false; - } - return $ret; - } - - // {{{ getChannelValidator() - /** - * @param string channel name - * @return PEAR_Validate|false - */ - function &getChannelValidator($channel) - { - $chan = $this->getChannel($channel); - if (PEAR::isError($chan)) { - return $chan; - } - $val = $chan->getValidationObject(); - return $val; - } - // }}} - // {{{ getChannels() - /** - * @param string channel name - * @return array an array of PEAR_ChannelFile objects representing every installed channel - */ - function &getChannels() - { - $ret = array(); - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - foreach ($this->_listChannels() as $channel) { - $e = &$this->_getChannel($channel); - if (!$e || PEAR::isError($e)) { - continue; - } - $ret[] = $e; - } - $this->_unlock(); - return $ret; - } - - // }}} - // {{{ checkFileMap() - - /** - * Test whether a file or set of files belongs to a package. - * - * If an array is passed in - * @param string|array file path, absolute or relative to the pear - * install dir - * @param string|array name of PEAR package or array('package' => name, 'channel' => - * channel) of a package that will be ignored - * @param string API version - 1.1 will exclude any files belonging to a package - * @param array private recursion variable - * @return array|false which package and channel the file belongs to, or an empty - * string if the file does not belong to an installed package, - * or belongs to the second parameter's package - */ - function checkFileMap($path, $package = false, $api = '1.0', $attrs = false) - { - if (is_array($path)) { - static $notempty; - if (empty($notempty)) { - if (!class_exists('PEAR_Installer_Role')) { - require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Installer/Role.php'; - } - $notempty = create_function('$a','return !empty($a);'); - } - $package = is_array($package) ? array(strtolower($package[0]), strtolower($package[1])) - : strtolower($package); - $pkgs = array(); - foreach ($path as $name => $attrs) { - if (is_array($attrs)) { - if (isset($attrs['install-as'])) { - $name = $attrs['install-as']; - } - if (!in_array($attrs['role'], PEAR_Installer_Role::getInstallableRoles())) { - // these are not installed - continue; - } - if (!in_array($attrs['role'], PEAR_Installer_Role::getBaseinstallRoles())) { - $attrs['baseinstalldir'] = is_array($package) ? $package[1] : $package; - } - if (isset($attrs['baseinstalldir'])) { - $name = $attrs['baseinstalldir'] . DIRECTORY_SEPARATOR . $name; - } - } - $pkgs[$name] = $this->checkFileMap($name, $package, $api, $attrs); - if (PEAR::isError($pkgs[$name])) { - return $pkgs[$name]; - } - } - return array_filter($pkgs, $notempty); - } - if (empty($this->filemap_cache)) { - if (PEAR::isError($e = $this->_lock(LOCK_SH))) { - return $e; - } - $err = $this->_readFileMap(); - $this->_unlock(); - if (PEAR::isError($err)) { - return $err; - } - } - if (!$attrs) { - $attrs = array('role' => 'php'); // any old call would be for PHP role only - } - if (isset($this->filemap_cache[$attrs['role']][$path])) { - if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path] == $package) { - return false; - } - return $this->filemap_cache[$attrs['role']][$path]; - } - $l = strlen($this->install_dir); - if (substr($path, 0, $l) == $this->install_dir) { - $path = preg_replace('!^'.DIRECTORY_SEPARATOR.'+!', '', substr($path, $l)); - } - if (isset($this->filemap_cache[$attrs['role']][$path])) { - if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path] == $package) { - return false; - } - return $this->filemap_cache[$attrs['role']][$path]; - } - return false; - } - - // }}} - // {{{ flush() - /** - * Force a reload of the filemap - * @since 1.5.0RC3 - */ - function flushFileMap() - { - $this->filemap_cache = null; - clearstatcache(); // ensure that the next read gets the full, current filemap - } - - // }}} - // {{{ apiVersion() - /** - * Get the expected API version. Channels API is version 1.1, as it is backwards - * compatible with 1.0 - * @return string - */ - function apiVersion() - { - return '1.1'; - } - // }}} - - - /** - * Parse a package name, or validate a parsed package name array - * @param string|array pass in an array of format - * array( - * 'package' => 'pname', - * ['channel' => 'channame',] - * ['version' => 'version',] - * ['state' => 'state',] - * ['group' => 'groupname']) - * or a string of format - * [channel://][channame/]pname[-version|-state][/group=groupname] - * @return array|PEAR_Error - */ - function parsePackageName($param, $defaultchannel = 'pear.php.net') - { - $saveparam = $param; - if (is_array($param)) { - // convert to string for error messages - $saveparam = $this->parsedPackageNameToString($param); - // process the array - if (!isset($param['package'])) { - return PEAR::raiseError('parsePackageName(): array $param ' . - 'must contain a valid package name in index "param"', - 'package', null, null, $param); - } - if (!isset($param['uri'])) { - if (!isset($param['channel'])) { - $param['channel'] = $defaultchannel; - } - } else { - $param['channel'] = '__uri'; - } - } else { - $components = @parse_url((string) $param); - if (isset($components['scheme'])) { - if ($components['scheme'] == 'http') { - // uri package - $param = array('uri' => $param, 'channel' => '__uri'); - } elseif($components['scheme'] != 'channel') { - return PEAR::raiseError('parsePackageName(): only channel:// uris may ' . - 'be downloaded, not "' . $param . '"', 'invalid', null, null, $param); - } - } - if (!isset($components['path'])) { - return PEAR::raiseError('parsePackageName(): array $param ' . - 'must contain a valid package name in "' . $param . '"', - 'package', null, null, $param); - } - if (isset($components['host'])) { - // remove the leading "/" - $components['path'] = substr($components['path'], 1); - } - if (!isset($components['scheme'])) { - if (strpos($components['path'], '/') !== false) { - if ($components['path']{0} == '/') { - return PEAR::raiseError('parsePackageName(): this is not ' . - 'a package name, it begins with "/" in "' . $param . '"', - 'invalid', null, null, $param); - } - $parts = explode('/', $components['path']); - $components['host'] = array_shift($parts); - if (count($parts) > 1) { - $components['path'] = array_pop($parts); - $components['host'] .= '/' . implode('/', $parts); - } else { - $components['path'] = implode('/', $parts); - } - } else { - $components['host'] = $defaultchannel; - } - } else { - if (strpos($components['path'], '/')) { - $parts = explode('/', $components['path']); - $components['path'] = array_pop($parts); - $components['host'] .= '/' . implode('/', $parts); - } - } - - if (is_array($param)) { - $param['package'] = $components['path']; - } else { - $param = array( - 'package' => $components['path'] - ); - if (isset($components['host'])) { - $param['channel'] = $components['host']; - } - } - if (isset($components['fragment'])) { - $param['group'] = $components['fragment']; - } - if (isset($components['user'])) { - $param['user'] = $components['user']; - } - if (isset($components['pass'])) { - $param['pass'] = $components['pass']; - } - if (isset($components['query'])) { - parse_str($components['query'], $param['opts']); - } - // check for extension - $pathinfo = pathinfo($param['package']); - if (isset($pathinfo['extension']) && - in_array(strtolower($pathinfo['extension']), array('tgz', 'tar'))) { - $param['extension'] = $pathinfo['extension']; - $param['package'] = substr($pathinfo['basename'], 0, - strlen($pathinfo['basename']) - 4); - } - // check for version - if (strpos($param['package'], '-')) { - $test = explode('-', $param['package']); - if (count($test) != 2) { - return PEAR::raiseError('parsePackageName(): only one version/state ' . - 'delimiter "-" is allowed in "' . $saveparam . '"', - 'version', null, null, $param); - } - list($param['package'], $param['version']) = $test; - } - } - // validation - $info = $this->channelExists($param['channel']); - if (PEAR::isError($info)) { - return $info; - } - if (!$info) { - return PEAR::raiseError('unknown channel "' . $param['channel'] . - '" in "' . $saveparam . '"', 'channel', null, null, $param); - } - $chan = $this->getChannel($param['channel']); - if (PEAR::isError($chan)) { - return $chan; - } - if (!$chan) { - return PEAR::raiseError("Exception: corrupt registry, could not " . - "retrieve channel " . $param['channel'] . " information", - 'registry', null, null, $param); - } - $param['channel'] = $chan->getName(); - $validate = $chan->getValidationObject(); - $vpackage = $chan->getValidationPackage(); - // validate package name - if (!$validate->validPackageName($param['package'], $vpackage['_content'])) { - return PEAR::raiseError('parsePackageName(): invalid package name "' . - $param['package'] . '" in "' . $saveparam . '"', - 'package', null, null, $param); - } - if (isset($param['group'])) { - if (!PEAR_Validate::validGroupName($param['group'])) { - return PEAR::raiseError('parsePackageName(): dependency group "' . $param['group'] . - '" is not a valid group name in "' . $saveparam . '"', 'group', null, null, - $param); - } - } - if (isset($param['state'])) { - if (!in_array(strtolower($param['state']), $validate->getValidStates())) { - return PEAR::raiseError('parsePackageName(): state "' . $param['state'] - . '" is not a valid state in "' . $saveparam . '"', - 'state', null, null, $param); - } - } - if (isset($param['version'])) { - if (isset($param['state'])) { - return PEAR::raiseError('parsePackageName(): cannot contain both ' . - 'a version and a stability (state) in "' . $saveparam . '"', - 'version/state', null, null, $param); - } - // check whether version is actually a state - if (in_array(strtolower($param['version']), $validate->getValidStates())) { - $param['state'] = strtolower($param['version']); - unset($param['version']); - } else { - if (!$validate->validVersion($param['version'])) { - return PEAR::raiseError('parsePackageName(): "' . $param['version'] . - '" is neither a valid version nor a valid state in "' . - $saveparam . '"', 'version/state', null, null, $param); - } - } - } - return $param; - } - - /** - * @param array - * @return string - */ - function parsedPackageNameToString($parsed, $brief = false) - { - if (is_string($parsed)) { - return $parsed; - } - if (is_object($parsed)) { - $p = $parsed; - $parsed = array( - 'package' => $p->getPackage(), - 'channel' => $p->getChannel(), - 'version' => $p->getVersion(), - ); - } - if (isset($parsed['uri'])) { - return $parsed['uri']; - } - if ($brief) { - if ($channel = $this->channelAlias($parsed['channel'])) { - return $channel . '/' . $parsed['package']; - } - } - $upass = ''; - if (isset($parsed['user'])) { - $upass = $parsed['user']; - if (isset($parsed['pass'])) { - $upass .= ':' . $parsed['pass']; - } - $upass = "$upass@"; - } - $ret = 'channel://' . $upass . $parsed['channel'] . '/' . $parsed['package']; - if (isset($parsed['version']) || isset($parsed['state'])) { - $ver = isset($parsed['version']) ? $parsed['version'] : ''; - $ver .= isset($parsed['state']) ? $parsed['state'] : ''; - $ret .= '-' . $ver; - } - if (isset($parsed['extension'])) { - $ret .= '.' . $parsed['extension']; - } - if (isset($parsed['opts'])) { - $ret .= '?'; - foreach ($parsed['opts'] as $name => $value) { - $parsed['opts'][$name] = "$name=$value"; - } - $ret .= implode('&', $parsed['opts']); - } - if (isset($parsed['group'])) { - $ret .= '#' . $parsed['group']; - } - return $ret; - } } * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: REST.php,v 1.40 2009/03/26 23:12:46 dufuz Exp $ + * @version CVS: $Id: REST.php 286489 2009-07-29 05:59:08Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since Release 1.4.0a1 */ @@ -83942,7 +84581,7 @@ * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 1.4.0a1 */ @@ -83953,7 +84592,7 @@ function PEAR_REST(&$config, $options = array()) { - $this->config = &$config; + $this->config = &$config; $this->_options = $options; } @@ -83970,7 +84609,6 @@ */ function retrieveCacheFirst($url, $accept = false, $forcestring = false, $channel = false) { - $cachefile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . md5($url) . 'rest.cachefile'; @@ -84127,11 +84765,9 @@ */ function saveCache($url, $contents, $lastmodified, $nochange = false, $cacheid = null) { - $cacheidfile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . - md5($url) . 'rest.cacheid'; - - $cachefile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . - md5($url) . 'rest.cachefile'; + $cachedir = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . md5($url); + $cacheidfile = $cachedir . 'rest.cacheid'; + $cachefile = $cachedir . 'rest.cachefile'; if ($cacheid === null && $nochange) { $cacheid = unserialize(implode('', file($cacheidfile))); @@ -84265,7 +84901,7 @@ } $request .= $ifmodifiedsince . - "User-Agent: PEAR/1.8.0/PHP/" . PHP_VERSION . "\r\n"; + "User-Agent: PEAR/1.9.0/PHP/" . PHP_VERSION . "\r\n"; $username = $this->config->get('username', null, $channel); $password = $this->config->get('password', null, $channel); @@ -84373,7 +85009,7 @@ * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: 10.php,v 1.60 2009/03/07 23:09:56 dufuz Exp $ + * @version CVS: $Id: 10.php 287558 2009-08-21 22:21:28Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since Release 1.4.0a12 */ @@ -84391,7 +85027,7 @@ * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 1.4.0a12 */ @@ -84425,16 +85061,18 @@ */ function getDownloadURL($base, $packageinfo, $prefstate, $installed, $channel = false) { - $channel = $packageinfo['channel']; - $package = $packageinfo['package']; $states = $this->betterStates($prefstate, true); if (!$states) { return PEAR::raiseError('"' . $prefstate . '" is not a valid state'); } - $state = isset($packageinfo['state']) ? $packageinfo['state'] : null; - $version = isset($packageinfo['version']) ? $packageinfo['version'] : null; - $info = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . '/allreleases.xml', false, false, $channel); + $channel = $packageinfo['channel']; + $package = $packageinfo['package']; + $state = isset($packageinfo['state']) ? $packageinfo['state'] : null; + $version = isset($packageinfo['version']) ? $packageinfo['version'] : null; + $restFile = $base . 'r/' . strtolower($package) . '/allreleases.xml'; + + $info = $this->_rest->retrieveData($restFile, false, false, $channel); if (PEAR::isError($info)) { return PEAR::raiseError('No releases available for package "' . $channel . '/' . $package . '"'); @@ -84486,22 +85124,27 @@ function getDepDownloadURL($base, $xsdversion, $dependency, $deppackage, $prefstate = 'stable', $installed = false, $channel = false) { - $channel = $dependency['channel']; - $package = $dependency['name']; $states = $this->betterStates($prefstate, true); if (!$states) { return PEAR::raiseError('"' . $prefstate . '" is not a valid state'); } - $state = isset($dependency['state']) ? $dependency['state'] : null; - $version = isset($dependency['version']) ? $dependency['version'] : null; - $info = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . '/allreleases.xml', false, false, $channel); + + $channel = $dependency['channel']; + $package = $dependency['name']; + $state = isset($dependency['state']) ? $dependency['state'] : null; + $version = isset($dependency['version']) ? $dependency['version'] : null; + $restFile = $base . 'r/' . strtolower($package) . '/allreleases.xml'; + + $info = $this->_rest->retrieveData($restFile, false, false, $channel); if (PEAR::isError($info)) { return PEAR::raiseError('Package "' . $deppackage['channel'] . '/' . $deppackage['package'] . '" dependency "' . $channel . '/' . $package . '" has no releases'); } + if (!is_array($info) || !isset($info['r'])) { return false; } + $exclude = array(); $min = $max = $recommended = false; if ($xsdversion == '1.0') { @@ -84619,19 +85262,23 @@ if (!$found) { $release = $info['r'][0]; } - $pinfo = $this->_rest->retrieveCacheFirst($base . 'p/' . strtolower($package) . '/' . + + $packageLower = strtolower($package); + $pinfo = $this->_rest->retrieveCacheFirst($base . 'p/' . $packageLower . '/' . 'info.xml', false, false, $channel); if (PEAR::isError($pinfo)) { return PEAR::raiseError('Package "' . $package . '" does not have REST info xml available'); } - $releaseinfo = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/' . + + $releaseinfo = $this->_rest->retrieveCacheFirst($base . 'r/' . $packageLower . '/' . $release['v'] . '.xml', false, false, $channel); if (PEAR::isError($releaseinfo)) { return PEAR::raiseError('Package "' . $package . '" Version "' . $release['v'] . '" does not have REST xml available'); } - $packagexml = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/' . + + $packagexml = $this->_rest->retrieveCacheFirst($base . 'r/' . $packageLower . '/' . 'deps.' . $release['v'] . '.txt', false, true, $channel); if (PEAR::isError($packagexml)) { return PEAR::raiseError('Package "' . $package . '" Version "' . $release['v'] . @@ -84642,39 +85289,49 @@ if (!$packagexml) { $packagexml = array(); } - $allinfo = $this->_rest->retrieveData($base . 'r/' . strtolower($package) . + + $allinfo = $this->_rest->retrieveData($base . 'r/' . $packageLower . '/allreleases.xml', false, false, $channel); if (!is_array($allinfo['r']) || !isset($allinfo['r'][0])) { $allinfo['r'] = array($allinfo['r']); } + $compatible = false; foreach ($allinfo['r'] as $release) { if ($release['v'] != $releaseinfo['v']) { continue; } + if (!isset($release['co'])) { break; } + $compatible = array(); if (!is_array($release['co']) || !isset($release['co'][0])) { $release['co'] = array($release['co']); } + foreach ($release['co'] as $entry) { $comp = array(); - $comp['name'] = $entry['p']; + $comp['name'] = $entry['p']; $comp['channel'] = $entry['c']; - $comp['min'] = $entry['min']; - $comp['max'] = $entry['max']; + $comp['min'] = $entry['min']; + $comp['max'] = $entry['max']; if (isset($entry['x']) && !is_array($entry['x'])) { $comp['exclude'] = $entry['x']; } + $compatible[] = $comp; } + if (count($compatible) == 1) { $compatible = $compatible[0]; } + break; } + + $deprecated = false; if (isset($pinfo['dc']) && isset($pinfo['dp'])) { if (is_array($pinfo['dp'])) { $deprecated = array('channel' => (string) $pinfo['dc'], @@ -84683,30 +85340,24 @@ $deprecated = array('channel' => (string) $pinfo['dc'], 'package' => trim($pinfo['dp'])); } - } else { - $deprecated = false; } + + $return = array( + 'version' => $releaseinfo['v'], + 'info' => $packagexml, + 'package' => $releaseinfo['p']['_content'], + 'stability' => $releaseinfo['st'], + 'compatible' => $compatible, + 'deprecated' => $deprecated, + ); + if ($found) { - return - array('version' => $releaseinfo['v'], - 'info' => $packagexml, - 'package' => $releaseinfo['p']['_content'], - 'stability' => $releaseinfo['st'], - 'url' => $releaseinfo['g'], - 'compatible' => $compatible, - 'deprecated' => $deprecated, - ); - } else { - return - array('version' => $releaseinfo['v'], - 'package' => $releaseinfo['p']['_content'], - 'stability' => $releaseinfo['st'], - 'info' => $packagexml, - 'compatible' => $compatible, - 'deprecated' => $deprecated, - 'php' => $phpversion - ); + $return['url'] = $releaseinfo['g']; + return $return; } + + $return['php'] = $phpversion; + return $return; } function listPackages($base, $channel = false) @@ -84715,12 +85366,15 @@ if (PEAR::isError($packagelist)) { return $packagelist; } + if (!is_array($packagelist) || !isset($packagelist['p'])) { return array(); } + if (!is_array($packagelist['p'])) { $packagelist['p'] = array($packagelist['p']); } + return $packagelist['p']; } @@ -84741,10 +85395,12 @@ if (PEAR::isError($packagelist)) { return $packagelist; } + if (!is_array($packagelist) || !isset($packagelist['p'])) { $ret = array(); return $ret; } + if (!is_array($packagelist['p'])) { $packagelist['p'] = array($packagelist['p']); } @@ -84761,6 +85417,7 @@ $categories[$cat] = $inf['ca']; } } + return array_values($categories); } @@ -84779,9 +85436,11 @@ if (PEAR::isError($packagelist)) { return $packagelist; } + if (!is_array($packagelist) || !isset($packagelist['p'])) { return array(); } + if (!is_array($packagelist['p']) || !isset($packagelist['p'][0])) { // only 1 pkg $packagelist = array($packagelist['p']); @@ -84825,7 +85484,7 @@ } if ($this->_rest->config->get('verbose') > 0) { $ui = &PEAR_Frontend::singleton(); - $ui->log('Retrieving data...0%', false); + $ui->log('Retrieving data...0%', true); } $ret = array(); if (!is_array($packagelist) || !isset($packagelist['p'])) { @@ -86232,7 +86891,7 @@ * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Common.php,v 1.20 2009/02/25 00:15:49 dufuz Exp $ + * @version CVS: $Id: Common.php 276394 2009-02-25 00:15:49Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since Release 1.4.0a1 */ @@ -86270,7 +86929,7 @@ * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 1.4.0a1 * @abstract @@ -86433,7 +87092,7 @@ * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Postinstallscript.php,v 1.22 2009/02/24 23:45:56 dufuz Exp $ + * @version CVS: $Id: Postinstallscript.php 276385 2009-02-24 23:46:03Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since Release 1.4.0a1 */ @@ -86451,7 +87110,7 @@ * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 1.4.0a1 */ @@ -86755,7 +87414,7 @@ * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: rw.php,v 1.14 2009/02/24 23:45:32 dufuz Exp $ + * @version CVS: $Id: rw.php 276385 2009-02-24 23:46:03Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since Release 1.4.0a10 */ @@ -86770,7 +87429,7 @@ * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 1.4.0a10 */ @@ -86923,7 +87582,7 @@ * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Replace.php,v 1.19 2009/02/25 00:15:49 dufuz Exp $ + * @version CVS: $Id: Replace.php 276394 2009-02-25 00:15:49Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since Release 1.4.0a1 */ @@ -86938,7 +87597,7 @@ * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 1.4.0a1 */ @@ -87087,66 +87746,66 @@ return $contents; } } -?> - read/write version - * - * PHP versions 4 and 5 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: rw.php,v 1.5 2009/02/24 23:45:44 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a10 - */ -/** - * Base class - */ -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Task/Replace.php'; -/** - * Abstracts the replace task xml. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a10 - */ -class PEAR_Task_Replace_rw extends PEAR_Task_Replace -{ - function PEAR_Task_Replace_rw(&$pkg, &$config, &$logger, $fileXml) - { - parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE); - $this->_contents = $fileXml; - $this->_pkg = &$pkg; - $this->_params = array(); - } - - function validate() - { - return $this->validateXml($this->_pkg, $this->_params, $this->config, $this->_contents); - } - - function setInfo($from, $to, $type) - { - $this->_params = array('attribs' => array('from' => $from, 'to' => $to, 'type' => $type)); - } - - function getName() - { - return 'replace'; - } - - function getXml() - { - return $this->_params; - } -} +?> - read/write version + * + * PHP versions 4 and 5 + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: rw.php 276385 2009-02-24 23:46:03Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a10 + */ +/** + * Base class + */ +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Task/Replace.php'; +/** + * Abstracts the replace task xml. + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a10 + */ +class PEAR_Task_Replace_rw extends PEAR_Task_Replace +{ + function PEAR_Task_Replace_rw(&$pkg, &$config, &$logger, $fileXml) + { + parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE); + $this->_contents = $fileXml; + $this->_pkg = &$pkg; + $this->_params = array(); + } + + function validate() + { + return $this->validateXml($this->_pkg, $this->_params, $this->config, $this->_contents); + } + + function setInfo($from, $to, $type) + { + $this->_params = array('attribs' => array('from' => $from, 'to' => $to, 'type' => $type)); + } + + function getName() + { + return 'replace'; + } + + function getXml() + { + return $this->_params; + } +} ?> @@ -87158,7 +87817,7 @@ * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Unixeol.php,v 1.12 2009/02/25 00:15:49 dufuz Exp $ + * @version CVS: $Id: Unixeol.php 276394 2009-02-25 00:15:49Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since Release 1.4.0a1 */ @@ -87173,7 +87832,7 @@ * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 1.4.0a1 */ @@ -87223,61 +87882,61 @@ return preg_replace("/\r\n|\n\r|\r|\n/", "\n", $contents); } } -?> - read/write version - * - * PHP versions 4 and 5 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: rw.php,v 1.6 2009/02/24 23:45:30 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a10 - */ -/** - * Base class - */ -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Task/Unixeol.php'; -/** - * Abstracts the unixeol task xml. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a10 - */ -class PEAR_Task_Unixeol_rw extends PEAR_Task_Unixeol -{ - function PEAR_Task_Unixeol_rw(&$pkg, &$config, &$logger, $fileXml) - { - parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE); - $this->_contents = $fileXml; - $this->_pkg = &$pkg; - $this->_params = array(); - } - - function validate() - { - return true; - } - - function getName() - { - return 'unixeol'; - } - - function getXml() - { - return ''; - } -} +?> - read/write version + * + * PHP versions 4 and 5 + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: rw.php 276385 2009-02-24 23:46:03Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a10 + */ +/** + * Base class + */ +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Task/Unixeol.php'; +/** + * Abstracts the unixeol task xml. + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a10 + */ +class PEAR_Task_Unixeol_rw extends PEAR_Task_Unixeol +{ + function PEAR_Task_Unixeol_rw(&$pkg, &$config, &$logger, $fileXml) + { + parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE); + $this->_contents = $fileXml; + $this->_pkg = &$pkg; + $this->_params = array(); + } + + function validate() + { + return true; + } + + function getName() + { + return 'unixeol'; + } + + function getXml() + { + return ''; + } +} ?> @@ -87289,7 +87948,7 @@ * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Windowseol.php,v 1.11 2009/02/25 00:15:49 dufuz Exp $ + * @version CVS: $Id: Windowseol.php 276394 2009-02-25 00:15:49Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since Release 1.4.0a1 */ @@ -87304,7 +87963,7 @@ * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 1.4.0a1 */ @@ -87354,61 +88013,61 @@ return preg_replace("/\r\n|\n\r|\r|\n/", "\r\n", $contents); } } -?> - read/write version - * - * PHP versions 4 and 5 - * - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: rw.php,v 1.6 2009/02/24 23:45:20 dufuz Exp $ - * @link http://pear.php.net/package/PEAR - * @since File available since Release 1.4.0a10 - */ -/** - * Base class - */ -require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Task/Windowseol.php'; -/** - * Abstracts the windowseol task xml. - * @category pear - * @package PEAR - * @author Greg Beaver - * @copyright 1997-2009 The Authors - * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 - * @link http://pear.php.net/package/PEAR - * @since Class available since Release 1.4.0a10 - */ -class PEAR_Task_Windowseol_rw extends PEAR_Task_Windowseol -{ - function PEAR_Task_Windowseol_rw(&$pkg, &$config, &$logger, $fileXml) - { - parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE); - $this->_contents = $fileXml; - $this->_pkg = &$pkg; - $this->_params = array(); - } - - function validate() - { - return true; - } - - function getName() - { - return 'windowseol'; - } - - function getXml() - { - return ''; - } -} +?> - read/write version + * + * PHP versions 4 and 5 + * + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version CVS: $Id: rw.php 276385 2009-02-24 23:46:03Z dufuz $ + * @link http://pear.php.net/package/PEAR + * @since File available since Release 1.4.0a10 + */ +/** + * Base class + */ +require_once 'phar://install-pear-nozlib.phar/' . 'PEAR/Task/Windowseol.php'; +/** + * Abstracts the windowseol task xml. + * @category pear + * @package PEAR + * @author Greg Beaver + * @copyright 1997-2009 The Authors + * @license http://opensource.org/licenses/bsd-license.php New BSD License + * @version Release: 1.9.0 + * @link http://pear.php.net/package/PEAR + * @since Class available since Release 1.4.0a10 + */ +class PEAR_Task_Windowseol_rw extends PEAR_Task_Windowseol +{ + function PEAR_Task_Windowseol_rw(&$pkg, &$config, &$logger, $fileXml) + { + parent::PEAR_Task_Common($config, $logger, PEAR_TASK_PACKAGE); + $this->_contents = $fileXml; + $this->_pkg = &$pkg; + $this->_params = array(); + } + + function validate() + { + return true; + } + + function getName() + { + return 'windowseol'; + } + + function getXml() + { + return ''; + } +} ?> * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: Validate.php,v 1.54 2009/02/24 23:38:23 dufuz Exp $ + * @version CVS: $Id: Validate.php 276383 2009-02-24 23:39:37Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since Release 1.4.0a1 */ @@ -87443,7 +88102,7 @@ * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 1.4.0a1 */ @@ -88048,7 +88707,7 @@ * @author Greg Beaver * @copyright 1997-2006 The PHP Group * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: PECL.php,v 1.10 2009/02/24 23:39:19 dufuz Exp $ + * @version CVS: $Id: PECL.php 276383 2009-02-24 23:39:37Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since Release 1.4.0a5 */ @@ -88063,7 +88722,7 @@ * @author Greg Beaver * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 1.4.0a5 */ @@ -88111,7 +88770,7 @@ * @author Stephan Schmidt (original XML_Unserializer code) * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license New BSD License - * @version CVS: $Id: XMLParser.php,v 1.22 2009/03/08 00:45:39 dufuz Exp $ + * @version CVS: $Id: XMLParser.php 282970 2009-06-28 23:10:07Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since Release 1.4.0a1 */ @@ -88124,7 +88783,7 @@ * @author Stephan Schmidt (original XML_Unserializer code) * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license New BSD License - * @version Release: 1.8.0 + * @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 1.4.0a1 */ @@ -88146,13 +88805,13 @@ * stack for all data that is found * @var array $_dataStack */ - var $_dataStack = array(); + var $_dataStack = array(); /** * stack for all values that are generated * @var array $_valStack */ - var $_valStack = array(); + var $_valStack = array(); /** * current tag depth @@ -88184,8 +88843,7 @@ include_once 'phar://install-pear-nozlib.phar/' . 'PEAR.php'; return PEAR::raiseError("XML Extension not found", 1); } - $this->_valStack = array(); - $this->_dataStack = array(); + $this->_dataStack = $this->_valStack = array(); $this->_depth = 0; if ( @@ -88199,6 +88857,7 @@ if (version_compare(phpversion(), '5.0.0', 'lt') && $this->encoding == 'UTF-8') { $data = utf8_decode($data); + $this->encoding = 'ISO-8859-1'; } $xp = xml_parser_create($this->encoding); @@ -88228,25 +88887,21 @@ */ function startHandler($parser, $element, $attribs) { - $type = 'string'; - $this->_depth++; $this->_dataStack[$this->_depth] = null; $val = array( - 'name' => $element, - 'value' => null, - 'type' => $type, - 'childrenKeys' => array(), - 'aggregKeys' => array() - ); + 'name' => $element, + 'value' => null, + 'type' => 'string', + 'childrenKeys' => array(), + 'aggregKeys' => array() + ); if (count($attribs) > 0) { $val['children'] = array(); $val['type'] = 'array'; - $val['children']['attribs'] = $attribs; - } array_push($this->_valStack, $val); @@ -88277,18 +88932,14 @@ $data = $this->postProcess($this->_dataStack[$this->_depth], $element); // adjust type of the value - switch(strtolower($value['type'])) { - + switch (strtolower($value['type'])) { // unserialize an array case 'array': if ($data !== '') { $value['children']['_content'] = $data; } - if (isset($value['children'])) { - $value['value'] = $value['children']; - } else { - $value['value'] = array(); - } + + $value['value'] = isset($value['children']) ? $value['children'] : array(); break; /* @@ -88360,6 +89011,38 @@ $this->_dataStack[$this->_depth] .= $cdata; } } * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License - * @version CVS: $Id: System.php,v 1.66 2009/02/24 23:52:56 dufuz Exp $ + * @version CVS: $Id: System.php 276386 2009-02-24 23:52:56Z dufuz $ * @link http://pear.php.net/package/PEAR * @since File available since Release 0.1 */ @@ -93602,7 +94285,7 @@ * @author Tomas V.V. Cox * @copyright 1997-2006 The PHP Group * @license http://opensource.org/licenses/bsd-license.php New BSD License -* @version Release: 1.8.0 +* @version Release: 1.9.0 * @link http://pear.php.net/package/PEAR * @since Class available since Release 0.1 * @static @@ -94214,7 +94897,7 @@ * @author Stephan Schmidt * @copyright 2003-2008 Stephan Schmidt * @license http://opensource.org/licenses/bsd-license New BSD License - * @version CVS: $Id: Util.php,v 1.39 2009/02/09 14:23:42 ashnazg Exp $ + * @version CVS: $Id: Util.php 275418 2009-02-09 14:23:42Z ashnazg $ * @link http://pear.php.net/package/XML_Util */ @@ -98095,4 +98778,4 @@ GucAn22sSv3QiTSUWG9BmakiW9hFsb4V =g2mr -----END PGP SIGNATURE----- -G\$U D7TGBMB \ No newline at end of file +Z?Aj^1GBMB \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/main/php_version.h +++ php5-5.2.10.dfsg.1/main/php_version.h @@ -3,6 +3,6 @@ #define PHP_MAJOR_VERSION 5 #define PHP_MINOR_VERSION 2 #define PHP_RELEASE_VERSION 10 -#define PHP_EXTRA_VERSION "" -#define PHP_VERSION "5.2.10" +#define PHP_EXTRA_VERSION "-1ubuntu1" +#define PHP_VERSION "5.2.10-1ubuntu1" #define PHP_VERSION_ID 50210 --- php5-5.2.10.dfsg.1.orig/debian/php5-sybase.postrm +++ php5-5.2.10.dfsg.1/debian/php5-sybase.postrm @@ -0,0 +1,10 @@ +#!/bin/sh +set -e + +NEW_CONFFILE=/etc/php5/conf.d/mssql.ini +if [ "$1" = "upgrade" ] && dpkg --compare-versions "$2" lt 5.2.3-2 +then + rm $NEW_CONFFILE +fi + +#DEBHELPER# --- php5-5.2.10.dfsg.1.orig/debian/php5-dev.files +++ php5-5.2.10.dfsg.1/debian/php5-dev.files @@ -0,0 +1,6 @@ +usr/bin/php-config +usr/bin/phpize +usr/share/man/man1/php-config.1 +usr/share/man/man1/phpize.1 +usr/include +usr/lib/php5/build --- php5-5.2.10.dfsg.1.orig/debian/libapache2-mod-php5.postinst +++ php5-5.2.10.dfsg.1/debian/libapache2-mod-php5.postinst @@ -0,0 +1,63 @@ +#!/bin/sh + +set -e + +#DEBHELPER# + +if [ "$1" != "configure" ]; then + exit 0 +fi + +phpini="/etc/php5/apache2/php.ini" + +# LEGACY SUPPORT +# previous versions of php did not ship $phpini as a conffile nor did +# they use anything like ucf. as a result, we need to help transition +# those files into ucf a little more easily by updating unmodified +# ini files before registering them +# +# if we're upgrading from a pre-ucf version of php: +if dpkg --compare-versions "$2" le-nl "5.1.6-4"; then + # if the SAPI config file already exists and is unmodified + if [ -f "$phpini" ]; then + oldmd5=`md5sum $phpini | cut -d' ' -f1` + if [ "$oldmd5" = "c85605baab79fbcd3c289e442eb3caa2" ]; then + # then silently update it before registering via ucf + cp /usr/share/php5/php.ini-dist $phpini + fi + fi +fi +# END LEGACY SUPPORT + +ucf /usr/share/php5/php.ini-dist $phpini + +reload_apache() +{ + if apache2ctl configtest 2>/dev/null; then + invoke-rc.d apache2 force-reload || true + else + echo "Your apache2 configuration is broken, so we're not restarting it for you." + fi +} + +if [ -n "$2" ]; then + # recover the previous state + if [ -e /etc/php5/apache2/.start ]; then + a2enmod php5 >/dev/null || true + rm -f /etc/php5/apache2/.start + fi +# we're upgrading. test if we're enabled, and if so, restart to reload the module. + if [ -e /etc/apache2/mods-enabled/php5.load ]; then + reload_apache + fi + exit 0 +fi + +if [ -e /etc/apache2/apache2.conf ]; then +# Enable the module, but hide a2enmod's misleading message about apachectl +# and force-reload the thing ourselves. + a2enmod php5 >/dev/null || true + reload_apache +fi + +exit 0 --- php5-5.2.10.dfsg.1.orig/debian/php5-module.ini +++ php5-5.2.10.dfsg.1/debian/php5-module.ini @@ -0,0 +1,2 @@ +# configuration for php @extname@ module +extension=@dsoname@.so --- php5-5.2.10.dfsg.1.orig/debian/gbp.conf +++ php5-5.2.10.dfsg.1/debian/gbp.conf @@ -0,0 +1,8 @@ +[DEFAULT] +debian-branch = debian-sid +debian-tag = debian/%(version)s +upstream-branch = upstream-sid +upstream-tag = upstream/%(version)s + +[git-dch] +meta = 1 --- php5-5.2.10.dfsg.1.orig/debian/php5-sapi.lintian-overrides +++ php5-5.2.10.dfsg.1/debian/php5-sapi.lintian-overrides @@ -0,0 +1,6 @@ +# The extensions directory must exist, even if empty +@sapi@: package-contains-empty-directory @extdir@/ +# Not a spelling mistake, just a compilation curiosity +@sapi@: spelling-error-in-binary * ment meant +# Not a spelling mistake, tz code for Tahiti +@sapi@: spelling-error-in-binary * taht that --- php5-5.2.10.dfsg.1.orig/debian/php5-dev.dirs +++ php5-5.2.10.dfsg.1/debian/php5-dev.dirs @@ -0,0 +1,2 @@ +/usr/bin +/usr/share/lintian/overrides --- php5-5.2.10.dfsg.1.orig/debian/php5-sapi.links +++ php5-5.2.10.dfsg.1/debian/php5-sapi.links @@ -0,0 +1 @@ +etc/php5/conf.d etc/php5/@sapi@/conf.d --- php5-5.2.10.dfsg.1.orig/debian/extramodulelist +++ php5-5.2.10.dfsg.1/debian/extramodulelist @@ -0,0 +1,8 @@ +mysql MySQL mysqli +mysql MySQL pdo_mysql +interbase InterBase/Firebird pdo_firebird +common PDO pdo +odbc ODBC pdo_odbc +pgsql PostgreSQL pdo_pgsql +sqlite SQLite pdo_sqlite +sybase Sybase pdo_dblib --- php5-5.2.10.dfsg.1.orig/debian/libapache2-mod-php5.dirs +++ php5-5.2.10.dfsg.1/debian/libapache2-mod-php5.dirs @@ -0,0 +1,3 @@ +/etc/apache2/mods-available +/etc/php5/apache2 +/usr/lib/apache2/modules --- php5-5.2.10.dfsg.1.orig/debian/libapache2-mod-php5filter.prerm +++ php5-5.2.10.dfsg.1/debian/libapache2-mod-php5filter.prerm @@ -0,0 +1,20 @@ +#!/bin/sh + +set -e + +#DEBHELPER# + +if [ "$1" != "remove" -a "$1" != "purge" ]; then + exit 0 +fi + +if [ -e /etc/apache2/apache2.conf ]; then + if [ -e /etc/apache2/mods-enabled/php5.load ]; then + # set a flag to remember the original state + # useful when reinstalling the same version. + touch /etc/php5/apache2filter/.start + fi + a2dismod php5filter || true +fi + +exit 0 --- php5-5.2.10.dfsg.1.orig/debian/php5-common.docs +++ php5-5.2.10.dfsg.1/debian/php5-common.docs @@ -0,0 +1,10 @@ +CREDITS +EXTENSIONS +TODO +CODING_STANDARDS +README.CVS-RULES +README.EXT_SKEL +README.SELF-CONTAINED-EXTENSIONS +README.Zeus +README.PHP4-TO-PHP5-THIN-CHANGES +debian/README.Debian.security --- php5-5.2.10.dfsg.1.orig/debian/php5-common.dirs +++ php5-5.2.10.dfsg.1/debian/php5-common.dirs @@ -0,0 +1,7 @@ +/usr/lib/php5/libexec +/usr/share/lintian/overrides +/usr/share/doc/php5-common/examples +/usr/share/php5 +/var/lib/php5 +/usr/lib/php5 +/etc/php5/conf.d --- php5-5.2.10.dfsg.1.orig/debian/php-pear.dirs +++ php5-5.2.10.dfsg.1/debian/php-pear.dirs @@ -0,0 +1 @@ +/usr/share/doc/php-pear/PEAR --- php5-5.2.10.dfsg.1.orig/debian/rules +++ php5-5.2.10.dfsg.1/debian/rules @@ -0,0 +1,608 @@ +#!/usr/bin/make -f +# Sample debian/rules that uses debhelper. +# GNU copyright 1997 by Joey Hess. +# +# This version is for a hypothetical package that builds an +# architecture-dependant package, as well as an architecture-independent +# package. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +# This has to be exported to make some magic below work. +export DH_OPTIONS + +# Set this flag to 'yes' if you want to disable all modifications breaking abi +# compatibility to upstream +PHP5_COMPAT=no + +DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) +DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) +DEB_HOST_ARCH ?= $(shell dpkg-architecture -qDEB_HOST_ARCH) + +PHP5_HOST_GNU_TYPE = $(subst gnulp,gnu,$(DEB_HOST_GNU_TYPE)) +PHP5_BUILD_GNU_TYPE = $(subst gnulp,gnu,$(DEB_BUILD_GNU_TYPE)) + +PHP5_HOST_GNU_TYPE := $(shell echo $(PHP5_HOST_GNU_TYPE) | sed 's/-gnu$$//') +PHP5_BUILD_GNU_TYPE := $(shell echo $(PHP5_BUILD_GNU_TYPE) | sed 's/-gnu$$//') + +PHP5_SOURCE_VERSION = $(shell dpkg-parsechangelog | grep ^Version | sed "s/Version: //") +PHP5_UPSTREAM_VERSION = $(shell echo $(PHP5_SOURCE_VERSION) | sed -e "s/-.*//" -e "s/.*://") +PHP5_DEBIAN_REVISION = $(shell echo $(PHP5_SOURCE_VERSION) | sed "s/.*-//") + +# specify some options to our patch system +QUILT_DIFF_OPTS=-p +QUILT_NO_DIFF_TIMESTAMPS=1 +export QUILT_DIFF_OPTS QUILT_NO_DIFF_TIMESTAMPS + +PROG_SENDMAIL = /usr/sbin/sendmail +ifeq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) + CFLAGS += -O2 +endif +CFLAGS += -Wall -fsigned-char -fno-strict-aliasing +# LFS support +ifneq (yes,$(PHP5_COMPAT)) + CFLAGS += $(shell getconf LFS_CFLAGS) +endif + +# Enable IEEE-conformant floating point math on alphas (not the default) +ifeq (alpha-linux-gnu,$(DEB_HOST_GNU_TYPE)) + CFLAGS += -mieee +endif + +ifeq ($(DEB_HOST_GNU_TYPE), $(findstring $(DEB_HOST_GNU_TYPE), ia64-linux-gnu powerpc64-linux-gnu)) + CFLAGS += -g +else + CFLAGS += -gstabs +endif + +# Old magic.mime location: +ifeq ($(wildcard /usr/share/misc/file/magic.mime), /usr/share/misc/file/magic.mime) +MAGIC_MIME = /usr/share/misc/file/magic.mime +endif +# New magic.mime location: +ifeq ($(wildcard /usr/share/file/magic.mime), /usr/share/file/magic.mime) +MAGIC_MIME = /usr/share/file/magic.mime +endif + +# some other helpful (for readability at least) shorthand variables +PHPIZE_BUILDDIR = debian/php5-dev/usr/lib/php5/build + +# support new (>= 2.2) and older versions of libtool for backporting ease +LIBTOOL_DIRS = /usr/share/libtool/config /usr/share/libtool +LTMAIN = $(firstword $(wildcard $(foreach d,$(LIBTOOL_DIRS),$d/ltmain.sh))) +LTMAIN_DIR = $(dir $(LTMAIN)) + +ifeq ($(LTMAIN_DIR), /usr/share/libtool/) +LIBTOOL_CONFLICTS:=libtool (>= 2.2) +else ifeq ($(LTMAIN_DIR), /usr/share/libtool/config/) +LIBTOOL_CONFLICTS:=libtool (<< 2.2) +else +LIBTOOL_CONFLICTS:=$(error "could not resolve path to ltmain.sh") +endif + +COMMON_CONFIG=--build=$(DEB_BUILD_GNU_TYPE) \ + --host=$(DEB_HOST_GNU_TYPE) \ + --sysconfdir=/etc \ + --mandir=/usr/share/man \ + --disable-debug \ + --with-regex=php \ + --disable-rpath \ + --disable-static \ + --with-pic \ + --with-layout=GNU \ + --with-pear=/usr/share/php \ + --enable-calendar \ + --enable-sysvsem \ + --enable-sysvshm \ + --enable-sysvmsg \ + --enable-bcmath \ + --with-bz2 \ + --enable-ctype \ + --with-db4 \ + --without-gdbm \ + --with-iconv \ + --enable-exif \ + --enable-ftp \ + --with-gettext \ + --enable-mbstring \ + --with-pcre-regex=/usr \ + --enable-shmop \ + --enable-sockets \ + --enable-wddx \ + --with-libxml-dir=/usr \ + --with-zlib \ + --with-kerberos=/usr \ + --with-openssl=/usr \ + --enable-soap \ + --enable-zip \ + --with-mime-magic=$(MAGIC_MIME) \ + --with-exec-dir=/usr/lib/php5/libexec \ + --with-system-tzdata + +BUILTIN_EXTENSION_CHECK=$$e=get_loaded_extensions(); natcasesort($$e); \ + $$s="The following extensions are built in:"; \ + foreach($$e as $$i) { $$s .= " $$i"; } \ + echo("php:Extensions=" . wordwrap($$s . ".\n", 75, "\$${Newline} ")); + +# include the patch/unpatch rules from quilt +include /usr/share/quilt/quilt.make + +prepared: prepared-stamp +prepared-stamp: $(QUILT_STAMPFN) + dh_testdir + sed -i -e 's/EXTRA_VERSION=""/EXTRA_VERSION="-$(PHP5_DEBIAN_REVISION)"/' configure.in + ./buildconf --force + touch prepared-stamp + +unprepared: + dh_testdir + sed -i -e 's/EXTRA_VERSION="-$(PHP5_DEBIAN_REVISION)"/EXTRA_VERSION=""/' configure.in + rm -f prepared-stamp + +test-results.txt: build-apache2-stamp build-cli-stamp build-cgi-stamp +ifeq (,$(findstring nocheck,$(DEB_BUILD_OPTIONS))) + mkdir -p temp_session_store + env NO_INTERACTION=1 TEST_PHP_CGI_EXECUTABLE=./cgi-build/sapi/cgi/cgi-bin.php5 TEST_PHP_EXECUTABLE=./apache2-build/sapi/cli/php ./apache2-build/sapi/cli/php run-tests.php > test-results.txt + rm -rf temp_session_store +else + echo 'nocheck found in DEB_BUILD_OPTIONS' > test-results.txt +endif + cat test-results.txt + +build: build-apache2-stamp build-apache2filter-stamp build-cgi-stamp build-cli-stamp build-pear-stamp test-results.txt + +build-apache2-stamp: configure-apache2-stamp + dh_testdir + cd apache2-build && $(MAKE) + + touch build-apache2-stamp + +build-apache2filter-stamp: configure-apache2filter-stamp + dh_testdir + cd apache2filter-build && $(MAKE) + + touch build-apache2filter-stamp + +build-cli-stamp: configure-cli-stamp + dh_testdir + cd cli-build && $(MAKE) + + touch build-cli-stamp + + +build-cgi-stamp: configure-cgi-stamp + dh_testdir + cd cgi-build && $(MAKE) && mv sapi/cgi/php-cgi sapi/cgi/cgi-bin.php5 + + # Dirty hack to not rebuild everything twice + cd cgi-build/main && \ + sed -i -e 's/FORCE_CGI_REDIRECT 1/FORCE_CGI_REDIRECT 0/' \ + -e 's/DISCARD_PATH 0/DISCARD_PATH 1/' php_config.h && \ + sed -i -e 's/--enable-force-cgi-redirect/--enable-discard-path/' build-defs.h && \ + touch ../../ext/standard/info.c && \ + touch ../../sapi/cgi/cgi_main.c + + cd cgi-build && $(MAKE) && mv sapi/cgi/php-cgi sapi/cgi/usr.bin.php5-cgi + + touch build-cgi-stamp + +build-pear-stamp: build-cgi-stamp + dh_testdir + -mkdir pear-build + -mkdir pear-build-download + cd cgi-build && PHP_PEAR_DOWNLOAD_DIR=$(CURDIR)/pear-build-download $(MAKE) install-pear PHP_PEAR_PHP_BIN=/usr/bin/php PHP_PEAR_INSTALL_DIR=/usr/share/php PHP_PEAR_SYSCONF_DIR=/etc/pear PHP_PEAR_SIG_BIN=/usr/bin/gpg INSTALL_ROOT=$(CURDIR)/pear-build + sed -i -e 's/-d output_buffering=1 -d open_basedir="" -d safe_mode=0/-d output_buffering=1 -d open_basedir="" -d safe_mode=0 -d memory_limit="-1"/' \ + $(CURDIR)/pear-build/usr/bin/pear && \ + sed -i -e 's/-d output_buffering=1 -d safe_mode=0/-d output_buffering=1 -d open_basedir="" -d safe_mode=0 -d memory_limit="-1"/' \ + $(CURDIR)/pear-build/usr/bin/pecl && \ + sed -i -e 's/-d memory_limit="-1"//' \ + -e 's/-d output_buffering=1 -d open_basedir="" -d safe_mode=0/-d output_buffering=1 -d open_basedir="" -d safe_mode=0 -d memory_limit="-1"/' \ + $(CURDIR)/pear-build/usr/bin/peardev + sed -i -re "s#('PEAR_CONFIG_SYSCONFDIR', PHP_SYSCONFDIR)#\1 . '/pear'#" $(CURDIR)/pear-build/usr/share/php/PEAR/Config.php + patch -s -d $(CURDIR)/pear-build/usr/share/php/ -p0 -i $(CURDIR)/debian/patches/php5-pear-CVE-2011-1072.patch + patch -s -d $(CURDIR)/pear-build/usr/share/php/ -p0 -i $(CURDIR)/debian/patches/php5-pear-CVE-2011-1144.patch + patch -s -d $(CURDIR)/pear-build/usr/share/php/ -p0 -i $(CURDIR)/debian/patches/php5-pear-CVE-2011-1144-regression.patch + touch build-pear-stamp + +configure: configure-apache2-stamp configure-apache2filter-stamp configure-cli-stamp configure-cgi-stamp + +configure-apache2-stamp: prepared-stamp + dh_testdir + if [ -d apache2-build ]; then rm -rf apache2-build; fi + -mkdir apache2-build + cd apache2-build && \ + CFLAGS="$(CFLAGS)" PROG_SENDMAIL="$(PROG_SENDMAIL)" ../configure \ + --prefix=/usr --with-apxs2=/usr/bin/apxs2 \ + --with-config-file-path=/etc/php5/apache2 \ + --with-config-file-scan-dir=/etc/php5/apache2/conf.d \ + $(COMMON_CONFIG) \ + --without-mm \ + --with-curl=shared,/usr \ + --with-zlib-dir=/usr \ + --with-gd=shared,/usr --enable-gd-native-ttf \ + --with-gmp=shared,/usr \ + --with-jpeg-dir=shared,/usr \ + --with-xpm-dir=shared,/usr/X11R6 \ + --with-png-dir=shared,/usr \ + --with-freetype-dir=shared,/usr \ + --with-ttf=shared,/usr \ + --with-t1lib=shared,/usr \ + --with-ldap=shared,/usr \ + --with-ldap-sasl=/usr \ + --with-mhash=shared,/usr \ + --with-mysql=shared,/usr \ + --with-mysqli=shared,/usr/bin/mysql_config \ + --with-pspell=shared,/usr \ + --with-unixODBC=shared,/usr \ + --with-recode=shared,/usr \ + --with-xsl=shared,/usr \ + --with-snmp=shared,/usr \ + --with-sqlite=shared,/usr \ + --with-mssql=shared,/usr \ + --with-tidy=shared,/usr \ + --with-xmlrpc=shared \ + --with-pgsql=shared,/usr PGSQL_INCLUDE=`pg_config --includedir` \ + --enable-pdo=shared \ + --without-pdo-dblib \ + --with-pdo-mysql=shared,/usr \ + --with-pdo-odbc=shared,unixODBC,/usr \ + --with-pdo-pgsql=shared,/usr/bin/pg_config \ + --with-pdo-sqlite=shared,/usr \ + --with-pdo-dblib=shared,/usr + cd apache2-build && \ + cp ../Zend/zend_ini_scanner.c ../Zend/zend_language_scanner.c \ + ../Zend/zend_ini_parser.h ../Zend/zend_language_parser.h \ + ../Zend/zend_ini_parser.c ../Zend/zend_language_parser.c \ + Zend/ + touch configure-apache2-stamp + +configure-apache2filter-stamp: prepared-stamp + dh_testdir + if [ -d apache2filter-build ]; then rm -rf apache2filter-build; fi + -mkdir apache2filter-build + cd apache2filter-build && \ + CFLAGS="$(CFLAGS)" PROG_SENDMAIL="$(PROG_SENDMAIL)" ../configure \ + --prefix=/usr --with-apxs2filter=/usr/bin/apxs2 \ + --with-config-file-path=/etc/php5/apache2filter \ + --with-config-file-scan-dir=/etc/php5/apache2filter/conf.d \ + $(COMMON_CONFIG) \ + --without-mm \ + --disable-pdo \ + --without-mysql --without-sybase-ct --without-mssql \ + --without-sqlite + cd apache2filter-build && \ + cp ../Zend/zend_ini_scanner.c ../Zend/zend_language_scanner.c \ + ../Zend/zend_ini_parser.h ../Zend/zend_language_parser.h \ + ../Zend/zend_ini_parser.c ../Zend/zend_language_parser.c \ + Zend/ + touch configure-apache2filter-stamp + +configure-cgi-stamp: prepared-stamp + dh_testdir + if [ -d cgi-build ]; then rm -rf cgi-build; fi + -mkdir cgi-build + cd cgi-build && \ + CFLAGS="$(CFLAGS)" PROG_SENDMAIL="$(PROG_SENDMAIL)" ../configure \ + --prefix=/usr --enable-force-cgi-redirect --enable-fastcgi \ + --with-config-file-path=/etc/php5/cgi \ + --with-config-file-scan-dir=/etc/php5/cgi/conf.d \ + $(COMMON_CONFIG) \ + --without-mm \ + --disable-pdo \ + --without-mysql --without-sybase-ct --without-mssql \ + --without-sqlite + cd cgi-build && \ + cp ../Zend/zend_ini_scanner.c ../Zend/zend_language_scanner.c \ + ../Zend/zend_ini_parser.h ../Zend/zend_language_parser.h \ + ../Zend/zend_ini_parser.c ../Zend/zend_language_parser.c \ + Zend/ + touch configure-cgi-stamp + +configure-cli-stamp: prepared-stamp + dh_testdir + if [ -d cli-build ]; then rm -rf cli-build; fi + -mkdir cli-build + cd cli-build && \ + CFLAGS="$(CFLAGS)" PROG_SENDMAIL="$(PROG_SENDMAIL)" ../configure \ + --prefix=/usr --disable-cgi \ + --with-config-file-path=/etc/php5/cli \ + --with-config-file-scan-dir=/etc/php5/cli/conf.d \ + $(COMMON_CONFIG) \ + --with-libedit \ + --without-mm \ + --disable-pdo \ + --without-mysql --without-sybase-ct --without-sqlite \ + --without-mssql --enable-pcntl \ + --with-ncurses=/usr + cd cli-build && \ + cp ../Zend/zend_ini_scanner.c ../Zend/zend_language_scanner.c \ + ../Zend/zend_ini_parser.h ../Zend/zend_language_parser.h \ + ../Zend/zend_ini_parser.c ../Zend/zend_language_parser.c \ + Zend/ + touch configure-cli-stamp + +clean: unprepared unpatch + dh_testdir + dh_testroot + + + rm -f configure-apache2-stamp build-apache2-stamp + rm -f configure-apache2filter-stamp build-apache2filter-stamp + rm -f configure-cgi-stamp build-cgi-stamp + rm -f configure-cli-stamp build-cli-stamp + rm -f build-pear-stamp + rm -f install-stamp + rm -rf apache2-build + rm -rf apache2filter-build + rm -rf cgi-build + rm -rf cli-build + rm -rf pear-build pear-build-download + rm -f debian/copyright + rm -f test-results.txt + dh_clean -Xorig + + # clean up autogenerated cruft + cat debian/modulelist | while read package extname dsoname; do \ + rm -f debian/php5-$$package.postinst; \ + done + for sapi in libapache2-mod-php5 libapache2-mod-php5filter php5-cgi php5-cli; do \ + for cruft in postrm links; do \ + rm -f debian/$${sapi}.$${cruft}; \ + done; \ + done + +install: DH_OPTIONS= +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + + chmod 01733 debian/php5-common/var/lib/php5 + + # Add here commands to install the package into debian/php5. + # install apache2 DSO module + cp apache2-build/.libs/libphp5.so \ + debian/libapache2-mod-php5/`apxs2 -q LIBEXECDIR`/ + cp debian/libapache2-mod-php5.load \ + debian/libapache2-mod-php5/etc/apache2/mods-available/php5.load + cp debian/libapache2-mod-php5.conf \ + debian/libapache2-mod-php5/etc/apache2/mods-available/php5.conf + + # Add here commands to install the package into debian/php5. + # install apache2 DSO filter module + cp apache2filter-build/.libs/libphp5.so \ + debian/libapache2-mod-php5filter/`apxs2 -q LIBEXECDIR`/libphp5filter.so + cp debian/libapache2-mod-php5filter.load \ + debian/libapache2-mod-php5filter/etc/apache2/mods-available/php5filter.load + cp debian/libapache2-mod-php5filter.conf \ + debian/libapache2-mod-php5filter/etc/apache2/mods-available/php5filter.conf + + # sanitize php.ini file + # memory_limit: 16M for cgi/apache; 32M for cli + cat php.ini-dist | tr "\t" " " | sed -e'/memory_limit =/ s/\b128M/16M/g' > debian/php5-common/usr/share/php5/php.ini-dist + cat php.ini-dist | tr "\t" " " | sed -e'/memory_limit =/ s/\b128M/32M/g' > debian/php5-common/usr/share/php5/php.ini-dist.cli + cat php.ini-dist | tr "\t" " " > debian/php5-common/usr/share/doc/php5-common/examples/php.ini-dist + cat php.ini-recommended | tr "\t" " " > debian/php5-common/usr/share/doc/php5-common/examples/php.ini-recommended + cat php.ini-paranoid | tr "\t" " " > debian/php5-common/usr/share/doc/php5-common/examples/php.ini-paranoid + cp test-results.txt debian/php5-common/usr/share/doc/php5-common/ + + # install the apache modules' files + cd apache2-build && $(MAKE) install-headers install-build install-modules install-programs INSTALL_ROOT=$(CURDIR)/debian/libapache2-mod-php5 + # remove netware and win32 headers that we don't want + cd debian/libapache2-mod-php5/usr/include/php5/ && \ + $(RM) TSRM/readdir.h \ + TSRM/tsrm_config.nw.h TSRM/tsrm_config.w32.h\ + TSRM/tsrm_nw.h TSRM/tsrm_win32.h\ + Zend/zend_config.nw.h Zend/zend_config.w32.h\ + main/config.nw.h main/config.w32.h\ + main/win95nt.h + + # install PEAR + cp -a pear-build/* debian/php-pear/ + + # everything under usr/share/php/data except 'PEAR' is b0rken + # and actually needs to be fixed + [ ! -f debian/php-pear/usr/share/php/data/Structures_Graph/LICENSE ] || \ + $(RM) debian/php-pear/usr/share/php/data/Structures_Graph/LICENSE + [ ! -f debian/php-pear/usr/share/php/doc/PEAR/INSTALL ] || \ + $(RM) debian/php-pear/usr/share/php/doc/PEAR/INSTALL + for f in Structures_Graph/publish.sh Structures_Graph/package.sh \ + Structures_Graph/genpackage.xml.pl; do \ + $(RM) debian/php-pear/usr/share/php/data/$$f; \ + done + # we don't want test suites + $(RM) -r debian/php-pear/usr/share/php/test/ + [ -d debian/php-pear/usr/share/php/doc ] && { \ + mkdir -p debian/php-pear/usr/share/doc/php-pear/PEAR; \ + mv debian/php-pear/usr/share/php/doc/* \ + debian/php-pear/usr/share/doc/php-pear/PEAR/; \ + $(RM) -r debian/php-pear/usr/share/php/doc; \ + cd debian/php-pear/usr/share/php; \ + ln -s PEAR doc; \ + } + + # install extensions + ext=`./debian/libapache2-mod-php5/usr/bin/php-config --extension-dir`;\ + for i in libapache2-mod-php5 libapache2-mod-php5filter php5-cgi php5-cli; do \ + mkdir -p debian/$$i/$${ext}; \ + done; \ + cat debian/modulelist debian/extramodulelist | while read package extname dsoname; do \ + if [ -z "$$dsoname" ]; then dsoname=$$package; fi; \ + mkdir -p debian/php5-$$package$${ext}; \ + chrpath debian/libapache2-mod-php5/$${ext}/$$dsoname.so; \ + chrpath -d debian/libapache2-mod-php5/$${ext}/$$dsoname.so; \ + install -m 644 -o root -g root \ + debian/libapache2-mod-php5/$${ext}/$$dsoname.so \ + debian/php5-$$package$${ext}/$$dsoname.so; \ + rm debian/libapache2-mod-php5/$${ext}/$$dsoname.so; \ + done + + # install CGI + cp cgi-build/sapi/cgi/cgi-bin.php5 debian/php5-cgi/usr/lib/cgi-bin/php5 + cp cgi-build/sapi/cgi/usr.bin.php5-cgi debian/php5-cgi/usr/bin/php5-cgi + cp cli-build/sapi/cli/php.1 debian/php5-cgi/usr/share/man/man1/php5-cgi.1 + + # install CLI + cp cli-build/sapi/cli/php debian/php5-cli/usr/bin/php5 + cp cli-build/sapi/cli/php.1 debian/php5-cli/usr/share/man/man1/php5.1 + + # move and install -dev files + dh_movefiles --sourcedir=debian/libapache2-mod-php5 + rm -rf debian/libapache2-mod-php5/usr/lib/php5/build/ \ + debian/libapache2-mod-php5/usr/include/ \ + debian/libapache2-mod-php5/usr/bin/ + rm -rf debian/libapache2-mod-php5filter/usr/lib/php5/build/ \ + debian/libapache2-mod-php5filter/usr/include/ \ + debian/libapache2-mod-php5filter/usr/bin/ + for i in Makefile.global acinclude.m4 mkdep.awk phpize.m4 scan_makefile_in.awk; do \ + chmod 644 debian/php5-dev/usr/lib/php5/build/$$i; \ + done + # shipping duplicate files from other packages is hell for security audits + ln -sf /usr/share/misc/config.guess $(PHPIZE_BUILDDIR)/config.guess + ln -sf /usr/share/misc/config.sub $(PHPIZE_BUILDDIR)/config.sub + ln -sf /usr/share/aclocal/libtool.m4 $(PHPIZE_BUILDDIR)/libtool.m4 + ln -sf $(LTMAIN_DIR)ltmain.sh $(PHPIZE_BUILDDIR)/ltmain.sh + ln -sf /usr/bin/shtool $(PHPIZE_BUILDDIR)/shtool + # make php-dev stuff versioned + for i in php-config phpize; do \ + mv debian/php5-dev/usr/bin/$$i debian/php5-dev/usr/bin/"$$i"5; \ + mv debian/php5-dev/usr/share/man/man1/"$$i".1 debian/php5-dev/usr/share/man/man1/"$$i"5.1; \ + done + + # install common files + install -m755 debian/maxlifetime debian/php5-common/usr/lib/php5 + + # install lintian overrides + cp debian/php5.lintian-overrides $(CURDIR)/debian/php5-common/usr/share/lintian/overrides/php5-common + cp debian/php5-dev.lintian-overrides $(CURDIR)/debian/php5-dev/usr/share/lintian/overrides/php5-dev + + # install some generic lintian overrides + ext=`debian/php5-dev/usr/bin/php-config5 --extension-dir | cut -b2- `; \ + for sapi in php5-cli php5-cgi libapache2-mod-php5 libapache2-mod-php5filter; do \ + mkdir -p $(CURDIR)/debian/"$$sapi"/usr/share/lintian/overrides/; \ + sed "s/@sapi@/$$sapi/g;s,@extdir@,$$ext,g" \ + < $(CURDIR)/debian/php5-sapi.lintian-overrides \ + >> $(CURDIR)/debian/"$$sapi"/usr/share/lintian/overrides/"$$sapi"; \ + done + + # directories cleanup: + -rmdir -p debian/libapache2-mod-php5/usr/share/man/man1 + -find debian/php-pear -type d -exec rmdir --ignore-fail-on-non-empty -p '{}' \; >/dev/null 2>&1 + + touch install-stamp + +# Build architecture-independent files here. +# Pass -i to all debhelper commands in this target to reduce clutter. +binary-indep: DH_OPTIONS=-i +binary-indep: build install + # Need this version of debhelper for DH_OPTIONS to work. + dh_testdir + dh_testroot + cat debian/copyright.header LICENSE Zend/LICENSE > debian/copyright + + dh_installdocs + + for package in php5 php-pear; do \ + rm -rf debian/$$package/usr/share/doc/$$package; \ + ln -s php5-common debian/$$package/usr/share/doc/$$package; \ + done + + dh_link + dh_compress -Xphp.ini + dh_fixperms + dh_installdeb + dh_gencontrol + dh_md5sums + dh_builddeb + +# Build architecture-dependent files here. +binary-arch: build install + # Need this version of debhelper for DH_OPTIONS to work. + dh_testdir + dh_testroot + # Do this first so we don't overwrite any debhelper-generated files + # + # generate the maintscripts for various php + # modules from the templates. + cat debian/modulelist | while read package extname dsoname; do \ + if [ -z "$$dsoname" ]; then dsoname=$$package; fi; \ + sed -e"s/@extname@/$$extname/g; s/@dsoname@/$$dsoname/g; \ + /#EXTRA#/ r debian/php5-$${package}.postinst.extra" \ + < debian/php5-module.postinst \ + | sed -e'/#EXTRA#/ d' \ + > debian/php5-$${package}.postinst; \ + done + + # generate the config snippets for various php + # modules from the templates. + cat debian/modulelist debian/extramodulelist | while read package extname dsoname; do \ + if [ -z "$$dsoname" ]; then dsoname=$$package; fi; \ + mkdir -p debian/php5-$$package/etc/php5/conf.d; \ + sed -e"s/@extname@/$$extname/g; s/@dsoname@/$$dsoname/g" \ + < debian/php5-module.ini \ + > debian/php5-$${package}/etc/php5/conf.d/$${dsoname}.ini; \ + done + + # likewise, for the different sapi implementations + for tmpl in postrm links; do \ + for sapi in apache2 apache2filter cgi cli; do \ + sed -e "s/@sapi@/$$sapi/g" \ + < debian/php5-sapi.$$tmpl \ + > debian/php5-$${sapi}.$$tmpl; \ + done; \ + mv debian/php5-apache2.$$tmpl debian/libapache2-mod-php5.$$tmpl; \ + mv debian/php5-apache2filter.$$tmpl debian/libapache2-mod-php5filter.$$tmpl; \ + done + + cat debian/copyright.header LICENSE Zend/LICENSE > debian/copyright + dh_installdocs -s + + cat debian/modulelist | while read package extname dsoname; do \ + rm -rf debian/php5-$$package/usr/share/doc/php5-$$package; \ + ln -s php5-common debian/php5-$$package/usr/share/doc/php5-$$package; \ + done + + for package in php5-dbg php5-dev php5-cgi php5-cli libapache2-mod-php5 libapache2-mod-php5filter; do \ + rm -rf debian/$$package/usr/share/doc/$$package; \ + ln -s php5-common debian/$$package/usr/share/doc/$$package; \ + done + dh_installcron -pphp5-common --name=php5 + dh_installchangelogs -pphp5-common NEWS + dh_strip -s --dbg-package=php5-dbg + dh_link -s + dh_compress -s -Xphp.ini + dh_fixperms -s -X /var/lib/php5 + dh_installdeb -s + dh_shlibdeps -s + + phpapi=`./debian/php5-dev/usr/bin/php-config5 --phpapi`; \ + for i in libapache2-mod-php5 libapache2-mod-php5filter php5-cgi php5-cli; do \ + echo "php:Provides=phpapi-$${phpapi}" >> debian/$$i.substvars; \ + done; \ + cat debian/modulelist | while read package extname dsoname; do \ + echo "php:Depends=php5 | phpapi-$${phpapi}" >> debian/php5-$$package.substvars; \ + done + + for i in cgi cli; do \ + "$$i"-build/sapi/cli/php -n -r '$(BUILTIN_EXTENSION_CHECK)' \ + >> debian/php5-"$$i".substvars; \ + done + for i in apache2; do \ + "$$i"-build/sapi/cli/php -n -r '$(BUILTIN_EXTENSION_CHECK)' \ + >> debian/lib"$$i"-mod-php5.substvars; \ + "$$i"-build/sapi/cli/php -n -r '$(BUILTIN_EXTENSION_CHECK)' \ + >> debian/lib"$$i"-mod-php5filter.substvars; \ + done + + echo "apache2:Depends=apache2-mpm-prefork (>> 2.0.52) | apache2-mpm-itk, apache2.2-common" >>debian/libapache2-mod-php5.substvars + echo "apache2:Depends=apache2-mpm-prefork (>> 2.0.52) | apache2-mpm-itk, apache2.2-common" >>debian/libapache2-mod-php5filter.substvars + + echo "libtool:Conflicts=$(LIBTOOL_CONFLICTS)" >>debian/php5-dev.substvars + dh_gencontrol -s + dh_md5sums -s + dh_builddeb -s + +binary: binary-arch binary-indep +.PHONY: build clean binary-indep binary-arch binary install configure --- php5-5.2.10.dfsg.1.orig/debian/php5-cli.postinst +++ php5-5.2.10.dfsg.1/debian/php5-cli.postinst @@ -0,0 +1,37 @@ +#!/bin/sh + +set -e + +#DEBHELPER# + +if [ "$1" != "configure" ]; then + exit 0 +fi + +phpini="/etc/php5/cli/php.ini" +# LEGACY SUPPORT +# previous versions of php did not ship $phpini as a conffile nor did +# they use anything like ucf. as a result, we need to help transition +# those files into ucf a little more easily by updating unmodified +# ini files before registering them +# +# if we're upgrading from a pre-ucf version of php: +if dpkg --compare-versions "$2" le-nl "5.1.6-4"; then + # if the SAPI config file already exists and is unmodified + if [ -f "$phpini" ]; then + oldmd5=`md5sum $phpini | cut -d' ' -f1` + if [ "$oldmd5" = "c85605baab79fbcd3c289e442eb3caa2" ]; then + # then silently update it before registering via ucf + cp /usr/share/php5/php.ini-dist.cli $phpini + fi + fi +fi +# END LEGACY SUPPORT + +ucf /usr/share/php5/php.ini-dist.cli $phpini + +update-alternatives \ + --install /usr/bin/php php /usr/bin/php5 50 \ + --slave /usr/share/man/man1/php.1.gz php.1.gz /usr/share/man/man1/php5.1.gz + +exit 0 --- php5-5.2.10.dfsg.1.orig/debian/php5-dev.prerm +++ php5-5.2.10.dfsg.1/debian/php5-dev.prerm @@ -0,0 +1,15 @@ +#!/bin/sh + +set -e + +#DEBHELPER# + +if [ "$1" != "remove" -a "$1" != "purge" ]; then + exit 0 +fi + +for i in php-config phpize; do + update-alternatives --remove $i /usr/bin/"$i"5 +done + +exit 0 --- php5-5.2.10.dfsg.1.orig/debian/README.Debian.security +++ php5-5.2.10.dfsg.1/debian/README.Debian.security @@ -0,0 +1,22 @@ +the Debian stable security team does not provide security support +for certain configurations known to be inherently insecure. Most +specifically, the security team will not provide support for flaws in: + +- problems which are not flaws in the design of php but can be problematic + when used by sloppy developers (for example, not checking the contents + of a tar file before extracting it). + +- vulnerabilities involving register_globals being activated, unless + specifically the vulnerability activates this setting when it was + configured as deactivated. + +- vulnerabilities involving any kind of safe_mode or open_basedir + violation, as these are security models flawed by design and no longer + have upstream support either. + +- any "works as expected" vulnerabilities, such as "user can cause php + to crash by writing a malcious php script", unless such vulnerabilities + involve some kind of higher-level DoS or privilege escalation that would + not otherwise be available. + + -- sean finney Tue, 10 Oct 2006 12:42:06 +0200 --- php5-5.2.10.dfsg.1.orig/debian/php5-cgi.dirs +++ php5-5.2.10.dfsg.1/debian/php5-cgi.dirs @@ -0,0 +1,4 @@ +/etc/php5/cgi +/usr/lib/cgi-bin +/usr/bin +/usr/share/man/man1 --- php5-5.2.10.dfsg.1.orig/debian/libapache2-mod-php5filter.load +++ php5-5.2.10.dfsg.1/debian/libapache2-mod-php5filter.load @@ -0,0 +1 @@ +LoadModule php5_module /usr/lib/apache2/modules/libphp5filter.so --- php5-5.2.10.dfsg.1.orig/debian/libapache2-mod-php5filter.postinst +++ php5-5.2.10.dfsg.1/debian/libapache2-mod-php5filter.postinst @@ -0,0 +1,43 @@ +#!/bin/sh + +set -e + +#DEBHELPER# + +if [ "$1" != "configure" ]; then + exit 0 +fi + +phpini="/etc/php5/apache2filter/php.ini" + +ucf /usr/share/php5/php.ini-dist $phpini + +reload_apache() +{ + if apache2ctl configtest 2>/dev/null; then + invoke-rc.d apache2 force-reload || true + else + echo "Your apache2 configuration is broken, so we're not restarting it for you." + fi +} + +if [ -n "$2" ]; then + # recover the previous state + if [ -e /etc/php5/apache2filter/.start ]; then + a2enmod php5filter >/dev/null || true + fi +# we're upgrading. test if we're enabled, and if so, restart to reload the module. + if [ -e /etc/apache2/mods-enabled/php5filter.load ]; then + reload_apache + fi + exit 0 +fi + +if [ -e /etc/apache2/apache2.conf ]; then +# Enable the module, but hide a2enmod's misleading message about apachectl +# and force-reload the thing ourselves. + a2enmod php5filter >/dev/null || true + reload_apache +fi + +exit 0 --- php5-5.2.10.dfsg.1.orig/debian/php5-cli.prerm +++ php5-5.2.10.dfsg.1/debian/php5-cli.prerm @@ -0,0 +1,11 @@ +#!/bin/sh + +set -e + +#DEBHELPER# + +if [ "$1" = "remove" -o "$1" = "deconfigure" ]; then + update-alternatives --remove php /usr/bin/php5 +fi + +exit 0 --- php5-5.2.10.dfsg.1.orig/debian/php5-cli.dirs +++ php5-5.2.10.dfsg.1/debian/php5-cli.dirs @@ -0,0 +1,3 @@ +/etc/php5/cli +/usr/bin +/usr/share/man/man1 --- php5-5.2.10.dfsg.1.orig/debian/maxlifetime +++ php5-5.2.10.dfsg.1/debian/maxlifetime @@ -0,0 +1,13 @@ +#!/bin/sh -e + +max=1440 + +for ini in /etc/php5/*/php.ini; do + cur=$(sed -n -e 's/^[[:space:]]*session.gc_maxlifetime[[:space:]]*=[[:space:]]*\([0-9]\+\).*$/\1/p' $ini 2>/dev/null || true); + [ -z "$cur" ] && cur=0 + [ "$cur" -gt "$max" ] && max=$cur +done + +echo $(($max/60)) + +exit 0 --- php5-5.2.10.dfsg.1.orig/debian/php5-imap.substvars +++ php5-5.2.10.dfsg.1/debian/php5-imap.substvars @@ -0,0 +1 @@ +php:Depends=phpapi-20060613 --- php5-5.2.10.dfsg.1.orig/debian/README.source +++ php5-5.2.10.dfsg.1/debian/README.source @@ -0,0 +1,8 @@ + + == Generation of the php5-dbg package Depends == + + The following command can be used to generate a heuristic list of packages +the php5-dbg package probably needs to Depend on: +dh_testdir && egrep '^Package' debian/control | cut '-d ' -f2 | \ + egrep -v '(^php5|dbg|dev|common|pear)$' | tr "\n" "|" | sed 's/|$//' |\ + sed -r 's/([^|]+)(\||$)/ \1 (= ${binary:Version}) \2/g'; echo --- php5-5.2.10.dfsg.1.orig/debian/php5-sybase.prerm +++ php5-5.2.10.dfsg.1/debian/php5-sybase.prerm @@ -0,0 +1,12 @@ +#!/bin/sh +set -e + +OLD_CONFFILE=/etc/php5/conf.d/sybase_ct.ini +NEW_CONFFILE=/etc/php5/conf.d/mssql.ini +if [ "$1" = "upgrade" ] && dpkg --compare-versions "$2" lt 5.2.3-2 +then + sed -e's/\(extension=[[:space:]]*\)mssql\.so/\1sybase_ct.so/' \ + $NEW_CONFFILE > $OLD_CONFFILE +fi + +#DEBHELPER# --- php5-5.2.10.dfsg.1.orig/debian/php5.lintian-overrides +++ php5-5.2.10.dfsg.1/debian/php5.lintian-overrides @@ -0,0 +1,2 @@ +php5-common: non-standard-dir-perm var/lib/php5/ 1733 != 0755 +php5-common: package-contains-empty-directory usr/lib/php5/libexec/ --- php5-5.2.10.dfsg.1.orig/debian/libapache2-mod-php5.load +++ php5-5.2.10.dfsg.1/debian/libapache2-mod-php5.load @@ -0,0 +1 @@ +LoadModule php5_module /usr/lib/apache2/modules/libphp5.so --- php5-5.2.10.dfsg.1.orig/debian/changelog +++ php5-5.2.10.dfsg.1/debian/changelog @@ -0,0 +1,3752 @@ +php5 (5.2.10.dfsg.1-2ubuntu6.10) karmic-security; urgency=low + + * debian/patches/php5-pear-CVE-2011-1144-regression.patch: fix + mkdir parenthesis issue and PEAR::raiseErro typo (LP: #774452) + + -- Steve Beattie Mon, 02 May 2011 09:21:27 -0700 + +php5 (5.2.10.dfsg.1-2ubuntu6.9) karmic-security; urgency=low + + * SECURITY UPDATE: arbitrary files removal via cronjob + - debian/php5-common.php5.cron.d: take greater care when removing + session files. + - http://git.debian.org/?p=pkg-php%2Fphp.git;a=commitdiff_plain;h=d09fd04ed7bfcf7f008360c6a42025108925df09 + - CVE-2011-0441 + * SECURITY UPDATE: symlink tmp races in pear install + - debian/patches/php5-pear-CVE-2011-1072.patch: improved + tempfile handling. + - debian/rules: apply patch manually after unpacking PEAR phar + archive. + - CVE-2011-1072 + * SECURITY UPDATE: more symlink races in pear install + - debian/patches/php5-pear-CVE-2011-1144.patch: add TOCTOU save + file handler. + - debian/rules: apply patch manually after unpacking PEAR phar + archive. + - CVE-2011-1144 + * SECURITY UPDATE: use-after-free vulnerability + - debian/patches/php5-CVE-2010-4697.patch: retain reference to + object until getter/setter are done. + - CVE-2010-4697 + * SECURITY UPDATE: denial of service through application crash with + invalid images + - debian/patches/php5-CVE-2010-4698.patch: verify anti-aliasing + steps are either 4 or 16. + - CVE-2010-4698 + * SECURITY UPDATE: denial of service through application crash + - debian/patches/php5-CVE-2011-0421.patch: fail operation gracefully + when handling zero sized zipfile with the FL_UNCHANGED argument + - CVE-2011-0421 + * SECURITY UPDATE: denial of service through application crash when + handling images with invalid exif tags + - debian/patches/php5-CVE-2011-0708.patch: stricter exif checking + - CVE-2011-0708 + * SECURITY UPDATE: denial of service and possible data disclosure + through integer overflow + - debian/patches/php5-CVE-2011-1092.patch: better boundary + condition checks in shmop_read() + - CVE-2011-1092 + * SECURITY UPDATE: use-after-free vulnerability + - debian/patches/php5-CVE-2011-1148.patch: improve reference + counting + - CVE-2011-1148 + * SECURITY UPDATE: denial of service through buffer overflow crash + (code execution mitigated by compilation with Fortify Source) + - debian/patches/php5-CVE-2011-1464.patch: limit amount of precision + to ensure fitting within MAX_BUF_SIZE + - CVE-2011-1464 + * SECURITY UPDATE: denial of service through application crash via + integer overflow. + - debian/patches/php5-CVE-2011-1466.patch: improve boundary + condition checking in SdnToJulian() + - CVE-2011-1466 + * SECURITY UPDATE: denial of service through application crash + when using HTTP proxy with the FTP wrapper + - debian/patches/php5-CVE-2011-1469.patch: improve pointer handling + - CVE-2011-1469 + * SECURITY UPDATE: denial of service through application crash when + handling ziparchive streams + - debian/patches/php5-CVE-2011-1470.patch: set necessary elements of + the meta data structure + - CVE-2011-1470 + * SECURITY UPDATE: denial of service through application crash when + handling malformed zip files + - debian/patches/php5-CVE-2011-1471.patch: correct integer + signedness error when handling zip_fread() return value. + - CVE-2011-1471 + + -- Steve Beattie Thu, 28 Apr 2011 05:37:29 -0700 + +php5 (5.2.10.dfsg.1-2ubuntu6.7) karmic-security; urgency=low + + * debian/patches/php5-CVE-2010-3436-regression.patch: update + main/fopen_wrappers.c to include fix for open_basedir restriction + regression (LP: #701896) + + -- Steve Beattie Wed, 12 Jan 2011 07:51:41 -0800 + +php5 (5.2.10.dfsg.1-2ubuntu6.6) karmic-security; urgency=low + + * SECURITY UPDATE: overflow leading to xml decode bypass + - debian/patches/php5-CVE-2009-5016.patch: convert short to int + to prevent overflow in bit operations + - CVE-2009-5016 + * SECURITY UPDATE: xml decode bypass + - debian/patches/php5-CVE-2010-3780.patch: improve utf8 decoding + - CVE-2010-3780 + * SECURITY UPDATE: open_basedir bypass + - debian/patches/php5-CVE-2010-3436.patch: more strict checking in + php_check_specific_open_basedir() + - CVE-2010-3436 + * SECURITY UPDATE: NULL pointer dereference crash + - debian/patches/php5-CVE-2010-3709.patch: check for NULL when + getting zip comment + - CVE-2010-3709 + * SECURITY UPDATE: memory consumption denial of service + - debian/patches/php5-CVE-2010-3710.patch: check for email address + longer than RFC 2821 allows + - CVE-2010-3710 + * SECURITY UPDATE: infinite loop/denial of service when dealing with + certain textual forms of MAX_FLOAT (LP: #697181) + - debian/patches/php5-CVE-2010-4645.patch: treat local doubles + as volatile to avoid x87 registers in zend_strtod() + - CVE-2010-4645 + + -- Steve Beattie Fri, 07 Jan 2011 22:39:12 -0800 + +php5 (5.2.10.dfsg.1-2ubuntu6.5) karmic-security; urgency=low + + * SECURITY UPDATE: denial of service via xmlrpc crafted argument + - debian/patches/CVE-2010-0397.patch: make sure method_name isn't empty + in ext/xmlrpc/xmlrpc-epi-php.c, add test to + ext/xmlrpc/tests/bug51288.phpt. + - CVE-2010-0397 + * SECURITY UPDATE: weak entropy in Linear Congruential Generator (LCG) + - debian/patches/CVE-2010-1128.patch: add more entropy in + ext/standard/lcg.c. + - CVE-2010-1128 + * SECURITY UPDATE: safe_mode bypass via trailing slash in dir pathnames + - debian/patches/CVE-2010-1129.patch: properly validate pathname in + ext/standard/file.c. + - CVE-2010-1129 + * SECURITY UPDATE: safe_mode bypass via semicolon in session_save_path + - debian/patches/CVE-2010-1130.patch: check for semicolon in + ext/session/session.c. + - CVE-2010-1130 + * SECURITY UPDATE: arbitrary code execution via empty SQL query + - debian/patches/CVE-2010-1868.patch: use ecalloc instead of emalloc in + ext/sqlite/sqlite.c. + - CVE-2010-1868 + * SECURITY UPDATE: denial of service via fnmatch stack consumption + - debian/patches/CVE-2010-1917.patch: limit size of pattern in + ext/standard/file.c. + - CVE-2010-1917 + * SECURITY UPDATE: sensitive information disclosure or arbitrary code + execution via use-after-free in SplObjectStorage unserializer + - debian/patches/CVE-2010-2225.patch: fix logic in + ext/spl/spl_observer.c. + - CVE-2010-2225 + * SECURITY UPDATE: sensitive information disclosure via error messages + - debian/patches/CVE-2010-2531.patch: don't display data when flushing + output buffer in ext/standard/{var.c,php_var.h}, fix tests in + ext/standard/tests/general_functions/*. + - CVE-2010-2531 + * SECURITY UPDATE: arbitrary session variable modification via crafted + session variable name + - debian/patches/CVE-2010-3065.patch: handle PS_UNDEF_MARKER marker in + ext/session/session.c. + - CVE-2010-3065 + + -- Marc Deslauriers Tue, 14 Sep 2010 14:41:26 -0400 + +php5 (5.2.10.dfsg.1-2ubuntu6.4) karmic-security; urgency=low + + * SECURITY UPDATE: information disclosure and denial of service via + zend_restore_ini_entry_cb function. + - debian/patches/CVE-2009-2626.patch: make sure new_value exists in + main/main.c, gracefully handle failure in Zend/zend_ini.c. + - CVE-2009-2626 + * SECURITY UPDATE: Cross-site scripting via incomplete htmlspecialchars + filtering + - debian/patches/CVE-2009-4142.patch: rewrite handling logic in + ext/standard/html.c, add ext/standard/tests/strings/bug49785.phpt + test script, fix ext/standard/tests/strings/htmlentities-utf.phpt + test script. + - CVE-2009-4142 + * SECURITY UPDATE: restrictions bypass via incorrect session data + handling + - debian/patches/CVE-2009-4143.patch: protect from interrupt + corruption in ext/session/session.c. + - CVE-2009-4143 + + -- Marc Deslauriers Tue, 05 Jan 2010 13:14:59 -0500 + +php5 (5.2.10.dfsg.1-2ubuntu6.3) karmic-security; urgency=low + + * SECURITY UPDATE: certificate spoofing via null-byte certs (LP: #446313) + - debian/patches/CVE-2009-3291.patch: validate certificate's CN length + in ext/openssl/openssl.c. + - CVE-2009-3291 + * SECURITY UPDATE: denial of service via malformed exif images + (LP: #446313) + - debian/patches/CVE-2009-3292.patch: check length, return codes, and + nesting level in ext/exif/exif.c. + - CVE-2009-3292 + * SECURITY UPDATE: safe_mode bypass via tempam function + - debian/patches/CVE-2009-3557.patch: check for safe_mode in + ext/standard/file.c. + - CVE-2009-3557 + * SECURITY UPDATE: open_basedir restrictions bypass via posix_mkfifo + - debian/patches/CVE-2009-3558.patch: check for open_basedir in + ext/posix/posix.c. + - CVE-2009-3558 + * SECURITY UPDATE: denial of service via large number of files in + form-data POST request. + - debian/patches/CVE-2009-4017.patch: introduce new "max_file_uploads" + directive and enforce in main/main.c, main/rfc1867.c. + - ATTENTION: this update changes previous php5 behaviour by limiting + the number of files in a POST request to 50. This may be increased + by adding a "max_file_uploads" directive to the php.ini configuration + file. + - CVE-2009-4017 + * SECURITY UPDATE: safe_mode_protected_env_vars bypass via proc_open() + - debian/patches/CVE-2009-4018.patch: add safe_mode check in + ext/standard/proc_open.c + - CVE-2009-4018 + + -- Marc Deslauriers Thu, 26 Nov 2009 08:27:27 -0500 + +php5 (5.2.10.dfsg.1-2ubuntu6.1) karmic-proposed; urgency=low + + * debian/patches/series: Re-enable 019-z_off_t_as_long.patch. This is + causing users to have issues with zlib (LP: #451314) + + -- Chuck Short Wed, 28 Oct 2009 09:03:25 -0400 + +php5 (5.2.10.dfsg.1-2ubuntu6) karmic; urgency=low + + * debian/rules; Fix broken symlink preventing php-pear from working + properly. (LP: #451277) + + -- Chuck Short Fri, 23 Oct 2009 11:17:03 -0400 + +php5 (5.2.10.dfsg.1-2ubuntu5) karmic; urgency=low + + * debian/control, debian/patches/115-autoconf_ftbfs.patch:, debian/series: + Drop patch build-depend on autoconf2.13 + * pear/install-pear-nozlib.phar: PHP 5.2.10 was shipped with a broken + install-pear-nozllib.phar which caused pear to be broken. Use the + version from http://pear.php.net. (LP: #420639) + * debian/patches/fix-zlib-decompression: Add upstream fix from 5.2.11 + fo fix zlibe.deflage compress filter to actually accept level parameter. + * debian/rules: Fix symlink for pear. + + -- Chuck Short Tue, 13 Oct 2009 10:56:29 -0400 + +php5 (5.2.10.dfsg.1-2ubuntu4) karmic; urgency=low + + * debian/control: Move to php5-suhoshin to Suggests + + -- Chuck Short Fri, 18 Sep 2009 10:36:36 -0400 + +php5 (5.2.10.dfsg.1-2ubuntu3) karmic; urgency=low + + * debian/control, debian/patches/115-autoconf_ftbfs.patch: Revert building + with autoconf2.13 since upstream has the proper fix. + + -- Chuck Short Sun, 06 Sep 2009 15:50:29 -0400 + +php5 (5.2.10.dfsg.1-2ubuntu2) karmic; urgency=low + + * debian/control: Change dependencies to MySQL 5.1. + + -- Mathias Gug Tue, 18 Aug 2009 18:04:28 -0400 + +php5 (5.2.10.dfsg.1-2ubuntu1) karmic; urgency=low + + * Merge from debian unstable, remaining changes: + - debian/control, debian/rules: Disable a few build dependencies and + accompanying, binary packages which we do not want to support in main: + + firebird2-dev/php5-interbase (we have a seperate php-interbase source) + + libc-client/php5-imap (we have a seperate php-imap source) + + libmcrypt-dev/php5-mcrypt (seperate php-mycrpt source) + + readline support again, now that the libedit issue is fixed. + - debian/control: Add build dependency: libdedit-dev (>= 2.9.cvs.20050518-1) + CLI readline support. + - debian/rules: + - Correctly mangle PHP5_* macros for lpia + - debian/patches/119-sybase-alias.patch: + + Fix sybase regression since change to mssql. (LP: #240519) + - debian/patches/fix-autoconf-ftbfs.patch: + + Fixes FTBFS. + - debian/control: + + Use libdb-4.6-dev + + Rename Vcs-Browser & Vcs-Git to XS-Original-Vcs-Browser & XS-Original-Vcs-Git (LP: #323731). + + Use autoconf2.13 to build. Thanks to dreamcast4 (LP: #411890) + + -- Chuck Short Fri, 10 Jul 2009 07:19:08 +0100 + +php5 (5.2.10.dfsg.1-2) unstable; urgency=low + + * Declare that PEAR replaces XML_UTIL (Closes: #534621) + * Bump standards-version, no change needed + * Fix an unconditional limit on dblib_driver.c (Closes: #534881) + * Fix a segfault on exif_data_read with corrupted jpg files (Closes: #535888) + * Recommend php5-suhosin, as suggested by Thijs (Closes: #529760) + * Set sysconfig to /etc, to avoid getting /usr/etc in PHP_SYSCONFDIR + * Add myself to uploaders + * Fix the path to PEAR's config, directly in rules (Closes: #507762) + + -- Raphael Geissert Thu, 09 Jul 2009 18:25:48 -0500 + +php5 (5.2.10.dfsg.1-1ubuntu1) karmic; urgency=low + + * Merge from debian unstable, remaining changes: + - debian/control, debian/rules: Disable a few build dependencies and + accompanying binary packages which we do not want to support in main: + + firebird2-dev/php5-interbase (we have a seperate php-interbase source) + + libc-client/php5-imap (we have a seperate php-imap source) + + libmcrypt-dev/php5-mcrypt (seperate php-mycrpt source) + + readline support again, now that the libedit issue is fixed. + - debian/control: Add build dependency: libdedit-dev (>= 2.9.cvs.20050518-1) + CLI readline support + - debian/rules: + - Correctly mangle PHP5_* macros for lpia + - debian/patches/119-sybase-alias.patch: + + Fix sybase regression since change to mssql. (LP: #240519) + - debian/patches/fix-autoconf-ftbfs.patch: + + Fixes FTBFS + - debian/control: Use libdb-4.6-dev + * Dropped changes: + - debian/patches/use-specific-libdb-version.patch (LP: #165247), merged + upstream in a previous release. + * debian/control: Rename Vcs-Browser & Vcs-Git to XS-Original-Vcs-Browser & + XS-Original-Vcs-Git (LP: #323731) + + -- Andrew Mitchell Thu, 25 Jun 2009 23:07:59 +1200 + +php5 (5.2.10.dfsg.1-1) unstable; urgency=low + + * New Upstream Version + + * update whitespace in various debian patches + * remove obsolete debian patch sockets_spelling.patch + * remove 10 obsolete gentoo patches now incorporated upstream + * update suhosin.patch for 5.2.10 + + -- Sean Finney Wed, 24 Jun 2009 00:18:27 +0200 + +php5 (5.2.9.dfsg.1-4ubuntu1) karmic; urgency=low + + * Merge from debian unstable, remaining changes: + - debian/control, debian/rules: Disable a few build dependencies and + accompanying binary packages which we do not want to support in main: + + firebird2-dev/php5-interbase (we have a seperate php-interbase source) + + libc-client/php5-imap (we have a seperate php-imap source) + + libmcrypt-dev/php5-mcrypt (seperate php-mycrpt source) + + readline support again, now that the libedit issue is fixed. + - debian/control: Add build dependency: libdedit-dev (>= 2.9.cvs.20050518-1) + CLI readline support + - debian/rules: + - Correctly mangle PHP5_* macros for lpia + - debian/patches/use-specific-libdb-version.patch (LP: #165247), mangle + version ordering in patch to match code for clean application. + - debian/patches/119-sybase-alias.patch: + + Fix sybase regression since change to mssql. (LP: #240519) + - debian/patches/fix-autoconf-ftbfs.patch: + + Fixes FTBFS + - debian/control: Use libdb-4.6-dev + * Dropped changes: + - debian/patches/fix-pecl-libtool.dpatch: + + included in debian/patches/libtool2.2.patch + - debian/patches/fix-segfault-in-openssl.patch: + + gentoo/010_ext-openssl-utf8-conversion-crash.patch includes it from Debian + - debian/patches/CVE-2009-0754.patch + + Included upstream + * debian/control: Rename Vcs-Browser & Vcs-Git to XS-Original-Vcs-Browser & + XS-Original-Vcs-Git (LP: #323731) + + -- Andrew Mitchell Tue, 02 Jun 2009 13:11:34 +1200 + +php5 (5.2.9.dfsg.1-4) unstable; urgency=high + + [ Thijs Kinkhorst ] + * Update php5-cli package description to make it more neutral, thanks + Daniel Hahler (closes: #528833). + + [ Sean Finney ] + * fix syntax error in phpize5 caused by libtool2.2.patch + - thanks to Michal Čihař (Closes: #529248) + * this (and the previous libtool2.2 fix) should get to testing as + fast as possible, so bumping prio to high. + + -- Sean Finney Mon, 18 May 2009 21:47:25 +0200 + +php5 (5.2.9.dfsg.1-3) unstable; urgency=low + + [ Sean Finney ] + * add gbp.conf for use with git-buildpackage + + [ Raphael Geissert ] + * Pick some bug fixing patches from Gentoo (thanks!) + * Make phpize copy and use the separate m4 files needed by libtool 2.2 + (Closes: #527004) + + -- Sean Finney Mon, 11 May 2009 22:09:11 +0200 + +php5 (5.2.9.dfsg.1-2) unstable; urgency=low + + [ Mark A. Hershberger ] + * fix up clean target + + [ Thijs Kinkhorst ] + * Update package sections to match override. + + [ Raphael Geissert ] + * Detect the path to ltmain.sh at build time and set conflicts + appropriately + * Add libdb4.7-dev as an ORed build dependency to fix FTBFS + * Update the Vcs-* fields to reflect the move from svn to git + * Turn the phpapi dependencies into php5 | phpapi to fix + installability issues + * Bump Standards-Version to 3.8.1, no change needed + * Fix a typo in the code: s/adress/address + * Add a set of lintian overrides for some FP spelling-error-in-binary + * Avoid a useless 15 seconds sleep on php_curl_stream_read under heavy + load + + [ Sean Finney ] + * update our libtool patching to be a little cleaner and smarter + * cleanup some of the phpize "cleanup" code in debian/rules + * slightly refined way for supporting old/new libtool dirs + + -- Sean Finney Thu, 23 Apr 2009 21:13:03 +0200 + +php5 (5.2.9.dfsg.1-1) unstable; urgency=low + + * New upstream release (closes: #520538). + - fixes regressions with parsing via libxml2 (closes: #520246, #520423). + + [ Sean Finney ] + * Refresh all patches. + * Update suhosin patch to 5.2.9, remove autotools-generated files (configure, + php_config.h.in) and .dsp files from patch. + * remove obsolete configure options from ./configure: --enable-memory-limit, + --enable-track-vars, --enable-trans-sid, --enable-filepro and --enable-dbx. + * Remove obsoleted patches which have been incorporated upstream: + - snmp_leaks.patch + - BG-initializing-fix.patch + - CVE-2008-2829.patch + - CVE-2008-3658.patch + - CVE-2008-3659.patch + - CVE-2008-3660.patch + - CVE-2008-5557.patch + - CVE-2008-5658.patch + - pdo-fetchobject-prototype-error.patch + - zend_object_handlers-invalid-write.patch + - dba-inifile-truncation.patch + - gentoo/freetds-compat.patch + - gentoo/010_ticks-zts-crashes.patch + - gentoo/019_new-memory-corruption.patch + - gentoo/009_array-function-crashes.patch + - gentoo/015_CVE-2008-2665-wrapper-safemode-bypass.patch + - gentoo/017_xmlrpc-invalid-callback-crash.patch + - gentoo/007_dom-setAttributeNode-crash.patch + - gentoo/006_PDORow-crash.patch + - gentoo/005_stream_context_set_params-crash.patch + * Update fix_broken_upstream_tests.patch, one of the tests is fixed. + + -- Sean Finney Tue, 24 Mar 2009 19:05:09 +0100 + +php5 (5.2.6.dfsg.1-3ubuntu4) jaunty; urgency=low + + * SECURITY UPDATE: arbitrary file write by placing a "php_value error_log" + entry in a .htaccess file. + - debian/patches/CVE-2008-5625.patch: enforce restrictions when merging + in dir entry in sapi/apache/mod_php5.c and sapi/apache2handler/apache_config.c. + - CVE-2008-5625 + * SECURITY UPDATE: mbstring.func_overload setting in .htaccess affects + other virtual hosts. + - debian/patches/CVE-2009-0754.patch: don't terminate on the first + function that is not overloaded in ext/mbstring/mbstring.c. + - CVE-2009-0754 + + -- Marc Deslauriers Mon, 30 Mar 2009 19:20:34 -0400 + +php5 (5.2.6.dfsg.1-3ubuntu3) jaunty; urgency=low + + * debian/patches/fix-segfault-in-openssl.patch: Fixes sigsegv + when using openssl_x509_parse (LP: #351730) + + -- Chuck Short Mon, 30 Mar 2009 15:34:17 -0400 + +php5 (5.2.6.dfsg.1-3ubuntu2) jaunty; urgency=low + + * debian/patches/fix-autoconf-ftbfs.patch : Fixes a FTBFS. + + -- Chuck Short Fri, 13 Feb 2009 13:59:06 -0500 + +php5 (5.2.6.dfsg.1-3ubuntu1) jaunty; urgency=low + + * Merge from debian unstable, remaining changes: + - debian/control, debian/rules: Disable a few build dependencies and + accompanying binary packages which we do not want to support in main: + + firebird2-dev/php5-interbase (we have a seperate php-interbase source) + + libc-client/php5-imap (we have a seperate php-imap source) + + libmcrypt-dev/php5-mcrypt (seperate php-mycrpt source) + + readline support again, now that the libedit issue is fixed. + - debian/control: Add build dependency: libdedit-dev (>= 2.9.cvs.20050518-1) + CLI readline support + - debian/rules: + - Correctly mangle PHP5_* macros for lpia + - Point /usr/lib/php5/build/{libtool.m4, ltmain.sh} to the right locations. + - Configure with --build=$(DEB_BUILD_GNU_TYPE) --host=$(DEB_HOST_GNU_TYPE) + to fix a build failure on armel. + - debian/patches/use-specific-libdb-version.patch (LP: #165247), mangle + version ordering in patch to match code for clean application. + - debian/patches/119-sybase-alias.patch: + + Fix sybase regression since change to mssql. (LP: #240519) + - debian/control: Use libdb-4.6-dev + - Revert to using upstreams' bundled libtool for now, until either upstream + moves to libtool 2.x, or Debian/Ubuntu have the time to rewrite some m4. + * Manually copy autotools-dev's versions of config.{sub.guess} since we + no long have libtoolize doing it for us, thanks to the above changes. + * debian/patches/fix-pecl-libtool.dpatch: fix libtool brokenness with pecl. + (LP: #262251) + * Dropped debian/patches/deprecated_freetds_check.patch in favor of Debian's. + + -- Chuck Short Wed, 04 Feb 2009 21:52:47 +0000 + +php5 (5.2.6.dfsg.1-3) unstable; urgency=low + + [ Sean Finney ] + * Do not add -O2 to CFLAGS if DEB_BUILD_OPTIONS contains noopt. + * Security related fixes: + - php: inifile handler for the dba functions can be used to truncate a file + Patch: dba-inifile-truncation.patch (closes: #507101). + - CVE-2008-5658.patch: ZipArchive::extractTo directory traversal + Patch: CVE-2008-5658.patch (closes: #507857). + Thanks to Pierre Joye for help with the patch. + + [ Raphael Geissert ] + * Picked up some patches from Gentoo (most included in PHP 5.2.7 and later): + + patches/gentoo/005_stream_context_set_params-crash.patch + + patches/gentoo/006_PDORow-crash.patch + + patches/gentoo/007_dom-setAttributeNode-crash.patch + + patches/gentoo/009_array-function-crashes.patch + + patches/gentoo/010_ticks-zts-crashes.patch + + patches/gentoo/015_CVE-2008-2665-wrapper-safemode-bypass.patch + + patches/gentoo/017_xmlrpc-invalid-callback-crash.patch + + patches/gentoo/019_new-memory-corruption.patch + + patches/gentoo/freetds-compat.patch + - was deprecated_freetds_check.patch + + -- Sean Finney Sat, 24 Jan 2009 21:17:13 +0100 + +php5 (5.2.6.dfsg.1-2) unstable; urgency=low + + [ Sean Finney ] + * Make sure a file used to track state is properly removed in the + postinst, thanks Raphael (closes: #511049). + + [ Thijs Kinkhorst ] + * Fix watch file to mangle version. + + [ Raphael Geissert ] + * Ship script used to take an upstream tarball and remove the non + DFSG-free stuff, update watch file accordingly. + + -- Sean Finney Tue, 13 Jan 2009 08:24:36 +0100 + +php5 (5.2.6.dfsg.1-1) unstable; urgency=high + + [ Sean Finney ] + * Incorporate previous NMU. + * Updated system tzdata patch from Joe Orton. + * Removed tzdb-nofree_ents_ifnotzdata.patch, which is now incorporated + into Joe's patch. + * Two backported fixes from 5.2.8, thanks to Olivier Bonvalet for looking + them up. + - Upstream bug #46157 (PDOStatement::fetchObject prototype error) + Patch: pdo-fetchobject-prototype-error.patch + - Upstream bug #46308 (Invalid write in zend object handler / getter) + Patch: zend_object_handlers-invalid-write.patch + * Security related fixes: + - CVE-2008-5624: Incorporate fix from 5.3 for proper initialization of + uid/gid for apache2 sapi. + Patch: BG-initializing-fix.patch + - CVE-2008-5557: heap overflows in the mbstring extension. + Patch: CVE-2008-5557.patch (closes: #511493). + + [ Thijs Kinkhorst ] + * Correct description typo, thanks Mathias Brodala (Closes: #508989). + + -- Sean Finney Mon, 12 Jan 2009 12:12:36 +0100 + +php5 (5.2.6.dfsg.1-0.1) unstable; urgency=low + + * Non-maintainer upload. + * Remove exts/dbase from orig tarball (Closes: #341420) + + -- Ben Hutchings Sat, 29 Nov 2008 19:19:28 +0000 + +php5 (5.2.6-5) unstable; urgency=high + + * Update debian/copyright to document that the DFSG-unfree email + requirement in ext/standard/rand.c has been rescinded by the + copyrightholder (Closes: #498621). + + -- Thijs Kinkhorst Sun, 05 Oct 2008 11:32:35 +0200 + +php5 (5.2.6-4) unstable; urgency=high + + [ Sean Finney ] + * Take three unreleased fixes from upstream CVS: + - CVE-2008-3658: Buffer overflow in the imageloadfont function. + Patch: CVE-2008-3658.patch (closes: #499989) + - CVE-2008-3659: Buffer overflow in the memnstr function. + Patch: CVE-2008-3659.patch (closes: #499988) + - CVE-2008-3660: Remote DoS in fastcgi module + Patch: CVE-2008-3660.patch (closes: #499987) + + [ Raphael Geissert ] + * snmp_leaks.patch: fixes memory leaks in the snmp extension (Closes: #423296) + - Thanks to Rodrigo Campos for the follow up + - Thanks to Federico Cuello for the original patch + * php5-dev.lintian-override: fix it so it actually works + + -- Sean Finney Sun, 14 Sep 2008 14:25:11 +0200 + +php5 (5.2.6-3) unstable; urgency=high + + [ Thijs Kinkhorst ] + * Drop unneeded php5-timezonedb Suggests and obsolete php3 Conflicts. + * Add documentation about the timezonedb change (Closes: #492025). + + [ Adam Conrad ] + * Modify 033-we_WANT_libtool.patch to cope with newer versions of + libtool that only copy auxilliary files when --install is used, + while still working with older versions that DTRT without. + + [ Raphael Geissert ] + * debian/rules: + + Avoid installing useless test suites in php-pear (Closes: #478995) + + Remove any empty directory in php-pear + + Also get rid of usr/share/php/data/Structures_Graph/* + - Those were meant to be used by upstream maintainer + * debian/php5-dev.lintian-overrides: + - usr/lib/php5/build/run-tests.php is not meant to be used directly + * debian/control: bumped Standards Version to 3.8.0, no changes needed + * bad_whatis_entries.patch: fixes the whatis entries of all the manpages + * deprecated_freetds_check.patch: fixes the freetds detection routine + + Closes: #494230 + - Thanks to jklowden@freetds.org and the Gentoo folks for the patch + (RC bugfix, upload urgency bumped) + * debian/libapache2-mod-php5*-{prerm,postinst}: + - Create a status file when removing the package (but not purging) + while having the mod enabled so reinstallation of the package + does not end up disabling the module (Closes: #471548) + + [ Sean Finney ] + * Bump dependency on libmysqlclient15off to require the version from + lenny or later, in order to avoid subtle problems not previously detected + with libmysqlclient_r on mixed etch/lenny/sid systems (closes: #495575). + + -- Sean Finney Wed, 20 Aug 2008 19:32:02 +0200 + +php5 (5.2.6-2ubuntu5) jaunty; urgency=low + + * Configure with --build=$(DEB_BUILD_GNU_TYPE) --host=$(DEB_HOST_GNU_TYPE) + to fix a build failure on armel. + + -- Matthias Klose Thu, 20 Nov 2008 14:17:24 +0000 + +php5 (5.2.6-2ubuntu4) intrepid; urgency=low + + * debian/patches/fix-pecl-libtool.dpatch: fix libtool brokenness + with pecl. (LP: #262251) + + -- Chuck Short Tue, 14 Oct 2008 15:16:36 -0400 + +php5 (5.2.6-2ubuntu3) intrepid; urgency=low + + * debian/rules: Point /usr/lib/php5/build/{libtool.m4, ltmain.sh} + to the right locations. + + -- Chuck Short Wed, 20 Aug 2008 11:23:46 -0400 + +php5 (5.2.6-2ubuntu2) intrepid; urgency=low + + * Revert to using upstream's bundled libtool for now, until either upstream + moves to libtool 2.x, or Debian/Ubuntu have the time to rewrite some m4. + * Manually copy autotools-dev's versions of config.{sub,guess}, since we + no longer have libtoolize doing it for us, thanks to the above change. + * Fix libedit_is_editline.patch to patch sap/cli/php_cli* too (LP: 249800) + * Include patch from Debian (deprecated_freetds_check.patch) to fix FTBFS + with more recent versions of FreeTDS. + + -- Adam Conrad Tue, 12 Aug 2008 14:01:15 -0600 + +php5 (5.2.6-2ubuntu1) intrepid; urgency=low + + * Merge from debian unstable, remaining changes: + - debin/control, debian/rules: Disable a few build dependencies and + accompanying binary pckages which we do not want to support in main: + + freebird2-dev/php5-interbase (we have a seperate php-interbase source) + + libc-client-dev/php5-imap (we have a seperate php-imap source) + + libmcrypt-dev/php5-mcrypt (seperate php-mcrypt source) + + readline support again, now that the libedit issue is fixed. + - debian/control: Add build dependency: libedit-dev (>= 2.9.cvs.20050518-1) + CLI readline support + - debian/rules: + + Correctly mangle PHP5_* macros for lpia + - debian/patches/use-specific-libdb-version.patch (LP: #165247), mangle + version ordering in patch to match code for clean application. + - debian/patches/119-sybase-alias.patch: + + Fix sybase regression since change to msqql. (LP: #240519) + - debian/control: Use libdb-4.6-dev + + -- Chuck Short Thu, 17 Jul 2008 15:16:15 +0100 + +php5 (5.2.6-2) unstable; urgency=high + + [ Raphael Geissert ] + * Lintian-based changes: + - also install a lintian override for libapache2-mod-php5filter + - fixed the generic lintian overrides so they are meaningful + - dropping linda overrides, linda is gone now + - s/meta-package/metapackage + * debian/control: + - Updated php5's description so it mentions three instead of + only two server-side SAPIs + - Depend on php5-cli in php-pear (Closes: #482517) + + Previous change reverted because of PEAR packages FTBFS + - {B-,}Depend on tzdata to avoid crashes caused by the tz ext patch + - Dropped some versioned {b-,}dependencies that are satisified + even on sarge + * php.ini-*: state that when using a custom save_path, + gc_probability should also be set (Closes: #388808, #321460) + * tzdb-nofree_ents_ifnotzdata.patch: avoid free'ing ents when the tz dir does + not exist (Closes: #483461) + + [ Sean Finney ] + * Fix for CVE-2008-2829: unsafe usage of deprecated imap functions + Patch: CVE-2008-2829.patch + * Modifications to suhosin.patch due to alignment problems on some + architectures. Thanks to Stefan Esser for the initial suggestion. + (Closes: #481737). + * Rename the apache2 filter module to libphp5filter.so, to prevent + conflicting filenames for symbols in the debug package. + + -- Sean Finney Thu, 03 Jul 2008 08:14:45 +0200 + +php5 (5.2.6-1ubuntu4) intrepid; urgency=low + + * debian/patches/119-sybase-alias.patch: + - Update patch fixes FTBFS. + + -- Chuck Short Fri, 20 Jun 2008 14:07:29 +0000 + +php5 (5.2.6-1ubuntu3) intrepid; urgency=low + + * debian/control: Use libdb4.6-dev. + * debian/patches/119-sybase-alias.patch: + - Fix sybase regression since change to mssql. (LP: #240519) + + -- Chuck Short Thu, 19 Jun 2008 18:52:29 +0000 + +php5 (5.2.6-1ubuntu1) intrepid; urgency=low + + * Merge from Debian unstable. Remaining Ubuntu changes: + - debian/control, debian/rules: Disable a few build dependencies and + accompanying binary packages which we do not want to support in main: + + firebird2-dev/php5-interbase (we have a separate php-interbase source) + + libc-client-dev/php5-imap (we have a separate php-imap source) + + libmcrypt-dev/php5-mcrypt (separate php-mcrypt source) + + readline support again, now that the libedit issue is fixed. + - debian/control: Add build dependency: libedit-dev (>= 2.9.cvs.20050518-1) + CLI readline support + - debian/rules: + + Correctly mangle PHP5_* macros for lpia + - debian/patches/use-specific-libdb-version.patch (LP: #165247), mangle + version ordering in patch to match code for clean application + * Accepted into Debian + - debian/patches/027-readline_is_editline.patch (LP: #124846), patch + indexes bumped up to 5.2.6 + * Dropped changes: + - debian/rules: + + use 32M memory_limit for CLI and 16M for cgi/libapache (LP: #148871) + - debian/patches/fix_64bit_time.patch (LP: #194318), upstream + * New Ubuntu changes: + - main/php_version.h: updated with 5.2.6-1 Ubuntu version info + + -- Dustin Kirkland Tue, 27 May 2008 09:22:58 -0500 + +php5 (5.2.6-1) unstable; urgency=medium + + * New upstream release. Fixes several security issues of unknown impact: + + possible stack buffer overflow in the FastCGI SAPI + + integer overflow in printf() + + unknown issue CVE-2008-0599 + + a safe_mode bypass in cURL + + incomplete multibyte chars inside escapeshellcmd() + + [ Sean Finney ] + * New patch (use_embedded_timezonedb.patch) allows us to default to + using the system provided timezone database instead of the one bundled + with PHP. Many thanks to Joe Orten from Red Hat for the patch! + (closes: #447174, #471104). + * Updated the Suhosin patch to v0.9.6 (5.2.6). + * New patch: force_libmysqlclient_r.patch, forcing the build system + to link against the threadsafe libmysqlclient without having to enable + the other zts features in php. This is required since the apr libraries + are now linking against this as well and mysql exports the same symbols + from both libraries. Thanks to Stefan Fritsch (closes: #469081). + * Massaged/updated various other patches in debian/patches + * Update copyright information to have information about non-trivial + patches worthy of copyright attributions, and update information about + current debian maintainers. + * Add some useful quilt settings in debian/rules to lower the amount of + noise in future quilt updates. + * Now building a php5 apache2 module with filter-module support in a new + libapache2-mod-php5filter package (closes: #438120). + + [ Thijs Kinkhorst ] + * Checked for policy 3.7.3, no changes. + + [ Raphael Geissert ] + * Build a php5-dbg package with the debug symbols of the SAPIs & extensions + + Bump debhelper dependency to >= 5 as dh_strip behaves differently. + * debian/watch: refactored so it can actually be used to download the tarball + * debian/rules: removed bashisms (Closes: #478613) + * debian/control: add a notice about Suhosin being applied (Closes: #471324) + + Additionally make sure the PHP boilerplate is the same for each package + * debian/patches/manpage_spelling.patch: + - fix spelling mistakes in man page (Closes: #413712) + * debian/NEWS: s/suhosin/Suhosin (Closes: #434351) + * debian/control: removed ORed postgresql-dev build-dep (Closes: #429981) + + postgresql-dev is a transitional package since etch + * Override the following lintian messages: + + SAPI packages package-contains-empty-directory usr/lib/php5/20060613+lfs/ + + php5-common package-contains-empty-directory usr/lib/php5/libexec/ + * Set our custom PHP_PEAR_DOWNLOAD_DIR when building the pear stuff + + Avoids the creation of /tmp/pear (Closes: #463979) + * Replaced all 'make' with '$(MAKE)' so any extra flag is preserved + * debian/rules: s/DEB_BUILD_ARCH/DEB_HOST_ARCH + + HOST is the machine the package is built for. + * Recommend php5-cli instead of depending on it in php-pear (Closes: #243214) + + php5-cli is only needed by the, rearely used, pear installer + * debian/README.source: inform how to generate php5-dbg's Depends + * debian/patches/029-php.ini_paranoid.patch: updated (Closes: #459814) + + Thanks to Javier Fernández-Sanguino Peña + Changes: + - includes some variables which were no present in the first version and + removes modules not available in PHP5. Also fixes typos in comments which + have since been fixed in php.ini-dist + - adds notes (Debian-specific) of which security features applications + should not rely on + - add more information of why some variables were enabled + - reorder the description of changes to suit the location in the config file + - add notes of deprecated features in PHP6 + - add more (suggested) changes to the session module to make a more secure + use and storage of session IDs. + - remove the 'include' function from the list of disabled functions as it + is quite common for most applications + - modify the valid 'include_path' to make it really paranoid ('.' is not + allowed anymore) + - adjust locations of directories, including the upload dir and session dir + - proper definition for sql.safe_mode and description (missing in + php.ini-dist of what it is really for) + - added session configuration variables which are not available in + php.ini-dist together with recommended paranoid values + (session.referer_check, session.entropy_file, session.entropy_length) + - added more information to session configuration (not available in php.ini) + based on the information at php.net + * Lintian-based changes: + - debian/php5-common.dirs: do NOT create usr/share/doc/php5-common/PEAR/ + - fixed a hyphen-used-as-minus-sign in php5(1):319 + - get rid of usr/share/php/data/Structures_Graph/LICENSE in php-pear + * Move /usr/share/php/docs to /usr/share/doc/pear-php/PEAR (Closes: #331034) + + [ Steve Langasek ] + * Step down from the PHP maintenance team, removing myself from uploaders. + So long, and thanks for all the fish! + + -- Sean Finney Sun, 04 May 2008 21:15:47 +0200 + +php5 (5.2.5-3ubuntu1) intrepid; urgency=low + + * Merge from Debian unstable. Remaining Ubuntu changes: + - debian/control, debian/rules: Disable a few build dependencies and + accompanying binary packages which we do not want to support in main: + + firebird2-dev/php5-interbase (we have a separate php-interbase source) + + libc-client-dev/php5-imap (we have a separate php-imap source) + + libmcrypt-dev/php5-mcrypt (separate php-mcrypt source) + + readline support again, now that the libedit issue is fixed. + - debian/control: Add build dependency: libedit-dev (>= 2.9.cvs.20050518-1) + CLI readline support + - debian/rules: + + Correctly mangle PHP5_* macros for lpia + + use 32M memory_limit for CLI and 16M for cgi/libapache (LP: #148871) + - debian/patches/027-readline_is_editline.patch (LP: #124846) + - debian/patches/use-specific-libdb-version.patch (LP: #165247) + * New Ubuntu changes: + - debian/patches/fix_64bit_time.patch (LP: #194318) + - debian/patches/use-specific-libdb-version.patch (LP: #165247), + updated patch to match change in ordering of db versions + - main/php_version.h: updated with 5.2.5-3 Ubuntu version info + + -- Dustin Kirkland Tue, 06 May 2008 10:24:33 -0500 + +php5 (5.2.5-3) unstable; urgency=high + + * zend_parse_parameters does not handle size_t's, causing issues with + 043-recode_size_t.patch and segmentation faults for recode-using pages. + changed problematic parameters back to "int" and added an overflow check. + thanks to Thomas Stegbauer, Tim Dijkstra, Bart Cortooms, Sebastian Göbel, + and Vincent Tondellier for their reports. closes: #459020. + + -- Sean Finney Thu, 21 Feb 2008 00:59:21 +0100 + +php5 (5.2.5-2) unstable; urgency=low + + * debian/patches/libdb_is_-ldb: reorder the search for db4 instances to + give precedence to -ldb, so that we always get the version that matches + the installed -dev package instead of whichever most recent version php + upstream currently knows about. Closes: #463397. + * Update suhosin patch to not patch .dsp files (and config.w32), which + are irrelevant to Unix builds and seem to cause problems for clean + patching/unpatching. + + -- Steve Langasek Fri, 01 Feb 2008 18:46:15 +0000 + +php5 (5.2.5-1) unstable; urgency=low + + [ Sean Finney ] + * New upstream release + * Updated suhosin patch for 5.2.5 minus ./configure as before. + * Workaround for xargs not handling extra long cmdlines in session + cleanup script (Closes: #461755). + * Remove unneccesary DEB_BUILD_GNU_TYPE fudging (Closes: #429066). Thanks + to Riku Voipio for the report/patch. + + [ Raphael Geissert ] + * debian/rules: now DEB_BUILD_OPTIONS=nocheck aware + * Updated description of the php5 meta-package to reflect removal of apache + (Closes: #418038) + * Capitalise apache where needed (Closes: #439575) + * Homepage is now a control entry (moved from Description), Closes: #439578 + * Fixed test-results.txt target so parallel package building doesn't fail + * Added Suggests: php5-timezonedb to all the SAPIs + + [ Steve Langasek ] + * Add ${shlibs:Depends} to php5-common, since it does build ELF objects now + (pdo.so) + * Update build-deps to libdb4.6-dev now that libaprutil1-dev has switched. + Closes: #461192. + + -- Steve Langasek Thu, 17 Jan 2008 13:39:17 -0800 + +php5 (5.2.4-2ubuntu5) hardy; urgency=low + + * fixes strtotime support for 64 bit timestamps (LP: #194318) + - Upstream: http://bugs.php.net/bug.php?id=44209 + * Update tests to account for newly working timestamps + - Upstream: http://bugs.php.net/?id=44219 + + -- Dustin Kirkland Wed, 27 Feb 2008 13:00:18 -0500 + +php5 (5.2.4-2ubuntu4) hardy; urgency=low + + * No-change rebuild against libldap-2.4-2. + + -- Steve Langasek Fri, 25 Jan 2008 14:19:57 +0000 + +php5 (5.2.4-2ubuntu3) hardy; urgency=low + + * Rebuild again, some build dependency still pulled in db4.5 last time. + + -- Martin Pitt Fri, 04 Jan 2008 08:45:05 +0100 + +php5 (5.2.4-2ubuntu2) hardy; urgency=low + + * debian/patches/use-specific-libdb-version.patch: Support db4.6, too. + * debian/control: Build against db4.6. + + -- Martin Pitt Thu, 03 Jan 2008 11:13:25 +0100 + +php5 (5.2.4-2ubuntu1) hardy; urgency=low + + * Merge from Debian unstable (LP: #176011). Remaining Ubuntu changes: + - debian/control, debian/rules: Disable a few build dependencies and + accompanying binary packages which we do not want to support in main: + + firebird2-dev/php5-interbase (we have a separate php-interbase source) + + libc-client-dev/php5-imap (we have a separate php-imap source) + + libmcrypt-dev/php5-mcrypt (separate php-mcrypt source) + - debian/rules: Correctly mangle PHP5_* macros for lpia + - debian/control: DebianMaintainerField + * Builds php5-gmp (LP: #176013) + * Fixes sybase_ct for MS SQL (LP: #21995) + * New Ubuntu changes: + - debian/rules: use 32M memory_limit for CLI and 16M for cgi/libapache + (LP: #148871) + - debian/control, debian/rules: Configure CLI with --with-libedit for + readline support again, now that the libedit issue is fixed. + Extended debian/patches/027-readline_is_editline.patch (LP: #124846) + - Force build against db4.4 (by ignoring db4.5 if it is installed), + debian/patches/use-specific-libdb-version.patch (LP: #165247) + + -- dAniel hAhler Wed, 19 Dec 2007 10:48:04 +0100 + +php5 (5.2.4-2) unstable; urgency=low + + [ sean finney ] + * for posterity revised previous changelog to reference the CVE id's + of security issues resolved by the latest upstream release. + * lintian: use debian/compat instead of DH_COMPAT in debian/rules. + * lintian: use source:Version and binary:Version where appropriate, + instead of Source-Version + * lintian: remove a couple pieces of cruft in the changelog that were causing + false-postive wrong-bug-number-in-closes, but were generally useless + anyway. + + [ Raphael Geissert ] + * Using test-results.txt as a target + * cronjob now checks for existance of /usr/lib/php5/maxlifetime (Closes: #439286) + * Fixed memory limit of 1232M in php.ini for cli (Closes: #440624) + * Build the interbase extension using firebird2.0-dev (Closes: #433736) + * Unapply patches with debian/rules clean + + [ Steve Langasek ] + * Don't patch configure or php_config.h.in in suhosin.patch, as these are + auto-generated and including them in the patch results in a race + condition for the necessary build-time regeneration. Thanks to Daniel + Schepler for reporting, and to Damyan Ivanov for helping to sort out the + fix. Closes: #443637. + * Also remove the modified auto-generated files in the clean target, + which triggers a warning about disappearing files when building the + source package but avoids carrying irrelevant diffs to these files + in the Debian diff. + * Now that the testsuite is being run at build time, test failures cause + a bunch of junk files to be left around in the Debian diff. So clean up + several false-positive failures: + - 052-phpinfo_no_configure.patch: we're patching the output of phpinfo(), + so patch the test as well + - fix_broken_upstream_tests.patch: use a local directory for tests that + use sessions, skip the phpinfo test after all because it doesn't appear + to be compatible with current testsuite behavior, and disable the + moneyformat test if en_US locale is not available. + There are still several other failing tests, but these are not false + positives and remain enabled pending investigation. + + -- sean finney Wed, 24 Oct 2007 21:51:14 +0200 + +php5 (5.2.4-1) unstable; urgency=low + + * New upstream release. + * Security issues resolved in the latest release: + - CVE-2007-2519 - Directory traversal vulnerability in PEAR + + + [ sean finney ] + * patch from Jan Wagner to be able to conditionally disable any + patches that break binary-compatibility with official php + binary-only extensions. see debian/rules for more information. + * now incorporate the php unit tests into the build process. for + those interested the output is stored in the file + /usr/share/doc/php5-common/test-results.txt . + * by default we now ship with enable_dl = Off, as there are some + fairly significant ramifications security-wise to having it on. + * we shipping with the suhosin patch enabled by default. + special thanks to Blars Blarson for providing a sparc machine for + testing purposes with 5.2.3 (closes: #397179). + * new binary package php5-gmp, with the newly enabled gmp extension, + since whatever reason for not doing so either never existed or no + no longer exists (closes: #344137). Build-Depends added for libgmp3-dev. + + [ Steve Langasek ] + * php5-module.postinst: don't assume that the postinst is only relevant + when called with 'configure' as an argument, some future debhelper code + could apply in the case of other methods of invocation. + * Clean up build dependencies for recent library transitions: + - libsnmp-dev is now the real package name, and is supported as a virtual + package for backports. + - re-add firebird2-dev as an alternative to firebird1.5-dev, to support + backports. + - the curl -dev package name has changed from libcurl3-openssl-dev to + libcurl4-openssl-dev; update to the proper name, with libcurl-dev as + an alternative. + * Switch php5-sybase to use the mssql extension instead of the sybase_ct + extension. Closes: #418734, #329065. + + -- sean finney Sun, 16 Sep 2007 14:46:06 +0200 + +php5 (5.2.3-1ubuntu7) hardy; urgency=low + + * Rebuild for libsnmp10 -> libsnmp15 transition. + + -- Steve Kowalik Mon, 10 Dec 2007 20:33:11 +1100 + +php5 (5.2.3-1ubuntu6) gutsy; urgency=low + + * Trigger rebuild for hppa + + -- LaMont Jones Thu, 04 Oct 2007 12:18:16 -0600 + +php5 (5.2.3-1ubuntu5) gutsy; urgency=low + + * debian/rules: + - Fix broken memory_limit mangling for php5-cli. (LP: #109079) + - Don't clean out debian/copyright. (iz soyuz bug..) + * debian/php5-cli.postinst, debian/rules: + - Use same php.ini-dist for all flavours. The only difference used to be + cli having a higher memory_limit value, but upstream has changed this to + 128MB, which is higher than both of the previous values. + + -- Soren Hansen Mon, 03 Sep 2007 08:51:34 +0200 + +php5 (5.2.3-1ubuntu4) gutsy; urgency=low + + * debian/rules: Correctly mangle PHP5_* macros for lpia. + + -- Matthias Klose Fri, 10 Aug 2007 08:20:08 +0000 + +php5 (5.2.3-1ubuntu2) gutsy; urgency=low + + * Rebuild for the libcurl transition mess. + + -- Steve Kowalik Thu, 5 Jul 2007 00:12:51 +1000 + +php5 (5.2.3-1ubuntu1) gutsy; urgency=low + + * Merge from debian unstable, remaining changes: + - debian/changelog: Add some missing CVEs. + - debian/control: DebianMaintainerField + - debian/control, debian/rules: Disable a few build dependencies and + accompanying binary packages which we do not want to support in main: + + firebird2-dev/php5-interbase (we have a separate php-interbase source) + + libc-client-dev/php5-imap (we have a separate php-imap source) + + libmcrypt-dev/php5-mcrypt (separate php-mcrypt source) + + -- Soren Hansen Mon, 11 Jun 2007 20:32:54 +0200 + +php5 (5.2.3-1) unstable; urgency=low + + * new upstream release. + * upstream has incorporated the last of the recent CVE fixes, so + the patches have been removed. + * change build dependencies for firebird2-dev -> firebird1.5-dev, + as the firebird maintainer has changed names in order to provide + more clarity since there's also a firebird2.0 now (closes: #427181). + * now include, but do not apply by default, the suhosin patch. see + NEWS.Debian for more information. + + -- sean finney Mon, 04 Jun 2007 22:02:10 +0200 + +php5 (5.2.2-2) unstable; urgency=low + + [sean finney] + - build with --with-ldap-sasl and modify build-depends to include + libsasl2-dev in order to get the ldap_sasl_bind function (closes: #422490). + - the json extension is now on by default in php builds, so there's + no need for the php5-json package. added a Provides/Conflicts to + help set an upgrade path. + - apache 1.x support is soon disappearing. as a consequence we are + no longer building the libapache-mod-php5 module. the php5 metapackage + should as a result bring in libapache2-mod-php5 by default for those who + already have it installed. + + -- sean finney Sun, 20 May 2007 21:59:56 +0200 + +php5 (5.2.2-1ubuntu1) gutsy; urgency=low + + * Merge to Debian unstable; remaining Ubuntu changes: + - debian/changelog: Add some missing CVEs. + - debian/control, debian/rules: Disable a few build dependencies and + accompanying binary packages which we do not want to support in main: + + apache-dev/libapache-mod-php5 (die, Apache 1, die!) + + firebird2-dev/php5-interbase (we have a separate php-interbase source) + + libc-client-dev/php5-imap (we have a separate php-imap source) + + libmcrypt-dev/php5-mcrypt (separate php-mcrypt source) + - Add missing libsqlite3-dev build dependency. + + -- Martin Pitt Tue, 15 May 2007 16:15:43 +0200 + +php5 (5.2.2-1) unstable; urgency=low + + [ sean finney ] + * new upstream release (closes: #422405). + * /most/ of the previous CVE patches have been committed upstream, though: + - the patch for MOPB-41 was fixed in a different way and we'll be keeping + our fix for the time being. + - it doesn't seem like MOPB-45 has been fixed yet. + * remove build-dependency option on libmysqlclient12-dev, since the mysqli + option requires it, and 15 is in stable now anyway. thanks to + Henk van de kamer for finding this (closes: #422224). + * now includes requested fix for mysql row counts (closes: #418471). + * needle/haystack issues are reported fixed (closes: #399924). + * oh yeah, because we're using quilt now: (closes: #338315). + * update build-deps to libdb4.5-dev | libdb4.4-dev (closes: #421929). + note that the resulting php packages won't actually build against + libdb4.5 until all of our build-dependant packages do too. + + -- sean finney Sat, 05 May 2007 19:56:30 +0200 + +php5 (5.2.0-12) unstable; urgency=high + + [ sean finney ] + * modify the build-depends to play more nicely when the net-snmp + maintainers decide to change their package names (closes: #421061). + + -- sean finney Tue, 01 May 2007 14:24:01 +0200 + +php5 (5.2.0-11) unstable; urgency=high + + [ sean finney ] + * The following security issues are addressed with this update: + - CVE-2007-0910/MOPB-32 session_decode() Double Free Vulnerability + * note that this is an update to the previous version of the upstream + fix for CVE-2007-0910, which introduced a seperate exploit path. + - CVE-2007-1286/MOPB-04 unserialize() ZVAL Reference Counter Overflow + - CVE-2007-1380/MOPB-10 php_binary Session Deserialization Information Leak + - CVE-2007-1375/MOPB-14 substr_compare() Information Leak Vulnerability + - CVE-2007-1376/MOPB-15 shmop Functions Resource Verification Vulnerability + - CVE-2007-1453/MOPB-18 ext/filter HTML Tag Stripping Bypass Vulnerability + - CVE-2007-1453/MOPB-19 ext/filter Space Trimming Buffer Underflow Vuln. + - CVE-2007-1521/MOPB-22 session_regenerate_id() Double Free Vulnerability + - CVE-2007-1583/MOPB-26 mb_parse_str() register_globals Activation Vuln. + - CVE-2007-1700/MOPB-30 _SESSION unset() Vulnerability + - CVE-2007-1718/MOPB-34 mail() Header Injection + - CVE-2007-1777/MOPB-35 zip_entry_read() Integer Overflow Vulnerability + - CVE-2007-1887-1888/MOPB-41 sqlite_udf_decode_binary() Buffer Overflow + - CVE-2007-1824/MOPB-42 php_stream_filter_create() Off By One Vulnerablity + - CVE-2007-1889/MOPB-44 Memory Manager Signed Comparision Vulnerability + - CVE-2007-1900/MOPB-45 ext/filter Email Validation Vulnerability + * The other security issues resulting from the "Month of PHP bugs" either + did not affect the version of php5 shipped in unstable, or did not merit + a security update according to the established security policy for php + in debian. You are encouraged to verify that your configuration is not + affected by any of the other vulnerabilities by visiting: + http://www.php-security.org/ + * other, less interesting changes: + - now use quilt for managing local patches. + - massage all of the patches, eliminating fuzz and offsets. + + -- sean finney Mon, 23 Apr 2007 19:02:51 +0200 + +php5 (5.2.0-10) unstable; urgency=high + + [ sean finney ] + * The php security update contained a regression in the streams + module. this version contains an updated version of the patch + for CVE-2007-0906 (116-CVE-2007-0906_streams.patch), which should + fix the regression. Thanks to Martin Pitt for noticing this. + * Fix the patch names in the previous changelog entry, and fix a factual + inaccuracy that was accidentally pasted from the php4 changelog. + * The previous update was missing two fixes from CVE-2007-0906: + * interbase: (116-CVE-2007-0906_interbase.patch) + * zip: (116-CVE-2007-0906_zip.patch) + + -- sean finney Wed, 07 Mar 2007 23:11:29 +0100 + +php5 (5.2.0-9) unstable; urgency=high + + [ sean finney ] + * The following security issues are addressed with this update: + - CVE-2007-0906: Multiple buffer overflows in various code: + * session (116-CVE-2007-0906_session.patch) + * imap (116-CVE-2007-0906_imap.patch) + * str_replace: (116-CVE-2007-0906_string.patch) + * the sqlite and mail related vulnerabilities in this CVE do not + affect the php5 source packages. + - CVE-2007-0907: sapi_header_op buffer underflow (116-CVE-2007-0907.patch) + - CVE-2007-0908: wddx information disclosure (116-CVE-2007-0908.patch) + - CVE-2007-0909: More buffer overflows: + * the odbc_result_all function (116-CVE-2007-0909_odbc.patch) + * various formatted print functions (116-CVE-2007-0909_print.patch) + - CVE-2007-0910: Clobbering of super-globals (116-CVE-2007-0910.patch) + - CVE-2007-0988: 64bit unserialize DoS (116-CVE-2007-0988.patch) + Closes: #410995. + * The package maintainers would like to thank Joe Orton from redhat and + Martin Pitt from ubuntu for their help in preparation of this update. + * backport upstream fix for AUTH PLAIN support in imap extension + Closes: #401712. + + -- sean finney Sat, 03 Mar 2007 11:13:33 +0100 + +php5 (5.2.0-8) unstable; urgency=high + + [ sean finney ] + * Update package information to say simply "Apache 2" instead + of "Apache 2.0" (ref: #400306). + * Update package description for php-pear to mention needing + phpN-dev for building PECL extensions (closes: #401825). + * Add mention of Freetype fonts to php5-gd package description, + thanks to Ole Laursen for the suggestion (closes: #387881). + * Include a backported version of upstream's fix for + alignment calculatations which cause FTBFS problems for + some arches. Thanks to Roman Zippel for finding this (closes: #401129). + patch: 114-zend_alloc.c_m68k_alignment.patch + * Remove --enable-yp, as it's no longer used and seperately + packaged. Thanks to Martijn Grendelman for mentioning this + (closes: #402161). + * Add mention to README.Debian of needing to restart apache when + installing modules (closes: #392249). + * Don't strip the DSO modules if building with DEB_BUILD_OPTIONS + containing nostrip + * Backported a patch from upstream CVS to fix a rather nasty + memory leak in zend_alloc (closes: #402506). + patch: 115-zend_alloc.c_memleak.patch + * The memleak and FTBFS are targeted at etch, and there aren't + any other significant changes, so priority=high. + + -- sean finney Sun, 17 Dec 2006 16:49:35 +0100 + +php5 (5.2.0-7ubuntu2) feisty; urgency=low + + * debian/control: Add missing build dependency libsqlite3-dev to fix FTBFS. + + -- Martin Pitt Wed, 6 Dec 2006 16:27:03 +0100 + +php5 (5.2.0-7ubuntu1) feisty; urgency=low + + * Merge to Debian unstable; remaining Ubuntu changes: + - debian/control, debian/rules: Disable apache-dev build dependency and + remove libapache-mod-php5 package, since we do not support apache 1.3. + - debian/control: Build with db4.3, as long as our apache needs it. + - debian/changelog: Add some missing CVEs. + * debian/control: + - Remove firebird2-dev build dependency and php5-interbase package, since + we don't support Firebird and keep the separate php-interbase source. + - Remove libc-client-dev build dependency and php5-imap package, since + uw-imapd is in universe and we keep the separate php-imap source. + - Remove libmcrypt-dev build dependency and php5-mcrypt package, since + it is in universe and we keep the separate php-mcrypt source. + - libapr1-dev -> libapr0-dev, as long as we still have Apache 2.0. + * debian/rules: Disable above modules, and fix up dependency generation for + Apache 2.0 instead of 2.2. + + -- Martin Pitt Wed, 6 Dec 2006 12:55:44 +0100 + +php5 (5.2.0-7) unstable; urgency=high + + [ Steve Langasek ] + * Also disable firebird in the PDO config for archs other than + i386/amd64. + + -- sean finney Fri, 24 Nov 2006 15:20:53 +0100 + +php5 (5.2.0-6) unstable; urgency=high + + [ sean finney ] + * firebird2-dev (and thus php5-interbase) is only available on + i386/amd64, so update the control/rules information accordingly. + thanks to Bastian Blank for reporting this (closes: #399558). + + -- sean finney Wed, 22 Nov 2006 19:04:04 +0100 + +php5 (5.2.0-5) unstable; urgency=high + + [ sean finney ] + * bring some of the mainline php4 modules back into the php source + package instead of distributing them in independant source packages: + - php5-imap + - php5-interbase + - php5-mcrypt + - php5-pspell + - php5-tidy + these modules are still provided in the same binary packages as + before, but will now be built in tandem with the core php packages. + * fix for pdo.so duplicate loading warnings, thanks to Jan Wagner + (closes: #398367, #399248). + + -- sean finney Mon, 20 Nov 2006 12:41:37 +0100 + +php5 (5.2.0-4) unstable; urgency=high + + * Re-re-enable LFS support, forward-porting vorlon's fixes in + the php4 tree. + * Add a bit of support in upgrade scripts to avoid unnecessary + ucf prompting during upgrades (closes: #398363). + * Update build-dependencies to reflect that libpcre3-dev >= 6.6 + is required. Thanks to Jan Wagner for pointing this out. + * loosen dependencys for libapache2-mod-php5 to allow usage with + apache2-mpm-itk as an alternative to prefork. + Closes: #398580, #398481. + + -- sean finney Wed, 15 Nov 2006 08:33:28 +0100 + +php5 (5.2.0-3) unstable; urgency=high + + * Unify PHP options for pear binaries to: + -d output_buffering=1 -d open_basedir="" -d safe_mode=0 -d memory_limit="-1" + (Closes: #397625) + * [debian/rules]: Enable PDO building only in apache2 build. + + -- Ondřej Surý Fri, 10 Nov 2006 14:09:00 +0100 + +php5 (5.2.0-2) unstable; urgency=high + + [ Ondřej Surý ] + * Revert Large File Support for this moment. We will try to found + root of the problem for etch, but we do not promise anything. + (Closes: #397465) + + -- Ondřej Surý Wed, 8 Nov 2006 01:13:48 +0100 + +php5 (5.2.0-1) unstable; urgency=high + + [ sean finney ] + * new upstream release. since this means the 5.1 series is deadware + in the eyes of its developers, we better get on this train before + it's too late. Note: this also fixes the htmlentities() exploit. + Reference: CVE-2006-5465. + Closes: #396766. + * s/postinst/postrm/ on one critical line in debian/rules. whoops. + Thanks to Bart Martens for finding this (closes: #396873). + * as a pennance i've enabled LFS support (closes: #359686). + * new version now includes all mbstring headers (closes: #391368). + * enable new built-in zip support. + * enable pdo support for currently supported db types, and place the + extensions in the respective extension packages. future db + types will be added, but probably post-etch as they will probably + introduce new packages/dependencies (closes: #348882). + * move the mysqli module into the mysql module's package, and remove + the no longer necessary mysqli package. + * massaging/removal of various patches to upstream changes: + D patches/106-strptime_xopen.patch + D patches/110-CVE-2006-4812_zend_alloc.patch + M patches/006-debian_quirks.patch + D patches/111-mbstring-headers.patch + M patches/053-extension_api.patch + + [ Ondřej Surý ] + * Package checked, upload to unstable. + + -- Ondřej Surý Tue, 7 Nov 2006 09:26:51 +0100 + +php5 (5.1.6-6) unstable; urgency=high + + [ sean finney ] + * add notes to php.ini(-dist) about "unsupported" security features. + patch: 113-php.ini_securitynotes.patch + + [ Ondřej Surý ] + * SECURITY: include patch for html buffer overflows in ext/standard/html.c + Reference: CVE-2006-5465 + Patch: 114-CVE-2006-5465_htmlentities.patch + Closes: #396766 + + -- Ondřej Surý Fri, 3 Nov 2006 12:32:50 +0100 + +php5 (5.1.6-5) unstable; urgency=high + + [sean finney] + * add a README.Debian.security to clarify how we handle/respond + to security problems in stable releases. + * SECURITY: include patch for integer overflow in zend_alloc.c. + Reference: CVE-2006-04812 (closes: #391586). + patch: 110-CVE-2006-4812_zend_alloc.patch + * bump the debhelper compatibility level to 4. + * remove cyclic depends for mysql/mysqli. + * the long overdue rework of configuration file handling. this also + removes the need for debconf and template translations + (closes: #361211, #393788, #388697). + * start using ucf to manage the the various SAPI php.ini files. + * cleanup and consolidation of a few things in the ./debian dir + * bump the memory limit to 32M for the cli API (closes: #375070, #340586). + * include a fix for missing mbstring headers reported by Jan Wagner + (closes: #391368). + patch: 111-mbstring-headers.patch. + * include support for PTY's in proc_open, as reported by Eike Dehling. + according to php's BTS (http://bugs.php.net/bug.php?id=39224) the + feature was disabled only because the configure script couldn't + accurately determine whether the feature was available, and we know + it is :) (closes: #381438). + patch: 112-proc_open.patch. + * update standards-version to 3.7.2 + + -- sean finney Sat, 28 Oct 2006 14:29:44 +0200 + +php5 (5.1.6-4) unstable; urgency=high + + [sean finney] + * no longer build against GPL'd gdbm library (closes: #390452). + * updated apache2 module dependencies to build against and coexist + with apache2.2 (closes: #390455). + + -- sean finney Sat, 07 Oct 2006 12:06:09 +0200 + +php5 (5.1.6-3) unstable; urgency=low + + [ sean finney ] + * php5 was building against db4.3 even though db4.4 headers were + installed. fix applied to ./ext/dba/config.m4 while we wait + for a real fix from upstream (closes: #388601). + + -- sean finney Mon, 02 Oct 2006 17:42:50 +0200 + +php5 (5.1.6-2) unstable; urgency=low + + [ sean finney ] + * enable the mysqli extension (closes: #320835). + + -- sean finney Tue, 19 Sep 2006 19:31:27 +0200 + +php5 (5.1.6-1ubuntu3) feisty; urgency=low + + * Rebuild for ldbl128 change on powerpc and sparc. + + -- Matthias Klose Thu, 2 Nov 2006 10:00:32 +0000 + +php5 (5.1.6-1ubuntu2) edgy; urgency=low + + * SECURITY UPDATE: Safe mode bypass, remote arbitrary code execution. + * Fix/add CVE numbers in/to 5.1.4-0.1 and 5.1.6-1 changelogs. + * Add debian/patches/CVE-2006-4625.patch: + - Fix open_basedir/safe_mode bypass with ini_restore(). + - Ported from upstream CVS: + http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_ini.c?r1=1.39.2.2&r2=1.39.2.3 + * Add debian/patches/CVE-2006-4812.patch: + - Fix integer overflow in Zend's ecalloc(). + - Ported from upstream CVS: + http://cvs.php.net/viewvc.cgi/ZendEngine2/zend_alloc.c?r1=1.161&r2=1.162 + + -- Martin Pitt Tue, 10 Oct 2006 18:25:01 +0200 + +php5 (5.1.6-1ubuntu1) edgy; urgency=low + + * Merge from Debian unstable, bringing in a myriad of security fixes. + * Revert libdb4.3->libdb4.4 migration until we're ready to do this. + + -- Adam Conrad Wed, 13 Sep 2006 23:11:09 +1000 + +php5 (5.1.6-1) unstable; urgency=high + + [ Adam Conrad ] + * Drop 041-shut_up_snmp.patch, which was no longer needed as of 5.1.0. + + [ Ondřej Surý ] + * Acknowledge NMU. + * New upstream release (Closes: #383596) + - Added missing safe_mode/open_basedir checks inside the error_log(), + file_exists(), imap_open() and imap_reopen() functions. + - Fixed overflows inside str_repeat() and wordwrap() functions on 64bit + systems. + - Fixed possible open_basedir/safe_mode bypass in cURL extension and + with realpath cache. (CVE-2006-2563) (Closes: #370165) + - Fixed overflow in GD extension on invalid GIF images. + - Fixed a buffer overflow inside sscanf() function. (CVE-2006-4020) + (Closes: #382256) + - Fixed an out of bounds read inside stripos() function. + - Fixed memory_limit restriction on 64 bit system (really with 5.1.6). + * Bump libdb build-dep from libdb4.3 to libdb4.4, to match with apache. + + -- Ondřej Surý Sat, 19 Aug 2006 14:41:43 +0200 + +php5 (5.1.4-0.1ubuntu1) edgy; urgency=low + + * Merge from debian unstable. + + -- Fabio M. Di Nitto Wed, 12 Jul 2006 17:06:38 +0200 + +php5 (5.1.4-0.1) unstable; urgency=high + + * Non-maintainer upload. + * New upstream release. (Closes: #366109) + * Fixes information leak in html_entity_decode() (CVE-2006-1490). + (Closes: #359907) + * Fixes phpinfo() XSS (CVE-2006-0996). (Closes: #361914) + * Fixes copy() safe mode bypass (CVE-2006-1608). (Closes: #361915) + * Fixes tempnam() open_basedir bypass (CVE-2006-1494). (Closes: #361916) + * Fixes wordwrap() buffer overflow (CVE-2006-1990). (Closes: #365312) + * Fixes substr_compare() DoS condition (CVE-2006-1991). + * Fixes crash during too deep recursion (CVE-2006-1549). (Closes: #361917) + * Fixes injection in mb_send_mail() (CVE-2006-1014, CVE-2006-1015); not + mentioned in upstream changelog. (Closes: #368595) + * 044-strtod_arm_fix.patch: Adapted for new upstream; pulled in from + Piotr Roszatycki's packages. + * 108-64bit_datetime.patch: Patch to fix possible segfault on systems where + sizeof(void*) > sizeof(int); patch from David Mosberger-Tang. + + -- Steinar H. Gunderson Tue, 13 Jun 2006 22:38:33 +0200 + +php5 (5.1.2-1ubuntu3) dapper; urgency=low + + * Enable the mysqli extension, which is required for full functionality + of the ubuntu-server LAMP stack for dapper (launchpad.net/27904) + * Make php5-{mysql,mysqli} depend on each other to ease the pain of the + planned transition for Etch/Edgy where both will be packaged together. + * Comment out the EXTRA_VERSION hack, since it served its purpose when + we were providing CVS snapshots, but is now just a cause of complaints. + + -- Adam Conrad Thu, 18 May 2006 12:12:27 +1000 + +php5 (5.1.2-1ubuntu2) dapper; urgency=low + + * Rebuild against the new libmysqlclient15off with correct symbols. + + -- Adam Conrad Thu, 6 Apr 2006 12:48:51 +1000 + +php5 (5.1.2-1ubuntu1) dapper; urgency=low + + * Resynchronise with Debian, bringing in security fixes and PEAR fix. + + -- Adam Conrad Wed, 18 Jan 2006 18:09:55 +1100 + +php5 (5.1.2-1) unstable; urgency=low + + * New upstream bugfix and security update release (closes: #347894) + - Fixes multiple cross-site-scripting vulnerabilities; CVE-2006-0208 + - Resolves multiple HTTP response splitting vulnerabilities, allowing + arbitrary header injection via Set-Cookie headers; see CVE-2006-0207 + - While we don't currently build it, this release also fixes a format + string vulnerability in the mysqli extension; see CVE-2006-0200 + - Includes a new version of the PEAR installer that seems to have a + slightly better clue about the difference between INSTALL_ROOT and + PHP_PEAR_INSTALL_DIR, fixing pear.conf (closes: #346479, #346501) + * While the above is partially true, the PEAR installer is still a bit + broken (it won't install correctly under fakeroot anymore, YAY), so + shuffle debian/rules to have a build-pear-stamp target, as a stopgap. + * Add 106-strptime_xopen.patch, moving the _XOPEN_SOURCE definition down + in ext/standard/datetime.c, below the php.h include (closes: #346550) + * Add 107-reflection_is_ext.patch, munging ext/reflection/config.m4 to + properly call the PHP_ARG_ENABLE macro for an extension, not built-in. + * Stop php-pear from Replacing and Conflicting with php-html-template-it, + as we only now ship the bare essential to make the pear installer go. + + -- Adam Conrad Mon, 16 Jan 2006 16:12:31 +1100 + +php5 (5.1.1-1ubuntu1) dapper; urgency=low + + * Resynchronise with Debian, bringing in a myriad of security fixes. + + -- Adam Conrad Sun, 8 Jan 2006 02:07:20 +1100 + +php5 (5.1.1-1) unstable; urgency=low + + * New upstream bugfix release, skipping the problematic 5.1.0 release: + - Fixes a zend.ze1_compatibility_mode segfault (closes: #333374) + - Remove libtool patch from acinclude.m4, now integrated upstream. + - Remove 038-round_test_fix.patch, now integrated upstream. + - Remove 049-exported-headers.patch, as upstream's build system has + gotten more clever about what they should and shouldn't export. + - Remove 054-open_basedir_slash.patch, now integrated upstream. + - Remove 055-gd_safe_mode_checks.patch, fixed differently upstream. + - Mangle 101-sqlite_is_shared.patch, to deal with upstream changes. + - Remove 104-64_bit_serialize.patch, now integrated upstream. + - Remove 105-64_bit_imagettftext.patch, now integrated upstream. + * Many security vulnerabilities fixed (closes: #341368, #336005, #336654): + - Resolves a local denial of service in the apache2 SAPI, which can + be triggered by using session.save_path in .htaccess; CVE-2005-3319 + - Resolves an infinite loop in the exif_read_data function which can + be triggered with a specially-crafted JPEG image; CVE-2005-3353 + - Resolves a vulnerability in the parse_str function whereby a remote + attacker can fool PHP into turning on register_globals, thus making + applications vulnerable to global variable injections; CVE-2005-3389 + - Resolves a vulnerability in the RFC1867 file upload feature where, if + register_globals is enabled, a remote attacker can modify the GLOBALS + array with a multipart/form-data POST request; see CVE-2005-3390 + - Resolves numerous safe_mode and open_basedir bypasses; CVE-2005-3391 + - Resolves INI settings leaks in the apache2 SAPI, leading to safe_mode + and open_basedir bypasses between virtual hosts; CVE-2005-3392 + - Resolves a CRLF injection vulnerability in the mb_send_mail function, + allowing injection of arbitrary mail headers; see CVE-2005-3883 + - Includes PEAR 1.4.5, resolving a vulnerability in the pear installer + which could lead to arbitrary code execution; see CVE-2005-4154 + * Bump libdb build-dep from libdb4.2 to libdb4.3, to match with apache. + * Bump our MySQL build-dep to 5.0's libmysqlclient15-dev (closes: #343793) + * Automate the process of getting the list of built-in modules into the + package descriptions, so it stays fresh in the future (closes: #341867) + * Intentionally disable PDO support until I've sorted out the best way to + deal with shipping this shiny new feature that won't break the world. + * The new PEAR happens to fix the Command.php greedy match bug filed in + Debian as part of the fix for the wider security issue (closes: #334969) + * Create 056-mime_magic_strings.patch, making the mime_magic extension + more liberal about what mime-types is accepts, as well as making it skip + over ones it dislikes, rather than disabling itself (closes: #335674) + * Add 057-no_apache_installed.patch, to stop spewing a mess of errors in + configure because we don't have the apache binaries in the build chroot. + * Fix small typo in the php5-xsl package description (closes: #344816) + + -- Adam Conrad Thu, 15 Dec 2005 14:46:56 +1100 + +php5 (5.0.5-3) unstable; urgency=low + + * Build-Depend on libcurl3-openssl-dev, since libcurl3-dev is going away + soon. Keep libcurl3-dev as an alternate for backporting (see: #334367) + * Switch from libmysqlclient12 to libmysqlclient14; this puts us on the + *other* side of the line regarding which combinations of DSOs cause + segfaults, so hopefully the others catch up with us soon (closes: #332453) + * Look for magic.mime in /usr/share/file now instead of /usr/share/misc/file, + as the path has been changed to comply with the FHS (see: #334510) + * Make the above backportable as well, by searching for both files, and + picking the one that's currently installed on the user's system. + * Include swedish debconf translation from Daniel Nylander (closes: #330763) + * Make pear use '/usr/bin/php' instead of just 'php' to make sure we don't + get some random binary on $PATH that won't work right (closes: #329415) + * Set PHP_PEAR_SIG_BIN to /usr/bin/gpg, and have php-pear Recommends: gnupg + + -- Adam Conrad Fri, 21 Oct 2005 02:30:19 +1000 + +php5 (5.0.5-2ubuntu1) breezy; urgency=low + + * Resync with Debian, bringing in two security fixes, a file conflict fix, + and two 64-bit memory corruption and segfault fixes (no other changes). + + -- Adam Conrad Sun, 9 Oct 2005 03:14:32 +1000 + +php5 (5.0.5-2) unstable; urgency=medium + + * Remove Andres Salomon from the Uploaders field, at his request. Thanks + for all your work on the PHP packages, Andres, now fix our kernel bugs. + * Add 054-open_basedir_slash.patch, which fixes a bug where if open_basedir + is set to "/foo/", users can access files in "/foobar/", which is not the + documented behaviour; this addresses CAN-2005-3054 (see: #323585) + * Add 104-64_bit_serialize.patch from Joe Orton, resolving a segfault when + serializing objects on all 64-bit architectures (closes: #329768) + * Add 105-64_bit_imagettftext.patch, fixing a type mismatch in the GD + extension, causing memory corruption on 64-bit arches (closes: #331001) + * Add 055-gd_safe_mode_checks.patch from PHP CVS, adding missing safe_mode + checks to the _php_image_output and _php_image_output_ctx GD functions. + * Make php-pear Provide, Replace, and Conflict php-html-template-it, which + we appear to have absorbed into the main PEAR packaging (closes: #332393) + + -- Adam Conrad Tue, 27 Sep 2005 16:09:29 +1000 + +php5 (5.0.5-1ubuntu1) breezy; urgency=low + + * Resync with Debian, lowering libsnmp-dev build-dep to libsnmp5-dev. + * This new upstream includes a fixed XML_RPC class in php-pear, which + addresses CAN-2005-2498 and closes Ubuntu bug #13701. + + -- Adam Conrad Tue, 13 Sep 2005 14:52:10 +1000 + +php5 (5.0.5-1) unstable; urgency=low + + * New upstream release, adjust patch offsets and fuzz, and drop patches: + - Drop 009-snmp-int-sizes.patch, finally fixed upstream. + - Drop 051-gcc-4.0.patch, fixed differently upstream. + - Drop 102-php_streams.patch, fixed upstream. + - Drop 103-catch_segv.patch, also fixed upstream. + - Includes PEAR XML_RPC fix for CAN-2005-2498. + - Includes phpinfo() XSS fix for CVE-2005-3388. + * Distribute the shiny new manpages for php-config and phpize. + + -- Adam Conrad Mon, 12 Sep 2005 02:29:24 +1000 + +php5 (5.0.4-4) unstable; urgency=low + + * Ondřej Surý : + - Add patch from CVS to fix regression in PHP 5.0.4, where file related + functions all stop reading at 2,000,000 bytes (closes: #321930) + * Adam Conrad : + - Enable support for gdbm files in the dba handler; half the base system + already appears to depend on libgdm, so we can't make things worse. + - Add another patch from CVS to fix a segfault in the catch/throw + handler under interesting nesting cases (closes: #322507) + - Rebuild against libsnmp9-dev for new libsnmp SOVER (closes: #327107) + + -- Adam Conrad Thu, 8 Sep 2005 00:36:36 +1000 + +php5 (5.0.4-3ubuntu1) breezy; urgency=low + + * Resync with Debian, bringing in important changes to php5-dev and the + dependency relationships between php5 SAPIs and php5 extensions, as + well as making sure that php5 is backportable to hoary without changes. + + -- Adam Conrad Mon, 1 Aug 2005 09:54:24 +1000 + +php5 (5.0.4-3) unstable; urgency=low + + * And fix the module/extension API situation one last time, this time + we read ZEND_EXTENSION_API_NO, ZEND_MODULE_API_NO, and PHP_API_VERSION, + pick the most recent of the three, assume things broke in ways we're + not willing to cope with, and both change the extension directory to + use that value, as well as setting it to the provides/depends for the + various SAPI and extension packages. + * Add a new option to php-config, 'php-config --phpapi', which extension + packagers should now be using to get the current phpapi they're building + against and set their dependencies accordingly. + * Strip the -gnu off the end of the DEB_*_* variables and drop the + versioned dpkg-dev build-dep to ease backporting to sarge and hoary; + doing so in such a way as to still allow for easy cross-compiling. + * Add postgresql-dev build-dep alternate for easy hoary/sarge backports. + * Make libapache2-mod-php5 the default alternate dependency for the php5 + metapackage, since we really do want to encourage the apache upgrade. + * Make php5-dev stop shipping copies of files from autotools-dev, shtool, + and libtool, and instead symlink to them and depend on those packages, + thus avoiding the shtool issues from CAN-2005-1751 and CAN-2005-1759. + + -- Adam Conrad Sun, 31 Jul 2005 03:05:08 +1000 + +php5 (5.0.4-2) unstable; urgency=low + + * We now have a mailing list. Set the maintainer to the list, and move + myself to Uploaders where, apparently, I belong. + * Use ZEND_MODULE_API_NO rather than PHP_API_VERSION for extension deps, + as recent upstream ABI breakage in 4.4.0 leads me to believe this is + the only constant they actually bother to update on ABI changes. + * Bring back some concflicts that went missing (libapache-mod-php5 needs + to conflict with libapache-mod-php4 and older versions of php4, while + the two libapache2-mod-php[45] modules also need to conflict). + * Adjust debian/watch to not match on upstream's alpha/beta/rc releases. + + -- Adam Conrad Wed, 27 Jul 2005 22:30:42 +1000 + +php5 (5.0.4-1ubuntu2) breezy; urgency=low + + * libapache2-mod-php5 needs to conflict with libapache2-mod-php4 to + prevent people from shooting their own feet and breaking apache2. + + -- Adam Conrad Wed, 27 Jul 2005 22:29:14 +1000 + +php5 (5.0.4-1ubuntu1) breezy; urgency=low + + * Upload to breezy, disabling the libapache-mod-php5 build. + + -- Adam Conrad Wed, 27 Jul 2005 02:22:23 +1000 + +php5 (5.0.4-1) unstable; urgency=low + + * Initial PHP5 release; packaging forked from php4 4:4.3.11-1. + - Closes: #262977, #293832 + * Ondrej Sury : + - Removed some obsolete cruft, since there wasn't any previous php5 + packages there is no need, to check /usr/share/doc/*, etc. + - Removed apache2 IfModule hack, it's been fixed in php5. + - Updated patches to php5, removing those which are obsolete. + - Changes xslt extension to xsl (using libxslt). + - Updated debian/* including changelog. + - Raised update-alternatives priority to 50. + * Adam Conrad : + - Merged with php4 4:4.4.0-1 packaging. + - Re-roll upstream tarball to include PEAR::XML_RPC 1.3.3, which + includes a security fix for CVE CAN-2005-1921. + - Bump to Standards-Version 3.6.2, with no source changes. + - Stop distributing the phpextdist binary, as upstream has stopped. + - Drop the ext_skel binary and skeleton dir from php5-dev, as it has + been deemed obsolete upstream and the version in the tarball is not + considered useful anymore. PEAR::PECL_Gen upstream will replace it. + - Fix longstanding broken shebang lines in debconf config scripts. + - Remove lintian overrides for modules; lintian no longer complains + about missing shlibs for libraries outside the linker path. + - Add a linda override for the non-standard directory permissions on + /var/lib/php5 in php5-common. + - Rename php5-pear to php-pear, have it replace php4-pear, and depend + on php5-cli OR php4-cli; make sure it works with both. + - Compile in SOAP extension (closes: #307580) + - Enable SQLite extension as shared, make the xmlrpc extension shared. + - Enabled the pgsql extension, and disabled the imap extension (which + will be moving to another source package and become the example + package for out-of-tree builds). + + -- Adam Conrad Sat, 16 Jul 2005 23:42:36 +1000 + +php4 (4:4.3.11-1) unstable; urgency=low + + * New upstream release (closes: #304052) + - Drop CVS patches, we're back in step with upstream versions. + - Remove 048-x509_multiple_orgUnits.patch, incorporated in 4.3.11. + - Remove 050-4.3.11_file_copy_fix.patch, incorporated in 4.3.11. + - Remove 040-curl_open_basedir.patch, as upstream has solved this + in a different fashion. + - Adjust patches for offset and fuzz. + - Remove bits from debian/rules dealing with the DB PEAR extension, + since it's no longer shipped in the php4-pear package. + * Rebuild against newer version of freetds library (closes: #317369) + * Add 052-phpinfo_no_configure.patch, which disables the display of our + "Configure Command" in phpinfo(), which was the source of many bogus + bug reports over the years, due to people misinterpreting its meaning. + * New translations to Vietnamese and Russian (closes: #316821, #310199) + - vi.po contributed by Clytie Siddall + - ru.po contributed by Yuriy Talakan' + * Mention FastCGI in the description of php4-cgi (closes: #310810) + + -- Adam Conrad Mon, 4 Jul 2005 17:47:32 +1000 + +php4 (4:4.3.10-15) unstable; urgency=low + + * Bring back the shipping of /usr/share/doc symlinks in our packages, + as this, in concert with moving the migration detection from preinst + to postinst (which was done in the last upload), seems to give us the + sanest upgrade path. Thanks to Steve Langasek for smacking me around + with unpack/upgrade scenarios for a while to convince me of this. + + -- Adam Conrad Mon, 9 May 2005 02:13:19 -0600 + +php4 (4:4.3.10-14) unstable; urgency=high + + * Revert the directory->symlink magic to work how it used to, since the + new behaviour broke hideously on upgrades from Woody, causing certain + files (like the changelog) to mysteriously go missing (closes: #307591) + * Move our template php.ini to /usr/share/php4, so we stop violating + policy by using files from /usr/share/doc (as seen in #307591) + * Remove 'readline' from the php4-cli package description, since we don't + actually build with readline support enabled anymore (closes: #306571) + + -- Adam Conrad Wed, 4 May 2005 01:48:19 -0600 + +php4 (4:4.3.10-13) unstable; urgency=low + + * Update email address for Andres Salomon + * Add Portuguese translation from Miguel Figueiredo (closes: #305038) + * Include 051-gcc-4.0.patch, which resolves a build failure in + libxmlrpc (from the xmlrpc extension) with gcc-4.0 (closes: #287956) + + -- Adam Conrad Mon, 18 Apr 2005 00:29:54 -0600 + +php4 (4:4.3.10-12) unstable; urgency=low + + * Add 050-4.3.11_file_copy_fix.patch, which reverts a broken 'fix' + made to the copy() function, causing it to fail in particularly + spectacular ways when used on remote files (closes: #304601) + * Use -g instead of -gstabs on powerpc64-linux (closes: #301571) + + -- Adam Conrad Thu, 14 Apr 2005 03:53:27 -0600 + +php4 (4:4.3.10-11) unstable; urgency=medium + + * Address an FTBFS waiting to happen in the php4-dev package: + - Remove Win32 and Netware specific headers. + - Stop shipping php4-pgsql headers. + - Stop shipping the expat headers, since we don't even + use the bundled expat library. + - Make php4-dev depend on libssl-dev, since it wants to include + ssl.h when you use it to build network-using extensions. + * Stop building extensions twice; we don't need two copies. + + -- Adam Conrad Tue, 12 Apr 2005 03:14:03 -0600 + +php4 (4:4.3.10-10) unstable; urgency=low + + * Update to 200503131325 CVS (AKA: 4.3.11RC1), fixing several bugs + including a segfault in mysql_fetch_field() (closes: #299608) + * Remove 042-remove_windows_paths.patch, incorporated upstream. + * Add 048-x509_multiple_orgUnits.patch to bring the openssl extension + in line with the upcoming 4.3.11 behaviour of listing multiple + Organisational Units in an x509 cert as an array, rather than only + listing the last in the list. + * After much talk with upstream, revert the ZTS changes. We are no + longer building a thread-safe PHP. (closes: #299820, #297223, #297679) + * ZTS was breaking file search paths, leading to errors loading files + from the cwd (closes: #298282, #298518, #299089, #299356) + * Stop building caudium-php4 (closes: #294718, #297702, #295100) + - We can't link against the GPL pike7.2, which we've been doing. Oops. + - Even if the above weren't true, upstream has insisted that ZTS is a + horribly broken solution, slated for eventual removal, and should + never, ever be used. In light of that, caudium users should instead + use php4-cgi, either as a plain CGI, or as a FastCGI backend. + - Not even attempting to provide an upgrade path, as it would be + needlessly complex, and caudium-php4 in previous stable releases + was nothing more than a useless toy, given that it had nearly no + useful extensions built-in or supported. + * Rewrite 041-shut_up_snmp.patch to take a different approach, this time + regrettably reverting a fix for a memory leak, in the name of making + things work properly, including squashing the putenv() intecaction + bug between PHP and other apache modules (closes: #298511, #300628) + * On sidegrades from distributions where different modules may be built + from their own source, and thus have their own doc directories, bad + things happen when we try to replace those with symlinks, so now we + check for this in preinst, and fix stuff up magically to Just Work. + * Add Jeroen van Wolffelaar to Uploaders. + * Fix up modules regexes to use "\.so" instead of ".so" (cf: #300998) + + -- Adam Conrad Wed, 16 Mar 2005 22:46:05 -0700 + +php4 (4:4.3.10-9) unstable; urgency=low + + * Update 040-curl_open_basedir.patch once more to make sure it doesn't + segfault when fed a null or uninitialised URL (closes: #295447) + * Add 047-zts_with_dl.patch, courtesy of Steve Langasek to re-enable the + dl() function in our builds, despite upstream's claim that it "might + not be threadsafe on all platforms"; it is on ours (closes: #297839) + * Make the php4-dev binaries versioned with alternatives (closes: #295903) + * Update build-deps to libmysqlclient12-dev (closes: #290989, #227549) + + -- Adam Conrad Sun, 6 Mar 2005 07:30:35 -0700 + +php4 (4:4.3.10-8) unstable; urgency=high + + * Add 046-zend_plist_buggery.patch which unrolls the changes made to + zend.c in CVS post-4.3.10. The memory leaks fixed by these changes + seem to not have been hurting us terribly so far, while the "fix" + (breaking persistent lists) was, uhm, bad (closes: #295998, #296694) + * Revise 041-shut_up_snmp.patch to call init_snmp with 'snmpapp' as the + appname, rather than 'php', to maintain backward compatibility, and to + wrap our setenv/unsetenv magic only around snmp_shutdown, which seems to + solve a segfault when php4-snmp is loaded with mod_perl (closes: #296282) + * Fix 042-remove_windows_paths.patch to catch both cases where windows + path stripping should occur (closes: #296406) + + -- Adam Conrad Tue, 22 Feb 2005 07:49:32 -0700 + +php4 (4:4.3.10-7) unstable; urgency=high + + * Rewrite 040-curl_open_basedir.patch, so it now does what it's supposed + to (addressing CAN-2004-1392) and no longer segfaults (closes: #295447) + + -- Adam Conrad Thu, 17 Feb 2005 00:06:36 -0700 + +php4 (4:4.3.10-6) unstable; urgency=high + + * Add 044-strtod_arm_fix.patch to fix the FPU confusion FTBFS on arm. + * Add 045-exif_nesting_level.patch to bump the exif header parsing max + nesting level to something that actually works with most JPEG images. + + -- Adam Conrad Mon, 14 Feb 2005 16:04:28 -0700 + +php4 (4:4.3.10-5) unstable; urgency=low + + * Add 043-recode_size_t.patch to fix 32/64-bit issues causing the recode + extension to segfault on alpha/amd64/ia64 (closes: #294986) + * Move the ./buildconf stuff in the unpatch target inside the test + for patch-stamp, as it's uselss unless we're unpatching. + + -- Adam Conrad Sun, 13 Feb 2005 19:09:39 -0700 + +php4 (4:4.3.10-4) unstable; urgency=medium + + * Make php4-dev arch:any, as it contains some arch-specific defines. + * Add 042-remove_windows_paths.patch, a patch to rfc1867.c to strip Windows + paths from uploaded filenames, like it used to. (closes: #294305) + * Fix up caudium description to reflect the fact that caudium it is no + longer restricted from sharing extensions with other SAPIs. + * Build-dep on apache2-threaded-dev (>= 2.0.53-3) to make sure we + get a version with non-broken headers. + + -- Adam Conrad Wed, 9 Feb 2005 11:52:10 -0700 + +php4 (4:4.3.10-3) unstable; urgency=medium + + * Update to CVS, as of 200502060530 (closes: #288672) + - Fixes two vulnerabilities in exif.c, CAN-2005-1042 and CAN-2005-1043 + - Fixes two vulnerabilities in image.c, CAN-2005-0524 and CAN-2005-0525 + - File uploads with "'" in them aren't cut off anymore (closes: #288679) + - unserialize() is no longer ridiculously slow (closes: #291392) + - Add 000-200502060530_CVS.patch + - Adapt debian/rules to the realities of upstream's new buildconf + - Add 033-we_WANT_libtool.patch, to force relibtoolizing with Debian's + libtool, rather than using upstream's broken bundled libtool + - Drop 031_zend_strtod_1.1.2.10.patch and 032_zend_strtod_debian.patch + - Adjust patches for offsets and fuzz + - Force --with-pic, as policy demands it, and the build system doesn't + * Added several patches, yanked from the Fedora PHP sources: + - 034-apache2_umask_fix.patch, fixes umask not being properly reset + after each request (closes: #286225) + - 036-fd_setsize_fix.patch, fixes misuse of FD_SET() + - 038-round_test_fix.patch, makes the rounding test work on gcc-3.3 + * Removed --with-libedit, as being able to background php is more useful, + in my opinion, than using readline functions (see #286356) + * Include zip support in all SAPIs (closes: #288534, #288909) + * Enable Zend Thread Safety for all SAPIs, meaning that our modules + are now compiled for ZTS APIs as well. (closes: #278212, #264015) + - Make sure caudium-php4 now provides phpapi-$(ver), and modules can + be configured with the caudium SAPI. + - Add 039-reentrant_libs.patch to link to the reentrant versions of + libldap and libmysqlclient + * Stop suggesting phpdoc, as it's undistributable anyway. + * Add 040-curl_open_basedir.patch, to make php4-curl respect the value + of open_basedir, thanks to Martin Pitt (closes: #291410) + * Add 041-shut_up_snmp.patch, to prevent libsnmp5 from attempting (and + failing) to write persistent data every time it shuts down. Ugh. + + -- Adam Conrad Sun, 6 Feb 2005 05:32:11 -0700 + +php4 (4:4.3.10-2) unstable; urgency=high + + * Patch Zend/zend_strtod.c twice: + - Patch from upstream CVS to fix FTBFS on Sparc/Linux systems + - Patch from me to fix FTBFS on __mc68000__, __ia64__, and __s390__ + + -- Adam Conrad Sat, 18 Dec 2004 19:35:30 -0700 + +php4 (4:4.3.10-1) unstable; urgency=high + + * New upstream release, including the following security fixes: + - CAN-2004-1018 - shmop_write() out of bounds memory write access. + - CAN-2004-1018 - integer overflow/underflow in pack() and unpack() + functions. + - CAN-2004-1019 - possible information disclosure, double free and + negative reference index array underflow in deserialization code. + - CAN-2004-1020 - addslashes() not escaping \0 correctly. + - CAN-2004-1063 - safe_mode execution directory bypass. + - CAN-2004-1064 - arbitrary file access through path truncation. + - CAN-2004-1065 - exif_read_data() overflow on long sectionname. + - magic_quotes_gpc could lead to one level directory traversal with + file uploads. + * Adjust patch offsets for new upstream, fix 013-force_getaddrinfo.patch + to match with new configure.in and drop 026-4.3.10_session_fixes.patch + which is included in 4.3.10. + + -- Adam Conrad Wed, 15 Dec 2004 17:17:40 -0700 + +php4 (4:4.3.9-2) unstable; urgency=low + + * Adam Conrad : + - Add -fno-strict-aliasing to CFLAGS, as the (several thousand) + warnings I'm getting from GCC are frightening me a tad. + - Remove the php-cgi alternative in php4-cgi's prerm, to avoid + leaving dangling symlinks (closes: #275962, #282315) + - Include 030-imap_getacl.patch, adding the imap_getacl() function + required by the GOsa project (closes: #282484) + - Include php.ini-paranoid in doc/examples, provided and maintained + by Javier Fernández-Sanguino Peña (closes: #274374) + - Make /cgi-bin/php4 an alternative for /cgi-bin/php (closes: #282464) + - Remove obsolete info from README.Debian relating to session_mm, + since we stopped building with libmm a while back. + - Reintroduce /usr/lib/php4/libexec that went missing in a previous + upload, since the build uses it as the default safe_mode exec dir. + * Andres Salomon : + - Add patch to include gd headers in php4-dev, as some PECL modules + (notably, pdflib) expect it; 028-export_gd_headers.patch. + - Lintian fix: Add missing #DEBHELPER# token to php4-common.postrm. + + -- Adam Conrad Wed, 01 Dec 2004 18:48:13 -0700 + +php4 (4:4.3.9-1) unstable; urgency=high + + * New upstream release, removed the following patches fixed upstream: + 014-apache2handler_CVS_fixes.patch, 015-gdNewDynamicCtx_Add_Ex.patch, + 018-unix_socket_fd_leak.patch, 020-4.3.9_overflow_fixes.patch, + 021-4.3.9_sybase_ct_fixes.patch, 022-4.3.9_sprintf_fixes.patch, + 023-4.3.9_array_fixes.patch, 024-4.3.9_glob_fix.patch, + and 025-4.3.9_domxml_segfaults.patch + * Resolves undiscolsed vulnerabilities in GPC processing and rfc1867 + handling of file uploads via the $_FILES array; these have since + been assigned CVE CAN-2004-0958 and CAN-2004-0959 (closes: #274206) + * After some fairly heavy testing from several users and developers, + finally update php4-snmp to use libsnmp5 (closes: #195929) + * Add 026-4.3.10_session_fixes.patch from CVS, which prevents PHP + from segfaulting when a nonexistant or unsupported save_handler or + serialize_handler is specified in php.ini. + * Add /etc/apache/conf.d/php4.conf, setting up our mime-types, on the + off chance that the user's /etc/mime.types is broken (closes: #271171) + * Reintroduce a CGI binary at /usr/bin/php4-cgi, so people who can't + make use of the --force-cgi-redirect CGI binary in /usr/lib/cgi-bin + can instead use #!/usr/bin/php4-cgi scripts (closes: #273143) + * Enable FastCGI for both CGI binaries, now that it no longer conflicts + with, but rather complements, the CGI SAPI (closes: #233849) + * Bump libgd2 build-dep a notch to make sure we build against a version + that actually has XPM support built in (closes: #270435) + * Finally drop the bogus libapache-mod-ssl dependency from the apache1.3 + php4 module, as glibc (>= 2.3.2.ds1-17) has fixed the dlopen refcount + bug that we were hacking around (closes: #205553, #230956, #271000) + * Remove the mm session handler from the apache1.3 build. Since the + files handler now works on all arches, and is configured to be secure + by default, mm seems to have outlived its usefulness. + (closes: #119902, #149430, #166811, #272463, #232840) + * Rename sapi/apache2handler/sapi_apache2.c to mod_php4.c so that + directives aren't ambiguous between php4 and php5. + * Add Czech translation, thanks to Miroslav Kure (closes: #274038) + * Configure CLI with --with-libedit for readline support, and add + 027-readline_is_editline.patch, since Debian's libedit headers are + not installed in /usr/include/readline (closes: #274031) + * libcurl grew a new SONAME somewhere along the way, and upgrading + doesn't seem to cause regressions in php4-curl, so upgrade we shall, + changing build-deps accordingly (closes: #260389) + + -- Adam Conrad Mon, 4 Oct 2004 22:57:37 -0600 + +php4 (4:4.3.8-12) unstable; urgency=high + + * On new php4-cli installations, if php4-cgi is installed, we copy its + php.ini as a starting reference, so that command line scripts that + used to work don't start mysteriously failing (closes: #270153) + * php4-common has grown a postrm script to make sure we completely + clean out and remove /var/lib/php4 during the purge phase. + * Optimize garbage collection cronjob to use 'xargs -r -0 rm', so we + aren't forking for every session file we delete (closes: #268918) + + -- Adam Conrad Sun, 5 Sep 2004 19:17:42 -0600 + +php4 (4:4.3.8-11) unstable; urgency=high + + * Andres Salomon : + - Fix bashism in maxlifetime script (closes: #270015) + * Adam Conrad : + - Clarify setup instructions in README.Debian for using php4-cgi + with the apache and apache2 packages (closes: #228342, #228343) + + -- Adam Conrad Sat, 04 Sep 2004 23:21:21 -0600 + +php4 (4:4.3.8-10) unstable; urgency=high + + * Andres Salomon : + - Change frequency of session file cleansing, based on the maximum value + of session.gc_maxlifetime from all php.ini files (closes: #269688). + - Update README.Debian to mention session cleaning cron job. + * Adam Conrad : + - Drop php4-cgi from the list of alternate dependencies for the php4 + metpackage to smooth upgrades for woody users who have both php4 and + php4-cgi installed (closes: #269628, #269348, #269377) + - Fix cut-n-paste issue in php4-cli postinst (closes: #269466) + - Add 023-4.3.9_array_fixes.patch, which fixes problems with the + extract() function misbehaving with multiple element references. + - Add 024-4.3.9_glob_fix.patch to fix broken return values from glob() + when it succeeds with no matches (closes: #269287) + - Add 025-4.3.9_domxml_segfaults.patch, fixing segfaults in the domxml + extension when it shares memory space with other libxml2-using libs. + - Update the comments in php.ini to point out that, due to dilinger's + changes above, session.gc_maxlifetime is honoured by the gc cronjob. + + -- Adam Conrad Fri, 03 Sep 2004 20:42:56 -0600 + +php4 (4:4.3.8-9) unstable; urgency=high + + * Re-introduce the changelog.Debian that went missing in the last + upload due to the php4-common move from arch:all to arch:any + * Clean up lintian warnings regarding scripts that weren't executable + and executables that weren't scripts. + * Add a lintian override for the non-standard-dir-perm of /var/lib/php4 + * Update to Standards-Version 3.6.1 (no changes, other than the above) + + -- Adam Conrad Thu, 26 Aug 2004 21:53:27 -0600 + +php4 (4:4.3.8-8) unstable; urgency=low + + * Default session.save_path is now compiled in to php4, allowing + us to, again, comment out the value in php.ini. + * Comment out session.gc_probability in the default php.ini, as we've + now compiled in a default of 0, allowing the cronjob to do the + garbage collection for us instead. (closes: #267720) + * Make the 5 SAPI postinsts smarter, allowing them to poke around in + people's configs and make sure that sessions won't be broken + after we upgraded them from a perfectly functional system. + * Add 022-4.3.9_sprintf_fixes.patch, fixing incorrect formatting of + floats with padding by sprintf(). + * Make php4-common arch:any, and loosen up some of the other any->all + package dependencies to make sure binNMUs won't break. + + -- Adam Conrad Tue, 24 Aug 2004 03:09:43 -0600 + +php4 (4:4.3.8-7) unstable; urgency=high + + * Back out LFS support AGAIN, as we're disabling LFS in apache2 for + the Sarge release. (closes: #266869) + * Add 021-4.3.9_sybase_ct_fixes.patch, backporting several fixes + for the sybase_ct extension from 4.3.9rc1. + * Tidy up descriptions a fair bit: + - Disambiguate short descriptions of SAPIs. (closes: #244571) + - Refresh the (now much longer) lists of built-in modules for each SAPI. + - Explain why caudium-php4 can't use any loadable extensions. + - Remove silly advertising blurb for Zend, since very few people are + still using php3, and those who are can't be convinced to upgrade + just by telling them "Hey, it's faster!". + - Add Homepage URI to each SAPI description. + - Fix typo in php4-domxml description. (closes: #146124) + * Make caudium-php4 provide php4-mysql and php4-pgsql, so it can be used + with packages that depend on something like "php4, php4-mysql". + * Enable --with-mime-magic and make sure all SAPIs depend on libmagic1 + to pull in /usr/share/misc/file/magic.mime (closes: #175136) + + -- Adam Conrad Thu, 19 Aug 2004 18:27:17 -0600 + +php4 (4:4.3.8-6) unstable; urgency=high + + * Add libgcrypt11-dev to the build-depends, as something seems to be + pulling it in and causing an FTBFS (closes: #265952) + * Add 020-4.3.9_overflow_fixes, backporting fix for integer overflows + in array_slice(), array_splice(), substr(), substr_replace(), + strspn() and strcspn(). + * Bump the apache2 build-dep to (>= 2.0.50-9) to ensure we're building + against the new ABI-incompatble libapr0, which brings in proper + large file support. Bump the apache2 binary dependency as well. + (closes: #266210, #266192) + * Enable large file support on all SAPIs except for caudium, as I'm not + sure how caudium will react to the change, and I don't want to + destabilise anything just before release. This change has been + heavily tested with apache2/apache/cgi/cli, and all is well there. + * Re-enable 019-z_off_t_as_long.patch, which is needed to make sure + that LFS-enabled SAPIs can still use zlib file functions correctly. + * Rework the apache2 restarting logic to only restart apache2 if + apache2ctl configtest succeeds, otherwise kick out a warning to + the user. Even then, we run force-reload with ||true, in case + apache2 fails to start for other reasons (closes: #264958) + * Make php4-gd Provide php4-gd2, so packages which still depend on + php4-gd2 are installable (and so packaging frontends can take the + provides/conflicts/replaces hint and DTRT with it) + * Split php4-cgi to php4-cgi and php4-cli (closes: #227915) + - Add php4-cli to debian/control, replaces older php4-cgi versions + - php4-cgi depends on php4-cli for smooth transitions + - php4-pear now depends on php4-cli (closes: #243214, #221434) + - Add php4-cli to list of SAPIs configurable for modules + - Munge php.1 manpage to include -cli info + - Enable pcntl and ncurses in -cli (closes: #135861, #190947, #241806) + * Move all of php4's files to libapache-mod-php4, and make php4 a + metapackage that depends on libapache-mod-php4 | libapache2-mod-php4 | + php4-cgi | caudium-php4 (closes: #244573, #246654, #244571, #266517) + * Include skeleton directory in php4-dev (closes: #95832, #211338) + * Include php.ini-recommended in php4-common's examples (closes: #181396) + * Move /var/lib/php4 to php4-common and install a cronjob that cleans + out old sessions every 30 minutes (closes: #256831, #257111) + * Move the libapache-mod-ssl dependency from php4-imap to + libapache-mod-php4 to stop irritating users of other SAPIs + (closes: #240003, #246887, #263381) + * Compile pgsql and mysql support into the caudium SAPI, so it's + slightly less useless (closes: #181175) + + -- Adam Conrad Sun, 15 Aug 2004 19:56:14 -0600 + +php4 (4:4.3.8-5) unstable; urgency=low + + * Build-depend on chrpath and use it to nuke rpath from modules + during the install target of debian/rules. + * Add 018-unix_socket_fd_leak.patch to get rid of UNIX socket file + descriptor leak on failed fsockopen() calls. (closes: #257269) + * It would seem that if we want LFS support, all SAPIs and all extensions + that do file access need to be built with LFS support, and since + apache2 currently doesn't have LFS, this presents a problem. As + such, I'm disabling LFS accross the board until apache2 supports it. + (closes: #263962) + * Add 019-z_off_t_as_long.patch, including local headers for zlib, + forcing off_t = long for gzip file functions, however disable it + for now, as we'll only need it if we reenable LFS (closes: #208608) + * Add the Debian package revision as EXTRAVERSION to PHP, so one can + more easily tell what version is currently running (for instance, + if a user fails to restart Apache after an upgrade of php4, this + would become obvious to them in the version banner and in phpinfo() + * Fixed up debian/patches, adjusting offsets and adding newlines, + so patch stops complaining and applies them cleanly. + * libapache2-mod-php4 postinst now forces a reload of apache2, which + should get the module properly working in all cases where people + previously thought 'apachectl graceful' would cut it. + (closes: #241352, #263424, #228343) + * debian/rules explicitly sets PROG_SENDMAIL during configure so + that builds on buildds with no sendmail installed don't get the + mail() function disabled. (closes: #180734) + * Enable XMLRPC-EPI support for all SAPIs (closes: #228825, #249368) + * Enable sysvmsg support for all SAPIs (closes: #236190) + * Enable dbx support for all SAPIs (closes: #229508, #249797) + * Nuke aclocal.m4 before we run ./buildconf to ensure we get it + regenerated correctly, and we get an up-to-date libtoolization. + + -- Adam Conrad Mon, 9 Aug 2004 07:47:46 -0600 + +php4 (4:4.3.8-4) unstable; urgency=low + + * Drop 016-pread_pwrite_XOPEN_SOURCE_500.patch, as it didn't seem to + solve anything, really, and add 017-pread_pwrite_disable.patch, + wich completely disables pread/pwrite usage, fixing session support + on sparc, and pread/pwrite usage on amd64. (closes: #261311) + + -- Adam Conrad Mon, 26 Jul 2004 06:15:59 -0600 + +php4 (4:4.3.8-3) unstable; urgency=low + + * Steve Langasek : + - Give php4-pear a versioned dependency on php4-cgi, due to + backwards-compatibility issues (closes: #260924). + + * Adam Conrad : + - Added a debian/watch file for the curious, or people running + automated uscan scripts over the entire archive. + - Bump libgd2 build-dep to 2.0.28 to buy us guaranteed GIF + support in php4-gd (closes: #66293) + - Add 015-gdNewDynamicCtx_Add_Ex.patch, which fixes three double-free + errors in php4-gd. This, in concert with the librrd0 update + (see #261323) should clear up all known segfaults in php4-gd + (closes: #220196, #234571, #241270, #246833, #251220, #260790) + Thanks to Klaus Reimer for the tip. + - Add 016-pread_pwrite_XOPEN_SOURCE_500.patch, which fixes use of + pread/pwrite in conjunction with LFS64. This should fix the files + session handler on sparc, as well as the amd64 build failure. + (closes: #234766, #239420, #261311, #248765) + - Clean up debian/rules to remove a bunch of obsolete cruft, as well + as introducing an LFSFLAGS, allowing us to easily turn LFS support + on and off for each SAPI. + - Re-enable LFS for apache 1.3, as it was enable in Woody and we should + remain backward compatible. + + -- Adam Conrad Sun, 25 Jul 2004 18:49:31 -0600 + +php4 (4:4.3.8-2) unstable; urgency=high + + * Urgency "high" to make up for the last upload which contained + security fixes but was uploaded urgency "low". + + * Adam Conrad : + - Bump debhelper build-dep to >= 3, as we were using DH_COMPAT=3 + in debian/rules. Not sure how this was missed for so long. + - Add 014-apache2handler_CVS_fixes.patch, which fixes a memory + leak in the apache2handler SAPI, as well as a logical mishandling + of fatal errors during activation. + + * Steve Langasek : + - Revert large file support, which appears to cause + ABI-incompatibilities (and therefore segfaults) for apache2 + (closes: #259659). + + -- Adam Conrad Mon, 19 Jul 2004 20:44:00 -0600 + +php4 (4:4.3.8-1) unstable; urgency=low + + * Adam Conrad : + - New upstream release (4.3.8). Fixes several security issues: + + Fixed strip_tags() to correctly handle '\0' characters. + + Improved stability during startup when memory_limit is used. + + Replace alloca() with emalloc() for better stack protection. + + Added missing safe_mode checks inside ftok and itpc. + + Fixed address allocation routine in IMAP extension. + + Prevent open_basedir bypass via MySQL's LOAD DATA LOCAL. + + Fixes DoS in readfile() function, see CAN-2005-0596. + - php4-pear now includes PEAR::Mail 1.1.3 (closes: #257688) + - debian/control: change libpng3-dev build-dep to libpng12-dev + - Add Turkish debconf translation, thanks to Osman Yuksel. + (closes: #252940) + + * Andres Salomon : + - New upstream release (4.3.7). The following patches are dropped: + 007-dba_fix.patch + 008-xbithack.patch + 011-curl_api_update.patch + 012-curl_deprecated_opts.patch. + - Add 013-force_getaddrinfo.patch, so that getaddrinfo support is + always enabled (instead of doing check during build). + + * Steve Langasek : + - Enumerate supported SAPIs in both the module postinst and the module + config script, to avoid "question not found" errors from debconf. + This doesn't give us automatic support for new SAPIs as they're + added, but it avoids trying to configure SAPIs that we don't support + (e.g., caudium), and it also sidesteps shell syntax errors caused by + strangely-named subdirectories. + - Remove apache2 from the TODO list, because it's done + (closes: #243793). + - Add /var/lib/php4 to the list of directories for the apache2 module, + so we don't end up with a missing session dir (closes: #240962). + - s/modules-config/apache-modconf/, now that the canonical name of the + apache-common tool has changed + - Drop references to php3 in README.Debian, and document the + simplified process for enabling php4 in apache 1.3 (closes: #244564). + - Enable large files support for all SAPIs (closes: #249500). + - Fix commented-out default include path in php.ini (closes: #250274). + + -- Adam Conrad Wed, 14 Jul 2004 18:06:42 -0600 + +php4 (4:4.3.4-4) unstable; urgency=low + + * Drop apache2 work-around patch and add build-dep on apache2 2.0.48-8, + now that #228840 is fixed. + * Fix FTBFS problem caused by curl api changes, adding patches 011 and + 012 (closes: #239159). + * Add phpapi Provides for libapache2-mod-php4 (closes: #240386). + * Add versioned build-dep for pcre, as apache2 has proven that pcre-3.9 + and older won't work (closes: #215069). + * Tighten build-dep versions to match upstream's autoconf version checks + (closes: #214060). + + -- Andres Salomon Fri, 26 Mar 2004 23:27:27 -0500 + +php4 (4:4.3.4-3) unstable; urgency=low + + * Andres Salomon : + - Fix incorrect php.ini path in CLI manpage (closes: #233757). + - Add libapache2-mod-php4 module (closes: #214611). + * Updated Japanese debconf translation; thanks to Kenshi Muto + (closes: #222424). + * Build php4-gd against libgd2-xpm, removing the need for a separate + php4-gd2 package (closes: #235390, #206045, #135664). + * Add new Catalan debconf translation; thanks to Aleix Badia i Bosch + (closes: #236630). + * Add new Spanish debconf translation; thanks to Carlos Valdivia + Yagüe (closes: #235052). + + -- Steve Langasek Sat, 28 Feb 2004 12:11:57 -0600 + +php4 (4:4.3.4-2) unstable; urgency=low + + * Add build-depends on autoconf, missed earlier (closes: #235012). + * Minor updates to README.Debian list of supported extensions. + * Fix integer size mismatch in snmp extension affecting 64-bit + platforms + + -- Steve Langasek Thu, 26 Feb 2004 22:25:27 -0600 + +php4 (4:4.3.4-1) unstable; urgency=low + + * New upstream version. Update local patch set accordingly, with help + from Andres Salomon . + - includes fix for snmpget() not closing its socket + (closes: #207363). + * Update build-depends to libdb4.2-dev, to match apache-dev + (closes: #231692). + * Drop translations of stale templates, and add new German debconf + translation; thanks to Alwin Meschede + (closes: #232270). + * Add new Danish debconf translation; thanks to Claus Hindsgaul + (closes: #233887). + * Move local patches into debian/patches/ for easier management, and + add debian/rules targets for build-time application of patches. + * Fix a problem with PHP "xbithack" causing ini scope leakage + (closes: #230047). + * Re-enable the openssl extension statically, since we now know for + sure that the php4-imap problems are a glibc bug (closes: #197450). + * Fix pear to set /usr/bin/php4 instead of /usr/bin/php for the value + of php_bin, so PEAR-managed scripts work correctly + (closes: #228381). In addition, use alternatives for /usr/bin/php + for the benefit of user scripts (closes: #185283). + * Set the default session save_path to /var/lib/php4 instead of to + /tmp, and create this directory such that all users (for php4-cgi) + can create files there and access their own files once created, but + not see the names of other files in the directory (closes: #139810). + * Drop our override of upstream's register_globals default + (closes: #230878). + + -- Steve Langasek Sat, 14 Feb 2004 10:23:24 -0600 + +php4 (4:4.3.3-5) unstable; urgency=low + + * Have php4-pear Suggest: php4-dev, for PECL extensions + (closes: #225969). + * Recompiled against the new version of libxslt, to get rid of the + dependency on libxsltbreakpoint (closes: #224806). + * Also recompiled against the new version of libc-client (closes: #227347). + * Fix pear to not expect to be able to twiddle locks when running as + non-root, which also seems to fix a memory utilization problem + (closes: #225026). + * Make php4-imap depend on libapache-mod-ssl, since this seems to be + the only reliable way of getting apache to stop segfaulting. + * Build-depend on libt1-dev, which replaces t1lib-dev. + + -- Steve Langasek Mon, 5 Jan 2004 22:53:18 -0600 + +php4 (4:4.3.3-4) unstable; urgency=low + + * Fix prerm script to remove mod_php4, *not* mod_perl, from the + config (Closes: #216889). + * Use /etc/$i/httpd.conf instead of /etc/$i to decide whether to + call modules-config. + * Don't invoke debconf unless we have to in the postinst, to reduce + the risk of interactions between modules-config and our questions. + * Add Dutch debconf translation; thanks to Tim Dijkstra + (closes: #221439). + * Sync dba lock handling against upstream CVS HEAD, to fix a bug with + truncating db4 files when opening with 'c' (create). + (Closes: #221559). + + -- Steve Langasek Tue, 21 Oct 2003 16:49:03 -0500 + +php4 (4:4.3.3-3) unstable; urgency=low + + * Disable -gstabs on ia64, since this debugging symbol type is + apparently unknown there; we should now have clean builds (with + appropriate debugging symbols) on all archs. + + -- Steve Langasek Mon, 20 Oct 2003 19:07:40 -0500 + +php4 (4:4.3.3-2) unstable; urgency=low + + * Don't call db_stop in the postinst, as this seems to cause problems + for modules-config (closes: #215663, #215584). + * Remove duplicate -prefer-pic flag on caudium build, in hope of + making libtool do something sensible on ia64,hppa (closes: #216020). + * Always build with debugging symbols, per current policy. + * Unconditionally call dh_strip, which knows about DEB_BUILD_OPTIONS; + and call install -s when installing shared extensions by hand. + * Fix upstream build rules to not call libtool --silent. + + -- Steve Langasek Wed, 15 Oct 2003 23:19:55 -0500 + +php4 (4:4.3.3-1) unstable; urgency=low + + * New upstream release. + * Add Japanese debconf translation; thanks to Kenshi Muto + (closes: #211961). + * Fix caudium handling to always grab the current pike version from + dpkg when constructing include paths (closes: #212585). + * Bump the c-client build dependencies to use the new -dev package + name. + * Convert php4 postinst/prerm scripts to use the new apache + modules-config interface. + + -- Steve Langasek Sun, 21 Sep 2003 17:26:31 -0500 + +php4 (4:4.3.2+rc3-6) unstable; urgency=low + + * Add Brazilian Portuguese debconf translation; thanks to André Luís + Lopes (closes: #207078). + * Catch debian/control up with debian/rules for the zendapi -> phpapi + transition. + + -- Steve Langasek Sun, 31 Aug 2003 20:35:57 -0500 + +php4 (4:4.3.2+rc3-5) unstable; urgency=low + + * Kill the lintian warning on the grammar in the copyright file. + * Redirect apacheconfig I/O to /dev/tty, to work around debconf + behavior (for real this time). Closes: #207468, #206404. + * Replace 'zendapi' with 'phpapi', since the former does not + accurately describe the ABI changes that affect modules and can + leave some packages installable but broken (closes: #208020). Also, + remove the versioned conflicts with php4-{mysql,pgsql}, since this + now supersedes. + * Add French debconf translation; thanks to Michel Grentzinger + (closes: #207662). + + -- Steve Langasek Sat, 23 Aug 2003 21:43:24 -0500 + +php4 (4:4.3.2+rc3-4) unstable; urgency=low + + * Have all php extensions automatically detect and configure for any + installed SAPIs (closes: #143436). + * Remove spurious dependencies from php4-dev, and replace autoconf2.13 + with autoconf (closes: #180497). + * Conflict with old php4-pgsql as we do with php4-mysql, as it + manifests the same bug. + * Add preliminary rules for building apache2 SAPI, but don't enable. + * Call db_stop before trying to run apacheconfig (closes: #206404). + * Check for the existence of /etc/php4 before trying to rmdir it, + since there are apparently those who remove such directories + prematurely (closes: #206120). + + -- Steve Langasek Sun, 17 Aug 2003 00:19:38 -0500 + +php4 (4:4.3.2+rc3-3) unstable; urgency=low + + * Fixes for spurious package dependencies + * Fix the paths emitted by php-config, so we can build php4-pgsql et al. + + -- Steve Langasek Fri, 15 Aug 2003 23:44:55 -0500 + +php4 (4:4.3.2+rc3-2) unstable; urgency=low + + * Make sure pear.conf is properly marked as a conffile, by bumping + DH_COMPAT to 3. + * Generate all per-extension postinsts/prerms at build time, instead + of managing them by hand. + * Get rid of bogus, non-FHS directories from the caudium build. + * Install the upstream php manpage in the php4-cgi package + (closes: #175836). + * Prevent null dereferencing in ldap_explode_dn() (closes: #205405). + * Hard-code /usr/share/pear at the end of the include path, for + backwards compatibility. + * Debconf support for PHP extension registration, including + po-debconf support (closes: #122353). + * Fix interpreter path in /usr/bin/pear. + * Make php4-pear depends: php4-cgi (closes: #182393). + + -- Steve Langasek Wed, 13 Aug 2003 22:39:08 -0500 + +php4 (4:4.3.2+rc3-1) unstable; urgency=low + + * New upstream version. + - includes fix for buffer overflow crashes in imap module + (closes: #191640) + - includes fix for dysfunctional open_basedir directive + (closes: #197803) + - include fix for various XSS vulnerabilities (closes: #200736) + * Recompile against newest libc-client libs, following another soname + change (closes: #199049) + * Replace db2 with db4. + * Trim down the cgi sapi rules, since it will now build both cli and + cgi for us by default. + * Kludge the caudium sapi, by hard-coding the include path we need for + pike headers. + * Copy the lex/yacc-generated .c and .h files into the build + directories, since generating them at build time gives wildly + different, and undisputably broken, results. + * Update the install rules so they're compatible with current upstream + handling of pear and the various SAPIs. + * Add '=shared' to the --enable-xslt option, to get the right results + for that extension. + * Move PEAR extensions from /usr/share/pear to /usr/share/php. + * Conflict with php4-mysql=4:4.2.3-14, due to bizarre Zend errors. + + -- Steve Langasek Wed, 6 Aug 2003 22:43:28 -0500 + +php4 (4:4.2.3-14) unstable; urgency=low + + * Disable openssl extensions AGAIN. It appears that this double-linking mess + is still causing nasty segfaults. + (closes: #188014, #188025, #188058, #189202, #189653) + + -- Adam Conrad Sun, 20 Apr 2003 17:31:59 -0600 + +php4 (4:4.2.3-13) unstable; urgency=low + + * Revert NET-SNMP patch and build php4-snmp against UCD-SNMP again + (closes: #185534) + * Build against libmm13, as libmm12 no longer exists (closes: #187401) + * Rebuild caudium-php4 against latest caudium-dev + * Re-enable openssl linking and functions, now that our glibc 2.3 + problems appear to be ironed out. + * Enable xslt and exslt support in php4-domxml (closes: #172881) + + -- Adam Conrad Thu, 3 Apr 2003 05:53:24 -0700 + +php4 (4:4.2.3-12) unstable; urgency=low + + * Rebuild php4-sybase against libct1 (closes: #184461) + + -- Steve Langasek Sat, 8 Mar 2003 20:03:33 -0600 + +php4 (4:4.2.3-11) unstable; urgency=low + + * Remove pike header location detection from debian/rules and do it + properly in sapi/caudium/config.m4, using pike7.2-config --version + + -- Adam Conrad Mon, 3 Mar 2003 23:33:26 -0700 + +php4 (4:4.2.3-10) unstable; urgency=low + + * Added patch to build with NET-SNMP 5.x + * Updated build-dep for libc-client to 2003debian + (closes: #181565, #182854, #169886) + * Updated build-dep for libcurl to libcurl2-dev (closes: #179722) + * Added -mieee to alpha build to solve FPE errors (closes: #180656) + * Removed arch-specific logic to build with gcc-3.2 on arm, since gcc-3.2 + is now the default compiler on all architectures. + * Add libwrap0-dev to the end of the build-depends to work around #183041. + Someone remember to remove this later when the bug is fixed. :) + * Build against newer libsablot0-dev (closes: #179886, #181550) + * Introduce ugly hack in debian/rules to get the pike includes + directory right for the caudium SAPI. + + -- Adam Conrad Sun, 2 Mar 2003 12:49:07 -0700 + +php4 (4:4.2.3-9) unstable; urgency=low + + * Fix caudium-php4 to not conflict with php4-pear (closes: #175415). + + -- Steve Langasek Sun, 5 Jan 2003 16:40:20 -0600 + +php4 (4:4.2.3-8) unstable; urgency=low + + * Fix typo in debian/rules + * Rebuild to bring in sync with latest caudium packages + + -- Adam Conrad Wed, 25 Dec 2002 20:00:59 -0700 + +php4 (4:4.2.3-7) unstable; urgency=low + + * Set a sane default for safe_mode_exec_dir (closes: #122920). + * Rebuild against libmm-dev on i386, instead of against the + no-longer-available libmm11-dev which Provides: the same + (closes: #173509). + + -- Steve Langasek Mon, 16 Dec 2002 22:48:40 -0600 + +php4 (4:4.2.3-6) unstable; urgency=low + + * Build with PEAR for all SAPIs, so that the built-in include_path is + set correctly (overkill?). Closes: #169786, #172321 + * Change section of php4-dev package to devel. + * Add libkrb5-dev to build-depends, since libc-client2002-dev doesn't + pull it in (closes: #173313). + * Depend on coreutils instead of fileutils, since the latter is now an + empty package (closes: #171265). + + -- Steve Langasek Sun, 15 Dec 2002 23:20:30 -0600 + +php4 (4:4.2.3-5) unstable; urgency=low + + * Fix (snip, snip) the upstream build scripts, so that libphp4.so + isn't worthlessly linked against the problematic openssl libs + (closes: #165699, #165718, #165719, #166414). + * Update config.{sub,guess} so that the package builds on mips + platforms (closes #173218) + * Replace libc-client-ssl2001-dev with libc-client2002-dev in build + dependencies, fixing various php4-imap segfaults (closes: #169610, + #169769). + + -- Steve Langasek Sun, 15 Dec 2002 19:42:43 -0600 + +php4 (4:4.2.3-4) unstable; urgency=low + + * Remove build dependency on non-extant libmagick5-dev, which is no + longer used anyway (closes: #169829, #172402). + * Add myself to the Uploaders: field of the control file. + + -- Steve Langasek Sat, 14 Dec 2002 12:52:06 -0600 + +php4 (4:4.2.3-3) unstable; urgency=low + + * Backport a patch from CVS to sanitize control characters in php_url_parse() + to prevent ASCII control injection in fopen() calls. + + -- Adam Conrad Thu, 12 Sep 2002 16:29:46 -0600 + +php4 (4:4.2.3-2) unstable; urgency=low + + * I'm a moron (thanks to James Troup for pointing this out). + * Change gcc-3.1 references in debian/rules to gcc-3.2. + * Change GD build-dep to libgd-xpm-dev until GD package mess is worked out. + + -- Adam Conrad Tue, 10 Sep 2002 12:18:21 -0600 + +php4 (4:4.2.3-1) unstable; urgency=low + + * New upstream version + * Added a patch from Ginger Alliance to eliminate warnings in xslt compile + * Messed with the php4-imap build: + - compiling with SSL support (closes: #122700) + - commented out the static-on-i386 hack, libc-client is now linked dynamically + * Sessions should finally be fixed, however I won't tag the bugs "woody" + until I know for sure. (if you were affected, please test and send + followups to me) + * Updated arm build-dep to use gcc-3.2 since gcc-3.1 is gone now. + + -- Adam Conrad Tue, 10 Sep 2002 09:02:51 -0600 + +php4 (4:4.2.2-3) unstable; urgency=low + + * Fix typo resulting in php4-odbc not having a postinst + (closes: #157116, #157927) + * Build against latest caudium-dev to made caudium-php4 installable + again. (closes: #158247) + * Update build-deps to swap libpng3 for libpng2. (closes: #158908) + + -- Adam Conrad Sat, 7 Sep 2002 01:22:57 -0600 + +php4 (4:4.2.2-2) unstable; urgency=low + + * Pulled --with-ndbm out of ./configure, as libc6 no longer ships with + headers or the library for db1 (closes: #156141, #155889) + * Update build deps to build against libmm12 (closes: #155042) + * php4-curl no longer depends on libcurl2-ssl (closes: #155015) + + -- Adam Conrad Sat, 10 Aug 2002 01:12:47 -0600 + +php4 (4:4.2.2-1) unstable; urgency=medium + + * New upstream + * Fixes input validation vulnerability in rfc1867.c (closes: #153850) + * Added missing prerm/postinst for php4-xslt (oops) + + -- Adam Conrad Mon, 22 Jul 2002 11:58:53 -0600 + +php4 (4:4.2.1-3) unstable; urgency=low + + * Yet more build fixes. This time, bump the arm build-dep from gcc-3.0 to + gcc-3.1 to avoid compiler errors. I love the arm toolchain. No, really. + + -- Adam Conrad Wed, 29 May 2002 17:40:30 -0600 + +php4 (4:4.2.1-2) unstable; urgency=low + + * Applied small patch to fix building on non-32-bit architectures + (closes: #148231) + * Added still /more/ documentation about the unserializer, sessions, + and the session.save_handler php.ini option. + + -- Adam Conrad Sun, 26 May 2002 14:43:55 -0600 + +php4 (4:4.2.1-1) unstable; urgency=low + + * The "When is Debian going to have new software like XF^H^HPHP 4.2?" release. + * Probably the last update (barring huge packaging bugs or plain broken + binaries) before starting on a complete reorg of the PHP packages. + * Deserializer now works on big-endian architectures (addresses bug #121391 + and probably others) + * This release probably fixes a whole bunch of bugs. Will be going through + the bug list and playing the reproducibility game after the upload. + * Default include_path in php.ini now set to include pear. + * Upstream default for register_globals HAS CHANGED. In the Debian php.ini + we are still using "register_globals = On" for compatibility reasons, + however our packages will change too. This is a warning for anyone + packaging PHP scripts and applications to make sure you'll be compatible + with the new default once it's set. + + -- Adam Conrad Sun, 26 May 2002 06:24:21 -0600 + +php4 (4:4.1.2-4) unstable; urgency=high + + * No binaries were harmed in the making up this upload. + * Updated README.Debian and changelog. All other files untouched, + as the binaries were merely unpacked and repacked. + - Added a note to README.Debian about how to properly set up + Apache for use with php4, if the installation didn't (and it usually + doesn't ) get it right. + - Added a note to README.Debian about the unserializer (and sessions) + being messed up on big endian architectures. It's too late to try + to get a proper fix in for this, so we're just going to have to cope. + + -- Adam Conrad Fri, 26 Apr 2002 12:27:40 -0600 + +php4 (4:4.1.2-3.1) unstable; urgency=low + + * The 'I broke it, I have to take credit for it' release. + * Rebuild the package to get proper binary dependencies on alpha. + + -- Steve Langasek Sun, 31 Mar 2002 17:13:09 -0600 + +php4 (4:4.1.2-3) unstable; urgency=low + + * Switched to --with-regex=php (from =system). This fixes all the + problems with eregi/parse_url/fopen/etc on Alpha. + * Cleaned up long descriptions (closes: #130977, #130954) + + -- Adam Conrad Wed, 27 Mar 2002 15:11:43 -0700 + +php4 (4:4.1.2-2) unstable; urgency=low + + * New maintainer (closes: #132980) + * Enabling unixodbc support (closes: #107201) + * Changed the install-modules target in build/rules_pear.mk so that + it will error out in the case of an empty modules directory or + failure to install modules (closes: #135304) + + -- Adam Conrad Tue, 12 Mar 2002 00:25:41 -0700 + +php4 (4:4.1.2-1) unstable; urgency=high + + * New upstream version with a security fix. This + supercedes 4.1.1-2.2 from Steve Langasek: + * Fix an error in the handling of MIME file upload headers, which left + open a potential security hole. (Closes: #136063) + * Fixed gcc-3.0 fix :-) + * Thanks for fixing apache-common fix + * This version should fix session bugs with upstream fix (closes: #133877) + * With a brutal change to main/SAPI.c try to fix(?) authorize bugs + + -- Petr Cech Thu, 28 Feb 2002 11:14:26 +0100 + +php4 (4:4.1.1-2.1) unstable; urgency=low + + * Non-maintainer upload. + * loosen apache-common dependency to make us forwards-compatible, as + recommended by the apache maintainer. + * use gcc-3.0 when building on arm, because the default toolchain on + that arch has Issues (closes: #135906, #135913). + + -- Steve Langasek Tue, 26 Feb 2002 09:59:49 -0600 + +php4 (4:4.1.1-2) unstable; urgency=medium + + * Rebuild with apache 1.3.23. + * This package is in maintainer change mode. Though I orphaned it I'm not + going to change maintainer to QA, because we already have fresh blood. + * ext/gd/gd.c: s/HAVE_GD_GIF/HAVE_GD_GIF_CREATE/ to build correctly with + libgd which has GIF support (fixed included upstream) + * debian/control: + - Build-Depends: s/libgd1g-dev/libgd-dev/ + also libc-client at least version 4:2001adebian-6 to fix some segfaults + * ext/standard/head.c: make the setcookie() thingie test more simple + + -- Petr Cech Mon, 11 Feb 2002 20:07:22 +0100 + +php4 (4:4.1.1-1) unstable; urgency=high + + * New upstream bugfix release. + * debian/control: php4-gd - Conflicts/Replaces: php4-gd2 if I ever get + to upload it + * debian/rules: Correctly supply modified CFLAGS to build process + + -- Petr Cech Fri, 28 Dec 2001 23:23:47 +0100 + +php4 (4:4.1.0-2) unstable; urgency=low + + * debian/php4-cgi.README.Debian: fix typo (closes: #123866) + * debian/rules: remove --enable-mbstr-enc-trans as it breaks parametr + parsing (closes: #121403) + * debian/README.Debian: document shmmax increase (closes: #119688) + + -- Petr Cech Fri, 14 Dec 2001 09:59:59 +0100 + +php4 (4:4.1.0-1) unstable; urgency=high + + * Finally final 4.1.0 + * Urgency to reflect previous version + * debian/control: php4-pear depends on php4-cgi + + -- Petr Cech Thu, 13 Dec 2001 23:09:54 +0100 + +php4 (3:4.1-2) unstable; urgency=high + + * FIxes from CSV 4.1.0RC5. Looks like it was not the release after all. + * ext/exif/exif.c: MFH + * ext/ldap/ldap.c: small crash fix from HEAD + * and misc tiny changes. Really :-) + * ext/imap/php_imap.c: HIGH. fix from CVS (imap_rfc822_parse_adrlist) changing + the argument + + -- Petr Cech Sun, 9 Dec 2001 00:01:37 +0100 + +php4 (3:4.1-1) unstable; urgency=medium + + * Final 4.1.0 (not released) + * NEWS: s/4.0/4.1/ + * Build with GD1. It should fix some GD bugs, as gd 2.0.1 is supposed to be + a beta version with known bugs. How should I know. + * sablot extension removed upstream. So use XSLT (C/R in place) + * Apply fix for file_exists() from tilo (closes: #114409) + * "Cannot redeclare" were fixed in previous RCs (closes: #112341) + * previous version is build in hppa and ia64, so I assume it + (closes: #115391) + * Add note to sybase_ct, that it conflicts with mod_gzip folowing a user + report. + * This should fix the "final HTML> stripped" bug that was introduced + in 4.0.6-3. (closes: #110415). + * add --enable-ucd-snmp-hack to try to fix segfaults with ucd-snmp + + -- Petr Cech Mon, 26 Nov 2001 14:56:50 +0100 + +php4 (3:4.0.100-1) unstable; urgency=low + + * Really a 4.1.0RC2 + * Remove hack for apache 1.3.14, as we build-depends on 1.3.22 anyway + * Build-depends: libexpat1 (>= 1.95.2-2.1) for the .1 + * Added Provides: zendapi-$version to php4 and php4-cgi + * Made modules depend on zendapi-$version instead of php4|php4-cgi. + Please use this in your php4-$module packages + * Apply c-client hack only to i386 most architectures don't support linking + both PIC and non-PIC code. I'm still affrai to do this on i386, as it + crashes a lot more :( + * Apply some CVS patches + + -- Petr Cech Wed, 14 Nov 2001 20:50:19 +0100 + +php4 (3:4.0.99-4) unstable; urgency=medium + + * Recompile because of new version of caudium. + (I really hope this gets into testing soon as php in testing + now doesn't do apache 1.3.22) + + -- Petr Cech Fri, 9 Nov 2001 11:11:46 +0100 + +php4 (3:4.0.99-3) unstable; urgency=medium + + * Recompile for new libexpat1 (closes: #116623 and others) + * upstream: ext/gd/gd.c, ext/iconv/iconv.c + * crypt(): defalt to using DES crypt() (closes: #117092) + * debian/rules: disable libmm in -cgi build. Will lesser the impact + of the infamous /tmp/session_mm.reg + * apply patch to Zend, which should fix the "cannot redeclare" error. + It's still a bug in your code though (use include_once). More changes + to this are comming (upstream). + * Add some documentation to sybase + + -- Petr Cech Mon, 22 Oct 2001 11:20:46 +0200 + +php4 (3:4.0.99-2) unstable; urgency=low + + * "Some days are just no good" release. + * Recompile with apache 1.3.22 from Incoming + * Deal with automake going to 1:1.4 and automake1.5 + + -- Petr Cech Fri, 19 Oct 2001 15:02:00 +0200 + +php4 (3:4.0.99-1) unstable; urgency=low + + * This is really 4.1.0RC1, but ... + * Applied setcookie(), which is not in upstream yet + + -- Petr Cech Fri, 19 Oct 2001 12:05:20 +0200 + +php4 (3:4.0.6.7rc3-3) unstable; urgency=medium + + * Fix dependency in caudium-php4. Sorry for this + + -- Petr Cech Fri, 19 Oct 2001 11:28:07 +0200 + +php4 (3:4.0.6.7rc3-2) unstable; urgency=medium + + * Recompile with recent caudium/pike. Please, no new version so it can get + into testing :) + * debian/control: move php4-pear to suggests + * Fix setcookie() again. I really hate this bug + * Build-Depends: re2c - it's usually not needed, but if you make some + strange changes to the parser ... + * FIx automake 1.5 build problems (I hope) + + -- Petr Cech Thu, 18 Oct 2001 12:03:39 +0200 + +php4 (3:4.0.6.7rc3-1) unstable; urgency=low + + * New upstream test release. + + -- Petr Cech Fri, 5 Oct 2001 09:23:35 +0000 + +php4 (3:4.0.6.7rc2-3) unstable; urgency=low + + * "Let's try to fix some bugs" release. + * Add some patches: ldap (does this fix things?), pgsql, + domxml + * Build-Conflicts: automake (>= 1.5) for now + + -- Petr Cech Tue, 2 Oct 2001 10:55:23 +0200 + +php4 (3:4.0.6.7rc2-2) unstable; urgency=low + + * Enable recode extension (the library is LGPL) - shared + * Enable iconv extension - in main php4. Experimental + * Build-Depends: s/libgd-dev/libgd2-dev/ + * Build-Depends: libxml2-dev (>= 2.4.2) (Closes: #112304) + and fix autoconf macros (Closes: #113980) + * Improve?? description of PEAR (Closes: #112432) + + -- Petr Cech Sat, 22 Sep 2001 10:37:42 +0200 + +php4 (3:4.0.6.7rc2-1) unstable; urgency=medium + + * 2nd release candidate + * ext/mbstring: fix compile (cp1252) + * ext/standard/url_scanner_ex: off by one + * WARNING: caudium builds with Zend Threading enabled, but other + modules don't. So you cannot safely use DSO with caudium + * Added some Build-Conflicts - with broken libmysqlclient + - with libtool 1.4b + + -- Petr Cech Mon, 10 Sep 2001 18:04:27 +0200 + +php4 (3:4.0.6-6) unstable; urgency=medium + + * The "Paul Hampson fixes release". + * Closed those atexit() bugs. Now to find out, how to make libtool link with + gcc instead of ld :(( + * ext/standard/head.c: Fix setcookie("bla) (closes: #109524, #109697) + Thanks to Paul Hampson for finding the cause, though I've used another + fix - fixed changes in CVS made in -3 I think. Silly me to think, that + all "small" changes are fixes. + * libc-client2001 was fixed in -5, so add a (closes: #109202) here + * Conflicts: only with libtool 1.4b-{1,2,3}. libtool 1.4.1 is OK + + -- Petr Cech Sat, 1 Sep 2001 20:59:40 +0200 + +php4 (3:4.0.6-5) unstable; urgency=low + + * Recompile for libc-client2001 (I hope it doesn't break anything else) + And many other libraries. + * ATTENTION. php4 still doesn't work with autoconf 2.52 and thus libtool 1.4b!! + You have to get libtool 1.4 to be able to use phpize. + + -- Petr Cech Wed, 22 Aug 2001 23:26:08 +0200 + +php4 (3:4.0.6-4) unstable; urgency=high + + * Add pear/CODING_STANDARDS into php4-pear (fixes 105574. closed too early. sorry) + * Fix the nasty segfaults with mail(). That'll teach me taking upstream + changes without looking. Thanks Cvetan Ivanov for the correct fix (also upstream now) + (closes: #105686, #105878). + + -- Petr Cech Fri, 20 Jul 2001 23:07:30 +0200 + +php4 (3:4.0.6-3) unstable; urgency=high + + * ext/standard/mail.c: security fix + * debian/control: Build-Depends: libtool (>= 1.4) + * ext/curl/curl.c: fix typo + * ext/gd/config.m4: fix typo + * ext/mcrypt/mcrypt.c: upstream buffer overflow fix + * ext/mhash/mhash.c: upstream buffer overflow fix + * ext/pgsql/pgsql.c: fix + * ext/posix/config.m4: check for getpgid + * ext/sablot/sablot.c: fix leaks + * ext/standard/url* : fixes + * ext/sysvshm/sysvshm.c: fixes + * Zend/*: small fixes + + -- Petr Cech Fri, 13 Jul 2001 16:21:04 +0200 + +php4 (3:4.0.6-2) unstable; urgency=low + + * pear/Makefile.in: add IT_Error.php to installed files (closes: #103087) + * debian/control: - allow also libcurl-ssl-dev as Build-Depends (closes: #103618) + - libfreetype6-dev to Build-Depends + - add auto* suite to php4-dev depends (closes: #104199) + * debian/rules: - build gd module with freetype2 support + - move common ./configure flags to COMMON_CONFIG + - build with mbstring support + + -- Petr Cech Fri, 13 Jul 2001 08:22:02 +0200 + +php4 (3:4.0.6-1) unstable; urgency=medium + + * New upstream release. + * NOTE: new extension will probably be in another upload, to get this + into testing ... + + -- Petr Cech Mon, 25 Jun 2001 20:43:24 +0200 + +php4 (3:4.0.5.6rc3-3) unstable; urgency=low + + * The "I hate sablot release". Recompile with 0.60 + * debian/php4-domxml.postrm: also fix the :: (closes: #101306) + * debian/rules: --enable-ctype - still EXPERIMENTAL!!! Bug upstream + + -- Petr Cech Mon, 18 Jun 2001 09:46:17 +0200 + +php4 (3:4.0.5.6rc3-2) unstable; urgency=low + + * ext/sablot/config.m4: link sablot.so with -lsablot, not main php4 + * build/ ... : upstream fix for building with automake 1.4-pX + * don't fail, when libssl-dev is not installed. sigh + + -- Petr Cech Thu, 14 Jun 2001 23:36:34 +0200 + +php4 (3:4.0.5.6rc3-1) unstable; urgency=low + + * New upstream test release. + * Recompile with apache 1.3.20 + * debian/control: + - php4-dev: Depends: bison, flex (closes: #100634) + - Build-Depends: libcurl-dev (>=7.8) + * debian/rules: + - add --enable-bcmath to all rules (closes: #100491) + * Zend/zend.c: apply upstream fix to allow building of caudium + + -- Petr Cech Tue, 12 Jun 2001 22:27:26 +0200 + +php4 (3:4.0.5.6rc2-1) unstable; urgency=low + + * New upstream test release. + * FIx regex/regex.h (int regoff_t) + * fix php4-cgi build with pcre - don't use supplied pcre + * Fix wddx support (closes: #99468) + * Add missing $(INSTALL_ROOT) to sapi/caudium/config.m4 + + -- Petr Cech Fri, 8 Jun 2001 11:37:07 +0200 + +php4 (3:4.0.5.6rc1-1) unstable; urgency=low + + * New upstream test release with new bugs :)) + * moved pear from /usr/lib/php4 to /usr/share/php4 + * Whups. Sorry about the epoch 3: . It somehow slipped in, so I'll + have to live with it + + -- Petr Cech Wed, 16 May 2001 14:14:04 +0200 + +php4 (3:4.0.5-2) unstable; urgency=low + + * Build-Depend on newer libmhash-dev, as it supposedly doesn't + compile on current woody (closes: #96555) + * Build-Depends: s/freetype2/libttf-dev/ + * Stop building php4-pgsql - move to non-US + * Build-Deps on new libsablot0 + + -- Petr Cech Thu, 10 May 2001 10:43:02 +0200 + +php4 (3:4.0.5-1) unstable; urgency=medium + + * New upstream release. + * recompile with new sablot - how I hate this (closes: #95401) + * Merge XML into main php4 + * Reword README.Debian (closes: #89667) + * Enable wddx + * debian/*.postinst: * only ask upon first install, not upgrade (closes: #93452) + * fix typos (closes: #94118) + * Added support for Sybase/MS SQL Server (using FreeTDS) + using patch from: + http://rpms.arvin.dk/php/source/patches/php-sybase_ct.patch + thanks to Bradley Bell for the patch + * ext/pcre : two upstream fixes + * ext/sablot/sablot.c: small upstream fix + * build/buildcheck.sh : fixes to allow compile with libtool 1.4 + * ext/standard/exec.c: upstream fixes + * sapi/apache/mod_php4.c: off by one fix + * sapi/cgi/cgi_main.c: fix POST bug + * main/snprintf.c: upstream fix + + -- Petr Cech Wed, 3 May 2001 22:17:10 +0200 + +php4 (4.0.4.5rc6-2) unstable; urgency=low + + * Build-depends: libcurl-dev will pull libcurl2 (closes: #92994) + * TSRM/TSRM.c: upstream fix + * ext/pgsql: upstream fix + + -- Petr Cech Thu, 5 Apr 2001 17:51:09 +0200 + +php4 (4.0.4.5rc6-1) unstable; urgency=low + + * New upstream test release. + * Don't mention CGI support, as it's not so for a long time. + + -- Petr Cech Wed, 4 Apr 2001 13:47:45 +0200 + +php4 (4.0.4.5rc5-1) unstable; urgency=low + + * New upstream test release. + * ask about /etc/php4/cgi/php.ini also + * It's really recompiled for 1.3.19 (closes: #91901, #91822) + * problems with modules documented (closes: #81141, #82611) + + -- Petr Cech Mon, 2 Apr 2001 09:38:16 +0200 + +php4 (4.0.4.5rc3-1) unstable; urgency=low + + * New upstream RC release + * debian/rules: s/with-yp/enable-yp/ to really enable YP support. Discovered + on broken potato upload. -0potato2 is fixed + * Looks like there was a bug in latest build, this should fix it (closes: #92018) + * remove libmcal0 workaround + + -- Petr Cech Wed, 28 Mar 2001 21:15:36 +0200 + +php4 (4.0.4.5rc2-1) unstable; urgency=low + + * New upstream release test release 4.0.5RC2. + * debian/rules: Add lintian overrides + * debian/control: * add libexpat1-dev to Build-Depends + * add libmcal0 to Build-Depends since libmcal0-dev is + missing this dependancy :(( Bug filled + * ext/socket/socket.c: minor upstream patch + + -- Petr Cech Mon, 26 Mar 2001 20:43:49 +0200 + +php4 (4.0.4pl1-6) unstable; urgency=low + + * NEVER RELEASED + * Build-depends on libcurl1-dev (>= 7.6.1-5), which fixes the libcurl1 or + libcurl1-ssl problem. + * remove dh_testversion and use versioned Build-depends instead + + -- Petr Cech Tue, 13 Mar 2001 23:20:58 +0100 + +php4 (4.0.4pl1-5) unstable; urgency=low + + * Add lintian overrides + * Rebuild with correct libgd-dev installed. Sorry + (closes: #88490, #88255, #88371, #88619, #88635) + * Closed by fixed libjpeg (closes: #85865, #88141) + + -- Petr Cech Tue, 6 Mar 2001 17:26:41 +0100 + +php4 (4.0.4pl1-4) unstable; urgency=low + + * The "Enable what you can" release. + * Enable sablot extension (many files) (closes: #84073) + * Enable mcal extension (finaly closes: #65688, #85925) + * Build-Conflicts: bind-dev - this supposedly causes unresolved symbols. + Why? + * ext/pgsql/pgsql.c: apply tiny patch, which should fix postgres + problems. There is a better patch in CVS, but it needs changes to Zend + * pear/pear.in: binary is php4 no php (closes: #87848) + * ext/domxml/config.m4: link with -lxml2 (closes: #87457) + * debian/README.Debian: add notes about ldap, imap and mhash extensions + * debian/{control,rules}: activate bz2 extension + * php4.ini-dist: comment out include_path so php will use compiled in + path (closes 2nd part of 87848) + + -- Petr Cech Wed, 28 Feb 2001 10:18:11 +0100 + +php4 (4.0.4pl1-3) unstable; urgency=medium + + * Fixed postrm issues. Sorry + + -- Petr Cech Sun, 4 Feb 2001 06:13:00 +0100 + +php4 (4.0.4pl1-2) unstable; urgency=medium + + * debian/control: Build-depends: xlibs-dev (seems it's missing and causes + failed builds for arm, m68k and powerpc) + s/libsnmp4.1/libsnmp4.2/ (closes: #84139) + * debian/php4.*: make LoadModule matching case insensitive (fixes 83641 + for unstable) + + -- Petr Cech Wed, 31 Jan 2001 10:14:29 +0100 + +php4 (4.0.4pl1-1) unstable; urgency=high + + * New upstream version. + * This release fixes some security problems. + * Some patches from previous versions are not here. + * debian/control: Build-depends on newer libcurl1-dev, remove librecode-dev + * debian/control: add libjpeg62-dev to build-depends from powerpc buildlog + (hmm. Where ir Roman?) + * debian/php4{,-cgi}.postinst: don't mark php.ini as conffile and install it + when it doesn't already exist. I should find a way to check, that the default + php.ini changed and user should update it. + * debian/php4{,-cgi}.postrm: cleanup the /etc/php4 dir after purge + * fix xml.so not working with php4-cgi + + -- Petr Cech Thu, 23 Jan 2001 11:12:59 +0100 + +php4 (4.0.4final-6) unstable; urgency=medium + + * OK. Now also fix the prerm issues (closes: #81418) and to ease + that thanks for submiting bugs (closes: #81818, #81819) + * some upstream updates: browsercap, php-config + + -- Petr Cech Wed, 10 Jan 2001 14:04:19 +0100 + +php4 (4.0.4final-5) unstable; urgency=medium + + * OK. Take a deep breath and fix those bloody postinst + bugs - fix it and rewrite from ed -> sed, because ed is not essential :( + closes: #80801. + * apply some upstream fixes. + * disable ctype extension - not yet ready + + -- Petr Cech Tue, 2 Jan 2001 13:40:35 +0100 + +php4 (4.0.4final-4) unstable; urgency=low + + * debian/libc-client.la: add -lpam -ldl -lcrypt + * fix php4-cgi.postinst bugs (closes: #80817, #80805, #80801) + + -- Petr Cech Fri, 29 Dec 2000 11:40:43 +0100 + +php4 (4.0.4final-3) unstable; urgency=low + + * Brown Xmas Sock Release + * Grr. correctly fix the php4 postinst error + (closes: #80303, #80324, #80326, #80359) + NMU by Wichert Akkerman (closes: #80381) + * also fix php4-cgi. NMU by Marcelo E. Magallon + (closes: #80406). + * fix fix for php4-cgi postinst s/apache/cgi/ + * apply some upstream fixes to ext/session/ + * domxml/config.m4: fix my -Lshared,/usr/lib error + * debian/rules: + * add --enable-ctype to both targets + * --diable-pear to CGI target + * generate Depends: php4 (=ver) | php4-cgi (=ver) + + -- Petr Cech Wed, 27 Dec 2000 15:29:56 +0100 + +php4 (4.0.4final-2) unstable; urgency=low + + * Run apacheconfig with --force-modules. + * Fix stupid bug in php4 and php4-cgi postinst. + * ext/sysvshm/sysvshm.c : upstream fix + + -- Petr Cech Thu, 21 Dec 2000 22:58:27 +0100 + +php4 (4.0.4final-1) unstable; urgency=low + + * New upstream version. + * Sorry for the version, but da-katie doesn't allow overwriting of files, notably + .orig.tar.gz. It's my fault I know, but it worked till now. + + -- Petr Cech Wed, 20 Dec 2000 01:32:34 +0100 + +php4 (4.0.4-0RC6.1) unstable; urgency=low + + * OK. Final final RC for 4.0.4. + * Build-depends on libxml2-dev (>= 2.2.7) because php needs this. + * Activate ndbm dba driver. + + -- Petr Cech Sun, 17 Dec 2000 19:43:51 +0100 + +php4 (4.0.4-0RC5.1) unstable; urgency=low + + * UNRELEASED. + * Final RC for 4.0.4. + * Some mods to README.Debian and TODO + + -- Petr Cech Wed, 13 Dec 2000 00:01:08 +0100 + +php4 (4.0.4-0RC4.1) unstable; urgency=low + + * New upstream beta release. Let's stabilize things now and add new + modules after final release of 4.0.4. + + -- Petr Cech Thu, 7 Dec 2000 10:12:11 +0100 + +php4 (4.0.4-0RC3.2) unstable; urgency=low + + * recompile with new libc-client200-dev. + * fix source recompile + * depend on fixed apache 1.3.14-2 + + -- Petr Cech Thu, 7 Dec 2000 00:49:14 +0100 + +php4 (4.0.4-0RC3.1) unstable; urgency=low + + * New upstream beta release. + * Add libxml2-dev to build-depends (closes: #78479). + * implement DEB_BUILD_OPTIONS + * fix apache build wrt. apxs + * fix typo in description of curl modules (closes: #78828) + + -- Petr Cech Tue, 5 Dec 2000 14:22:30 +0100 + +php4 (4.0.3pl1-7) unstable; urgency=low + + * Rebuild with apache 1.3.14-1 + + -- Petr Cech Fri, 1 Dec 2000 01:41:41 +0100 + +php4 (4.0.3pl1-6) unstable; urgency=low + + * add --enable-memory-limit + * add --enable-exif per request from William Ono. + * Add Suggests: phpdoc (yes. it's here). + * ext/standard/crypt.c - fix from CVS. + * ext/ftp/ftp.{c,h} - fix mkdir() and RETR, STOR + * ext/gd/gd.c - add format string + - add XBM to phpinfo() + * ext/imap/php_imap.{c,h} - CVS fixes + * main/main.c - fix CGI crash + - add HTTP_SERVER_VARS in CGI mode + * and many more. Taken from php4.srpm (thanks :)) + * recompile with apache 1.3.12-2.2 + * and hack large files support into DSO module. php4 doesn't use it now :(( + + -- Petr Cech Thu, 30 Nov 2000 00:01:39 +0100 + +php4 (4.0.3pl1-5) unstable; urgency=low + + * Back out changes about --enable-versioning + * ext/domxml/php_domxml.c : fix compilation with recent libxml2 (>=2.2.7) + + -- Petr Cech Tue, 21 Nov 2000 18:03:56 +0100 + +php4 (4.0.3pl1-4) unstable; urgency=low + + * Clarify README.Debian about the DB change a bit (dbm_ -> dba_*) + * Remove aliasing hack - deprecated upstream. (closes: #76558) + * Compile with libgd-dev again (Write 100x always reinstall libgd-dev). + * --enable-versioning and tweak debian/control a bit, let's see, what breaks + + -- Petr Cech Tue, 14 Nov 2000 10:00:54 +0100 + +php4 (4.0.3pl1-3) unstable; urgency=low + + * Activate curl module. + * Really enable shmop module. + * Fix include paths in phpize. Now everyone should be able to easilly build + php4 extension modules (php4-dbase anyone?). + + -- Petr Cech Mon, 6 Nov 2000 23:17:41 +0100 + +php4 (4.0.3pl1-2) unstable; urgency=low + + * Build with libgd-dev installed (NOT libgd-gif). + + -- Petr Cech Tue, 17 Oct 2000 02:08:36 +0200 + +php4 (4.0.3pl1-1) unstable; urgency=medium + + * New upstream bugfix release. + * Depend on libopenldap1 as with the newer ldap module crashes php&apache. + + -- Petr Cech Mon, 16 Oct 2000 15:30:55 +0200 + +php4 (4.0.3-2) unstable; urgency=high + + * Urgency=high because last upload didn't have it ad it fixes some + security holes. + * ext/domxml/config.m4: don't try to build then --without-domxml + + -- Petr Cech Thu, 12 Oct 2000 12:50:17 +0200 + +php4 (4.0.3-1) unstable; urgency=low + + * New upstream release. + - fixes also some string format bugs + * Build with fixed libmysqlclient10-dev. + + -- Petr Cech Thu, 12 Oct 2000 00:00:07 +0200 + +php4 (4.0.2-7) unstable; urgency=low + + * Really, really install libldap2-dev. + * Workaround broken libmysqlclient9-dev. It has broken (again) .so symlink. + + -- Petr Cech Tue, 10 Oct 2000 22:28:48 +0200 + +php4 (4.0.2-6) unstable; urgency=low + + * Again fix description a little bit. + * Correct build-depends. + * Sic. Recompile, because I've busted (libopenldap-dev instead of + libldap2-dev was installed). + * While at it install also new apache glibc NMU and recompile with it. + * Move PEAR from php4-dev to php4 and install ALL of PEAR. + * add --prefix=/usr + * debhelper v2 + * prepare for CURL module + * Updated README.Debian + * updated XML module from php4 CVS to close: #72360 + + -- Petr Cech Mon, 2 Oct 2000 14:36:35 +0200 + +php4 (4.0.2-5) unstable; urgency=low + + * Correct build-depends (libgd1-dev -> libgd-dev). Where is Roman? :) + * Add libdb2-dev (>= 2:2.7.7-2.1) to build-depends for glibc 2.1.94. + * and recompile with glibc 2.1.94 to fix it. + + -- Petr Cech Wed, 27 Sep 2000 09:00:27 +0200 + +php4 (4.0.2-4) unstable; urgency=low + + * Tweak description a little bit more. + + -- Petr Cech Sun, 24 Sep 2000 23:58:15 +0200 + +php4 (4.0.2-3) unstable; urgency=low + + * Add info about what modules and why are enabled/disabled + into README.Debian. + * Install not so many docs (only in -dev now). + * Enable calendar and sockets modules. + * Rearange package descriptions so module-specific comments + go first. + * Create domxml module aka xmlv2. + * Fix spelling wan't -> want (closes: #70544). + * Add libraries for gd module only when linking this one + and not globaly (closes: #71623). + * Say that we wait for ENTER (closes: #71769). + * Fix logic in prerm script (closes: #71770). + + -- Petr Cech Sun, 24 Sep 2000 17:54:52 +0000 + +php4 (4.0.2-2) unstable; urgency=low + + * Add info about what modules and why are enabled/disabled + into README.Debian. + * Install not so many docs (only in -dev now). + * Enable calendar and sockets modules. + * Rearange package descriptions so module-specific comments + go first. + * Create domxml module aka xmlv2. + * Fix building (small typo). + * Compile with libmysqlclient9-dev installed. + + -- Petr Cech Mon, 18 Sep 2000 23:46:40 +0200 + +php4 (4.0.2-1) unstable; urgency=low + + * The "Back from vacation" release. + * New upstream fixed (and bugs). + * Correct postm script (only cosmetic) closes: #67350, #68541 + * build with libpcre3, libldap2 + * Use modified patch from -3 (remove #define XML_... php_XML_...) + + -- Petr Cech Thu, 7 Sep 2000 23:17:59 +0200 + +php4 (4.0.1pl2-3) unstable; urgency=low + + * UNRELEASED + * Fixed the XML packages. + + -- Norman Jordan Thu, 10 Aug 2000 21:45:15 +0000 + +php4 (4.0.1pl2-2) unstable; urgency=low + + * Fix source archive. + + -- Petr Cech Tue, 11 Jul 2000 11:04:48 +0000 + +php4 (4.0.1pl2-1) unstable; urgency=low + + * New upstream bug fix release (variation of the patches in -2) + * Build with new libgd1 library (maybe still in Incoming) + * Move PEAR stuff to php4 package (closes: #66897). + + -- Petr Cech Sun, 9 Jul 2000 09:01:06 +0000 + +php4 (4.0.1-2) unstable; urgency=low + + * Apply some CVS diffs in an attempt to fix opendir() problems. + + -- Petr Cech Fri, 30 Jun 2000 09:04:24 +0000 + +php4 (4.0.1-1) unstable; urgency=low + + * New upstream release (taken from CVS tag php_4_0_1). + * --with-regex=system else it plays havoc. Dunno why ... + * remove autoconf,automake,aclocal from configure rules. + * Fix description of XML --help message (no, it's not MySQL). + + -- Petr Cech Wed, 28 Jun 2000 22:55:16 +0200 + +php4 (4.0.0-4) unstable; urgency=low + + * Add -dev package (closes: #65907). + * Add -cgi and -cgi-* packages (closes: #51097, #52855). + * --enable-filepro + * Tweak copyright file a bit. + * Generate mhash module (closes part of 63186). + * Ask to remove libphp4 from httpd.conf upon remove/purge. + * Fixed build-depends, thanks to Roman Hodek (closes: #65938). + (I told you the first time it won't work :)) + * Mark /etc/php4/cgi/php.ini as conffile. + * Every module now ask if it should be enabled on install + (if it's not already) and disabled on remove/purge. + + -- Petr Cech Tue, 20 Jun 2000 14:29:01 +0200 + +php4 (4.0.0-3) unstable; urgency=low + + * Ship correct php.ini (extension_dir=/usr/lib/php4/apache). + * Don't use included libmysqlclient and use system one (fixes + wrong location of mysqld.sock) + * link XML module dynamicly with system xmlparse and xmltok. + + -- Petr Cech Wed, 14 Jun 2000 22:30:07 +0000 + +php4 (4.0.0-2) unstable; urgency=low + + * fix the IS_SLASH bug (closes: #65625 and probably others as well). + * Really change the maintainer field. + + -- Petr Cech Wed, 14 Jun 2000 07:44:05 +0000 + +php4 (4.0.0-1) unstable; urgency=low + + * New maintainer. + * New upstream release. + * Fix dynamic module loading. + * Added Build-Depends (I wonder, if I got them right) + * Standards-Version: 3.1.1 + + -- Petr Cech Tue, 13 Jun 2000 13:40:56 +0000 + +php4 (4.0rc1-2) unstable; urgency=low + + * Compile with latest apache and libraries from woody + (Closes: #62631, #62640) + + -- Gergely Madarasz Wed, 19 Apr 2000 14:39:25 +0200 + +php4 (4.0rc1-1) unstable; urgency=low + + * New upstream version + * Fix db2 support (Closes: #61709) + * Fix gd support (Closes: #61708) + * Remove ucd-snmp-hack from config options + + -- Gergely Madarasz Sun, 16 Apr 2000 17:04:05 +0200 + +php4 (4.0b4pl1-2) unstable; urgency=low + + * Build with --disable-debug so it should work with the zend + optimizer (Closes: #60265) + * Build with --enable-trans-sid (Closes: #60430) + * Write some more about php4/php3 differences in the description + (Closes: #60155) + + -- Gergely Madarasz Fri, 17 Mar 2000 17:35:29 +0100 + +php4 (4.0b4pl1-1) unstable; urgency=low + + * New upstream version + * Upstream reorganized the build system quite a bit, lots of patches + removed + + -- Gergely Madarasz Wed, 23 Feb 2000 17:16:00 +0100 + +php4 (4.0b3-4) unstable; urgency=low + + * Add /etc/php4/apache/php.ini to conffiles (Closes: #54194) + * Add info file for apacheconfig + * Offer to run apacheconfig and/or apache-sslconfig in postinst + * Comment out sendmail_path from php.ini so the default sendmail path + should work (Closes: #51355) + + -- Gergely Madarasz Thu, 6 Jan 2000 14:38:20 +0100 + +php4 (4.0b3-3) unstable; urgency=low + + * Compile with libgd instead of libgd-gif + + -- Gergely Madarasz Tue, 4 Jan 2000 18:07:56 +0100 + +php4 (4.0b3-2) unstable; urgency=low + + * Build imap and ldap modules + * Fix rm -f in rules file (Closes: #51623) + + -- Gergely Madarasz Mon, 3 Jan 2000 16:54:19 +0100 + +php4 (4.0b3-1) unstable; urgency=low + + * Initial Release. + + -- Gergely Madarasz Tue, 16 Nov 1999 19:33:42 +0100 + --- php5-5.2.10.dfsg.1.orig/debian/NEWS +++ php5-5.2.10.dfsg.1/debian/NEWS @@ -0,0 +1,41 @@ +php5 (5.2.6-1) unstable; urgency=medium + + * Now uses system timezone database. + + Debian PHP now makes use of the system wide timezone database from the + tzdata package, making sure any updates there are automatically used + by PHP aswell. Note that this requires that the PHP process has access + to /etc/localtime and /usr/share/zoneinfo (this is usually the case). + + * New php5-dbg package. + + We are now shipping a php5-dgb package which will greatly aid in finding + the cause of many crashes that you may experience. So if you are going to + report a bug for a reproducible crash, please install this package before + sending a backtrace. + + * New libapache2-mod-php5filter package. + + We are now also shipping a new libapache2-mod-php5filter package which + uses the "Apache 2.0 filter-module support via DSO through APXS". + + -- Thijs Kinkhorst Wed, 23 Jul 2008 17:42:06 +0200 + +php5 (5.2.3-2) unstable; urgency=low + + The Suhosin patch is now enabled by default! + + For more information, see + . + + Special thanks to Blars Blarson for providing a sparc machine for testing + that the patch seems to work okay on that architecture. If you experience + otherwise let us know! + + Suggestions are welcome for default configuration options, examples, + documentation, etc. + + In any event please report successes and/or failures to us at + pkg-php-maint@lists.alioth.debian.org. + + -- sean finney Thu, 12 Jul 2007 23:38:43 +0200 --- php5-5.2.10.dfsg.1.orig/debian/php5-cgi.postinst +++ php5-5.2.10.dfsg.1/debian/php5-cgi.postinst @@ -0,0 +1,40 @@ +#!/bin/sh + +set -e + +#DEBHELPER# + +if [ "$1" != "configure" ]; then + exit 0 +fi + +phpini="/etc/php5/cgi/php.ini" +# LEGACY SUPPORT +# previous versions of php did not ship $phpini as a conffile nor did +# they use anything like ucf. as a result, we need to help transition +# those files into ucf a little more easily by updating unmodified +# ini files before registering them +# +# if we're upgrading from a pre-ucf version of php: +if dpkg --compare-versions "$2" le-nl "5.1.6-4"; then + # if the SAPI config file already exists and is unmodified + if [ -f "$phpini" ]; then + oldmd5=`md5sum $phpini | cut -d' ' -f1` + if [ "$oldmd5" = "c85605baab79fbcd3c289e442eb3caa2" ]; then + # then silently update it before registering via ucf + cp /usr/share/php5/php.ini-dist $phpini + fi + fi +fi +# END LEGACY SUPPORT + +ucf /usr/share/php5/php.ini-dist $phpini + +update-alternatives \ + --install /usr/bin/php-cgi php-cgi /usr/bin/php5-cgi 50 \ + --slave /usr/share/man/man1/php-cgi.1.gz php-cgi.1.gz /usr/share/man/man1/php5-cgi.1.gz + +update-alternatives \ + --install /usr/lib/cgi-bin/php php-cgi-bin /usr/lib/cgi-bin/php5 50 + +exit 0 --- php5-5.2.10.dfsg.1.orig/debian/control +++ php5-5.2.10.dfsg.1/debian/control @@ -0,0 +1,363 @@ +Source: php5 +Section: php +Priority: optional +Maintainer: Ubuntu Developers +XSBC-Original-Maintainer: Debian PHP Maintainers +Uploaders: Adam Conrad , Jeroen van Wolffelaar , Ondřej Surý , Sean Finney , Thijs Kinkhorst , Raphael Geissert +Build-Depends: apache2-prefork-dev, autoconf2.13, automake1.4, bison, chrpath, debhelper (>= 5), flex, freetds-dev, libapr1-dev (>= 1.2.7-8), libbz2-dev, libcurl4-openssl-dev | libcurl-dev, libdb4.7-dev | libdb4.6-dev, libedit-dev (>= 2.9.cvs.20050518-1), libexpat1-dev (>= 1.95.2-2.1), libfreetype6-dev, libgcrypt11-dev, libgd2-xpm-dev, libgmp3-dev, libjpeg62-dev, libkrb5-dev, libldap2-dev, libmhash-dev (>= 0.8.8), libmysqlclient-dev, libncurses5-dev, libpam0g-dev, libpcre3-dev (>= 6.6), libpng12-dev, libpq-dev, libpspell-dev, librecode-dev, libsasl2-dev, libsnmp-dev, libsqlite0-dev, libssl-dev, libt1-dev, libtidy-dev, libtool, libwrap0-dev, libxmltok1-dev, libxml2-dev, libxslt1-dev (>= 1.0.18), quilt, re2c, unixodbc-dev, zlib1g-dev, tzdata +Standards-Version: 3.8.2 +XS-Original-Vcs-Git: git://git.debian.org/pkg-php/php.git +XS-Original-Vcs-Browser: http://git.debian.org/?p=pkg-php/php.git +Homepage: http://www.php.net/ + +Package: php5 +Architecture: all +Depends: libapache2-mod-php5 (>= ${source:Version}) | libapache2-mod-php5filter (>= ${source:Version}) | php5-cgi (>= ${source:Version}), php5-common (>= ${source:Version}) +Description: server-side, HTML-embedded scripting language (metapackage) + This package is a metapackage that, when installed, guarantees that you + have at least one of the three server-side versions of the PHP5 interpreter + installed. Removing this package won't remove PHP5 from your system, however + it may remove other packages that depend on this one. + . + PHP5 is an HTML-embedded scripting language. Much of its syntax is borrowed + from C, Java and Perl with a couple of unique PHP-specific features thrown + in. The goal of the language is to allow web developers to write dynamically + generated pages quickly. This version of PHP5 was built with the Suhosin patch. + +Package: php5-common +Architecture: any +Depends: sed (>= 4.1.1-1), ${shlibs:Depends} +Suggests: php5-suhosin +Provides: php5-json +Conflicts: php5-json +Description: Common files for packages built from the php5 source + This package contains the documentation and example files relevant to all + the other packages built from the php5 source. + . + PHP5 is an HTML-embedded scripting language. Much of its syntax is borrowed + from C, Java and Perl with a couple of unique PHP-specific features thrown + in. The goal of the language is to allow web developers to write dynamically + generated pages quickly. This version of PHP5 was built with the Suhosin patch. + +Package: libapache2-mod-php5 +Section: httpd +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, mime-support, ${apache2:Depends}, php5-common (= ${binary:Version}), libmagic1, ucf, tzdata +Conflicts: libapache2-mod-php4, libapache2-mod-php5filter +Provides: ${php:Provides} +Suggests: php-pear +Description: server-side, HTML-embedded scripting language (Apache 2 module) + This package provides the PHP5 module for the Apache 2 webserver (as + found in the apache2-mpm-prefork package). Please note that this package + ONLY works with Apache's prefork MPM, as it is not compiled thread-safe. + . + ${php:Extensions} + . + PHP5 is an HTML-embedded scripting language. Much of its syntax is borrowed + from C, Java and Perl with a couple of unique PHP-specific features thrown + in. The goal of the language is to allow web developers to write dynamically + generated pages quickly. This version of PHP5 was built with the Suhosin patch. + +Package: libapache2-mod-php5filter +Section: httpd +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, mime-support, ${apache2:Depends}, php5-common (= ${binary:Version}), libmagic1, ucf, tzdata +Conflicts: libapache2-mod-php4, libapache2-mod-php5 +Provides: ${php:Provides} +Suggests: php-pear +Description: server-side, HTML-embedded scripting language (apache 2 filter module) + This package provides the PHP5 Filter module for the Apache 2 webserver (as + found in the apache2-mpm-prefork package). Please note that this package + ONLY works with Apache's prefork MPM, as it is not compiled thread-safe. + . + Unless you specifically need filter-module support, you most likely + should instead install libapache2-mod-php5. + . + ${php:Extensions} + . + PHP5 is an HTML-embedded scripting language. Much of its syntax is borrowed + from C, Java and Perl with a couple of unique PHP-specific features thrown + in. The goal of the language is to allow web developers to write dynamically + generated pages quickly. This version of PHP5 was built with the Suhosin patch. + +Package: php5-cgi +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, mime-support, php5-common (= ${binary:Version}), libmagic1, ucf, tzdata +Provides: ${php:Provides} +Suggests: php-pear +Description: server-side, HTML-embedded scripting language (CGI binary) + This package provides the /usr/lib/cgi-bin/php5 CGI interpreter built + for use in Apache 2 with mod_actions, or any other CGI httpd that + supports a similar mechanism. Note that MOST Apache users probably + want the libapache2-mod-php5 package. + . + ${php:Extensions} + . + PHP5 is an HTML-embedded scripting language. Much of its syntax is borrowed + from C, Java and Perl with a couple of unique PHP-specific features thrown + in. The goal of the language is to allow web developers to write dynamically + generated pages quickly. This version of PHP5 was built with the Suhosin patch. + +Package: php5-cli +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, mime-support, php5-common (= ${binary:Version}), libmagic1, ucf, tzdata +Provides: ${php:Provides} +Suggests: php-pear +Description: command-line interpreter for the php5 scripting language + This package provides the /usr/bin/php5 command interpreter, useful for + testing PHP scripts from a shell or performing general shell scripting tasks. + . + ${php:Extensions} + . + PHP5 is an HTML-embedded scripting language. Much of its syntax is borrowed + from C, Java and Perl with a couple of unique PHP-specific features thrown + in. The goal of the language is to allow web developers to write dynamically + generated pages quickly. This version of PHP5 was built with the Suhosin patch. + +Package: php5-dev +Depends: autoconf2.13, automake1.4, libssl-dev, libtool, shtool, php5-common (>= ${binary:Version}) +Conflicts: ${libtool:Conflicts} +Architecture: any +Description: Files for PHP5 module development + This package provides the files from the PHP5 source needed for compiling + additional modules. + . + PHP5 is an HTML-embedded scripting language. Much of its syntax is borrowed + from C, Java and Perl with a couple of unique PHP-specific features thrown + in. The goal of the language is to allow web developers to write dynamically + generated pages quickly. This version of PHP5 was built with the Suhosin patch. + +Package: php5-dbg +Depends: php5-common (= ${binary:Version}), libapache2-mod-php5 (= ${binary:Version}) | libapache2-mod-php5filter (= ${binary:Version}) | php5-cgi (= ${binary:Version}) | php5-cli (= ${binary:Version}) | php5-curl (= ${binary:Version}) | php5-gd (= ${binary:Version}) | php5-gmp (= ${binary:Version}) | php5-imap (= ${binary:Version}) | php5-interbase (= ${binary:Version}) | php5-ldap (= ${binary:Version}) | php5-mcrypt (= ${binary:Version}) | php5-mhash (= ${binary:Version}) | php5-mysql (= ${binary:Version}) | php5-odbc (= ${binary:Version}) | php5-pgsql (= ${binary:Version}) | php5-pspell (= ${binary:Version}) | php5-recode (= ${binary:Version}) | php5-snmp (= ${binary:Version}) | php5-sqlite (= ${binary:Version}) | php5-sybase (= ${binary:Version}) | php5-tidy (= ${binary:Version}) | php5-xmlrpc (= ${binary:Version}) | php5-xsl (= ${binary:Version}) +Recommends: gdb +Section: debug +Priority: extra +Architecture: any +Description: Debug symbols for PHP5 + This package provides the debug symbols for PHP5 needed for properly + debugging errors in PHP5 with gdb. + . + PHP5 is an HTML-embedded scripting language. Much of its syntax is borrowed + from C, Java and Perl with a couple of unique PHP-specific features thrown + in. The goal of the language is to allow web developers to write dynamically + generated pages quickly. This version of PHP5 was built with the Suhosin patch. + +Package: php-pear +Architecture: all +Depends: php5-common (>= ${source:Version}), php5-cli | php4-cli +Recommends: gnupg +Conflicts: php-xml-util +Suggests: php5-dev | php4-dev +Replaces: php4-pear (<< 4:4.4.0-0), php-xml-util +Provides: php-xml-util +Description: PEAR - PHP Extension and Application Repository + This package contains the base PEAR classes for PHP, as well as the PEAR + installer. Many PEAR classes are already packaged for Debian, and can be + easily identified by names beginning with "php-", such as php-db and + php-auth. Note: to build and install precompiled PECL extensions, you + will need one of the php development packages installed. + . + PHP5 is an HTML-embedded scripting language. Much of its syntax is borrowed + from C, Java and Perl with a couple of unique PHP-specific features thrown + in. The goal of the language is to allow web developers to write dynamically + generated pages quickly. This version of PHP5 was built with the Suhosin patch. + +Package: php5-curl +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, ${php:Depends}, php5-common (= ${binary:Version}) +Description: CURL module for php5 + CURL is a library for getting files from FTP, GOPHER, HTTP server. + . + PHP5 is an HTML-embedded scripting language. Much of its syntax is borrowed + from C, Java and Perl with a couple of unique PHP-specific features thrown + in. The goal of the language is to allow web developers to write dynamically + generated pages quickly. This version of PHP5 was built with the Suhosin patch. + +Package: php5-gd +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, ${php:Depends}, php5-common (= ${binary:Version}) +Description: GD module for php5 + This package provides a module for handling graphics directly from PHP + scripts. It supports the PNG, JPEG, XPM formats as well as Freetype/ttf fonts. + . + PHP5 is an HTML-embedded scripting language. Much of its syntax is borrowed + from C, Java and Perl with a couple of unique PHP-specific features thrown + in. The goal of the language is to allow web developers to write dynamically + generated pages quickly. This version of PHP5 was built with the Suhosin patch. + +Package: php5-gmp +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, ${php:Depends}, php5-common (= ${binary:Version}) +Description: GMP module for php5 + This package provides a module for arbitrary precision arithmetic via the + GNU Multiple Precision (GMP) Arithmetic Library. + . + PHP5 is an HTML-embedded scripting language. Much of its syntax is borrowed + from C, Java and Perl with a couple of unique PHP-specific features thrown + in. The goal of the language is to allow web developers to write dynamically + generated pages quickly. This version of PHP5 was built with the Suhosin patch. + +Package: php5-ldap +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, ${php:Depends}, php5-common (= ${binary:Version}) +Description: LDAP module for php5 + This package provides a module for LDAP functions in PHP scripts. + . + PHP5 is an HTML-embedded scripting language. Much of its syntax is borrowed + from C, Java and Perl with a couple of unique PHP-specific features thrown + in. The goal of the language is to allow web developers to write dynamically + generated pages quickly. This version of PHP5 was built with the Suhosin patch. + +Package: php5-mhash +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, ${php:Depends}, php5-common (= ${binary:Version}) +Description: MHASH module for php5 + This package provides a module for mhash functions in PHP scripts. + . + PHP5 is an HTML-embedded scripting language. Much of its syntax is borrowed + from C, Java and Perl with a couple of unique PHP-specific features thrown + in. The goal of the language is to allow web developers to write dynamically + generated pages quickly. This version of PHP5 was built with the Suhosin patch. + +Package: php5-mysql +Architecture: any +Depends: libmysqlclient16, ${shlibs:Depends}, ${misc:Depends}, ${php:Depends}, php5-common (= ${binary:Version}) +Conflicts: php5-mysqli +Replaces: php5-mysqli +Description: MySQL module for php5 + This package provides modules for MySQL database connections directly from + PHP scripts. It includes the generic "mysql" module which can be used + to connect to all versions of MySQL, an improved "mysqli" module for + MySQL version 4.1 or later, and the pdo_mysql module for use with + the PHP Data Object extension. + . + PHP5 is an HTML-embedded scripting language. Much of its syntax is borrowed + from C, Java and Perl with a couple of unique PHP-specific features thrown + in. The goal of the language is to allow web developers to write dynamically + generated pages quickly. This version of PHP5 was built with the Suhosin patch. + +Package: php5-odbc +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, ${php:Depends}, php5-common (= ${binary:Version}) +Description: ODBC module for php5 + This package provides a module for database access through ODBC drivers. + It uses the unixODBC library as an ODBC provider. It also contains the + pdo_odbc module, for use with the PHP Data Object extension. + . + PHP5 is an HTML-embedded scripting language. Much of its syntax is borrowed + from C, Java and Perl with a couple of unique PHP-specific features thrown + in. The goal of the language is to allow web developers to write dynamically + generated pages quickly. This version of PHP5 was built with the Suhosin patch. + +Package: php5-pgsql +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, ${php:Depends}, php5-common (= ${binary:Version}) +Description: PostgreSQL module for php5 + This package provides a module for PostgreSQL database connections + directly from PHP scripts. It also includes the pdo_pgsql module for + use with the PHP Data Object extension. + . + PHP5 is an HTML-embedded scripting language. Much of its syntax is borrowed + from C, Java and Perl with a couple of unique PHP-specific features thrown + in. The goal of the language is to allow web developers to write dynamically + generated pages quickly. This version of PHP5 was built with the Suhosin patch. + +Package: php5-pspell +Architecture: any +Depends: ${shlibs:Depends}, ${php:Depends}, ${misc:Depends}, php5-common (= ${binary:Version}) +Description: pspell module for php5 + This package provides a module for pspell functions in PHP scripts. + . + PHP5 is an HTML-embedded scripting language. Much of its syntax is borrowed + from C, Java and Perl with a couple of unique PHP-specific features thrown + in. The goal of the language is to allow web developers to write dynamically + generated pages quickly. This version of PHP5 was built with the Suhosin patch. + +Package: php5-recode +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, ${php:Depends}, php5-common (= ${binary:Version}) +Description: recode module for php5 + This package provides a module for recode - character set recoding. + . + PHP5 is an HTML-embedded scripting language. Much of its syntax is borrowed + from C, Java and Perl with a couple of unique PHP-specific features thrown + in. The goal of the language is to allow web developers to write dynamically + generated pages quickly. This version of PHP5 was built with the Suhosin patch. + +Package: php5-snmp +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, ${php:Depends}, php5-common (= ${binary:Version}) +Description: SNMP module for php5 + This package provides a module for SNMP functions in PHP scripts. + . + PHP5 is an HTML-embedded scripting language. Much of its syntax is borrowed + from C, Java and Perl with a couple of unique PHP-specific features thrown + in. The goal of the language is to allow web developers to write dynamically + generated pages quickly. This version of PHP5 was built with the Suhosin patch. + +Package: php5-sqlite +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, ${php:Depends}, php5-common (= ${binary:Version}) +Description: SQLite module for php5 + This package provides a module allowing you to use the SQLite self-contained + database engine from within your PHP scripts, eliminating the need for a full + SQL server installation like MySQL or PostgreSQL. It also includes the + pdo_sqlite module, for use with the PHP Data Object extension. + . + PHP5 is an HTML-embedded scripting language. Much of its syntax is borrowed + from C, Java and Perl with a couple of unique PHP-specific features thrown + in. The goal of the language is to allow web developers to write dynamically + generated pages quickly. This version of PHP5 was built with the Suhosin patch. + +Package: php5-sybase +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, ${php:Depends}, php5-common (= ${binary:Version}) +Provides: php5-mssql +Description: Sybase / MS SQL Server module for php5 + This package provides a module for Sybase and Microsoft SQL Server + database connections directly from PHP scripts. It also includes the + pdo_dblib module for use with the PHP Data Object extension. + . + PHP5 is an HTML-embedded scripting language. Much of its syntax is borrowed + from C, Java and Perl with a couple of unique PHP-specific features thrown + in. The goal of the language is to allow web developers to write dynamically + generated pages quickly. This version of PHP5 was built with the Suhosin patch. + +Package: php5-tidy +Architecture: any +Depends: ${shlibs:Depends}, ${php:Depends}, ${misc:Depends}, php5-common (= ${binary:Version}) +Description: tidy module for php5 + This package provides a module for tidy functions in PHP scripts. + . + Tidy is an extension based on Libtidy (http://tidy.sf.net/) and allows + a PHP developer to clean, repair, and traverse HTML, XHTML, and XML + documents -- including ones with embedded scripting languages such as PHP + or ASP within them using OO constructs. + . + PHP5 is an HTML-embedded scripting language. Much of its syntax is borrowed + from C, Java and Perl with a couple of unique PHP-specific features thrown + in. The goal of the language is to allow web developers to write dynamically + generated pages quickly. This version of PHP5 was built with the Suhosin patch. + +Package: php5-xmlrpc +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, ${php:Depends}, php5-common (= ${binary:Version}) +Description: XML-RPC module for php5 + This package provides a module for XML-RPC functions in PHP scripts. + . + PHP5 is an HTML-embedded scripting language. Much of its syntax is borrowed + from C, Java and Perl with a couple of unique PHP-specific features thrown + in. The goal of the language is to allow web developers to write dynamically + generated pages quickly. This version of PHP5 was built with the Suhosin patch. + +Package: php5-xsl +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, ${php:Depends}, php5-common (= ${binary:Version}) +Description: XSL module for php5 + This package provides a module for XSL using the libxslt XSL parser. + . + PHP5 is an HTML-embedded scripting language. Much of its syntax is borrowed + from C, Java and Perl with a couple of unique PHP-specific features thrown + in. The goal of the language is to allow web developers to write dynamically + generated pages quickly. This version of PHP5 was built with the Suhosin patch. + --- php5-5.2.10.dfsg.1.orig/debian/libapache2-mod-php5filter.conf +++ php5-5.2.10.dfsg.1/debian/libapache2-mod-php5filter.conf @@ -0,0 +1,4 @@ + + AddInputFilter PHP php phtml php3 + AddOutputFilter PHP php phtml php3 + --- php5-5.2.10.dfsg.1.orig/debian/php5-module.postinst +++ php5-5.2.10.dfsg.1/debian/php5-module.postinst @@ -0,0 +1,27 @@ +#!/bin/sh + +set -e + +# here we test for upgrades from versions prior to the config-file-scan-dir +# migration. +# +# to avoid lots of scary warnings about duplicate-loaded modules, each +# module will remove its "extension=" line from each SAPI's php.ini file +# when upgrading from a "prior version". this will be the last time we +# ever muck with such files in maintainer scripts. really. promise :) + +if [ "$2" ] && dpkg --compare-versions "$2" lt "5.1.6-5"; then + extension_re='^[[:space:]]*extension[[:space:]]*=[[:space:]]*@dsoname@\.so$' + for SAPI in apache apache2 cgi cli; do + ini_file="/etc/php5/$SAPI/php.ini" + if [ -f "$ini_file" ]; then + if grep -q "$extension_re" $ini_file; then + sed -i -e "/$extension_re/d" $ini_file + fi + fi + done +fi + +#EXTRA# +#DEBHELPER# + --- php5-5.2.10.dfsg.1.orig/debian/libapache2-mod-php5.prerm +++ php5-5.2.10.dfsg.1/debian/libapache2-mod-php5.prerm @@ -0,0 +1,20 @@ +#!/bin/sh + +set -e + +#DEBHELPER# + +if [ "$1" != "remove" -a "$1" != "purge" ]; then + exit 0 +fi + +if [ -e /etc/apache2/apache2.conf ]; then + if [ -e /etc/apache2/mods-enabled/php5.load ]; then + # set a flag to remember the original state + # useful when reinstalling the same version. + touch /etc/php5/apache2/.start + fi + a2dismod php5 || true +fi + +exit 0 --- php5-5.2.10.dfsg.1.orig/debian/php5-sybase.postinst.extra +++ php5-5.2.10.dfsg.1/debian/php5-sybase.postinst.extra @@ -0,0 +1,6 @@ +OLD_CONFFILE=/etc/php5/conf.d/sybase_ct.ini +if [ -e "$OLD_CONFFILE" ] && dpkg --compare-versions "$2" lt-nl 5.2.3-2 +then + rm $OLD_CONFFILE +fi + --- php5-5.2.10.dfsg.1.orig/debian/php5-common.php5.cron.d +++ php5-5.2.10.dfsg.1/debian/php5-common.php5.cron.d @@ -0,0 +1,7 @@ +# /etc/cron.d/php5: crontab fragment for php5 +# This purges session files older than X, where X is defined in seconds +# as the largest value of session.gc_maxlifetime from all your php.ini +# files, or 24 minutes if not defined. See /usr/lib/php5/maxlifetime + +# Look for and purge old sessions every 30 minutes +09,39 * * * * root [ -x /usr/lib/php5/maxlifetime ] && [ -d /var/lib/php5 ] && find /var/lib/php5/ -depth -mindepth 1 -maxdepth 1 -type f -cmin +$(/usr/lib/php5/maxlifetime) -delete --- php5-5.2.10.dfsg.1.orig/debian/php5-dev.lintian-overrides +++ php5-5.2.10.dfsg.1/debian/php5-dev.lintian-overrides @@ -0,0 +1 @@ +php5-dev: script-not-executable ./usr/lib/php5/build/run-tests.php --- php5-5.2.10.dfsg.1.orig/debian/modulelist +++ php5-5.2.10.dfsg.1/debian/modulelist @@ -0,0 +1,19 @@ +curl CURL +gd GD +gmp GMP +imap IMAP +interbase Interbase +ldap LDAP +mcrypt MCrypt +mhash MHASH +mysql MySQL +odbc ODBC +pgsql PostgreSQL +pspell pspell +recode recode +snmp SNMP +sqlite SQLite +sybase Sybase mssql +tidy tidy +xmlrpc XML-RPC +xsl XSL --- php5-5.2.10.dfsg.1.orig/debian/php5-dev.postinst +++ php5-5.2.10.dfsg.1/debian/php5-dev.postinst @@ -0,0 +1,17 @@ +#!/bin/sh + +set -e + +#DEBHELPER# + +if [ "$1" != "configure" ]; then + exit 0 +fi + +for i in php-config phpize; do + update-alternatives \ + --install /usr/bin/"$i" $i /usr/bin/"$i"5 50 \ + --slave /usr/share/man/man1/"$i".1.gz "$i".1.gz /usr/share/man/man1/"$i"5.1.gz +done + +exit 0 --- php5-5.2.10.dfsg.1.orig/debian/libapache2-mod-php5filter.dirs +++ php5-5.2.10.dfsg.1/debian/libapache2-mod-php5filter.dirs @@ -0,0 +1,3 @@ +/etc/apache2/mods-available +/etc/php5/apache2filter +/usr/lib/apache2/modules --- php5-5.2.10.dfsg.1.orig/debian/libapache2-mod-php5.conf +++ php5-5.2.10.dfsg.1/debian/libapache2-mod-php5.conf @@ -0,0 +1,4 @@ + + AddType application/x-httpd-php .php .phtml .php3 + AddType application/x-httpd-php-source .phps + --- php5-5.2.10.dfsg.1.orig/debian/php5-cgi.prerm +++ php5-5.2.10.dfsg.1/debian/php5-cgi.prerm @@ -0,0 +1,14 @@ +#!/bin/sh + +set -e + +#DEBHELPER# + +if [ "$1" != "remove" -a "$1" != "purge" ]; then + exit 0 +fi + +update-alternatives --remove php-cgi /usr/bin/php5-cgi +update-alternatives --remove php-cgi-bin /usr/lib/cgi-bin/php5 + +exit 0 --- php5-5.2.10.dfsg.1.orig/debian/php5-common.README.Debian +++ php5-5.2.10.dfsg.1/debian/php5-common.README.Debian @@ -0,0 +1,159 @@ +Table of Contents: +--------------------------------------------------------------------- +* Using php5 with threaded webservers (eg. apache2-mpm-worker, caudium) +* Problems starting apache2 with php5 +* Session storage +* Other caveats +* php5-cgi and apache2 +* Restarting your web server after installing modules +* Configuration layout +* Timezone data from system timezone database +* Further documentation, errata, etc + + +Using php5 with threaded webservers (eg. apache2-mpm-worker, caudium) +--------------------------------------------------------------------- + + After much back-and-forth with upstream (and even building our + packages thread-safe for a while), we're currently admitting defeat + on that front, and are NOT building any thread-safe versions of + PHP for any webservers. Our recommendation is that, if you need + to use a threaded webserver, you should use php5-cgi in either + 'normal' CGI mode, or in FastCGI mode. + +Adam Conrad Sun, 06 Feb 2005 08:24:56 -0700 + + +Problems starting apache2 with php5 +---------------------------------- + + At the time of writing, there are no *known* incompatibilities + between any of the php5 modules we ship. However, there have been + many bug reports in the past due to dynamically-loaded extensions, + and it's possible there are still bugs in the released packages. If + Apache fails to start after you install php5, check your list of + enabled extensions at the bottom of /etc/php5/apache2/php.ini (and in + the per-sapi configuration directory), and try commenting out or + reordering the extensions until you find a combination that works. + + For example, in the past the mhash extension was incompatible with + some other common extensions. To work around this, you could list + the mhash extension first in php.ini. + + If you find an extension-related bug in the Debian packages, and you + are willing to help debug the problem, please send us a bug report + that lists all enabled PHP5 extensions (extension=), in the order + in which they appear in php.ini, as well as all enabled Apache modules + (LoadModule), with version numbers where possible. + +Steve Langasek Fri, 26 Apr 2002 13:39:00 -0500 + + +Session storage +--------------- + + Session files are stored in /var/lib/php5. For security purposes, this + directory is unreadable by non-root users. This means that php5 running + from apache2, for example, will not be able to clean up stale session + files. Instead, we have a cron job run every 30 mins that cleans up + stale session files; /etc/cron.d/php5. You may need to modify how + often this runs, if you've modified session.gc_maxlifetime in your + php.ini; otherwise, it may be too lax or overly aggressive in cleaning + out stale session files. + +Andres Salomon Fri, 03 Sep 2004 03:12:54 -0400 + + +Other caveats +------------- + + * extension_dir and include_path should be commented out, if you don't need + special settings for them so php will look in compiled-in paths. If you set + them, you should also add appropriate php install directories there. + +php5-cgi and apache2 +--------------------------- + +In 99% of cases, what you probably want isn't php5-cgi at all, but rather +the libapache2-mod-php5 package, which will configure themselves on +installation and Just Work(tm). If, however, you have a need to use +the CGI version of php5 with apache2, the following should help +get you going, though there are dozens of different ways to do this. + +Please note that this process will never be made automatic, as php5-cgi +is meant to be a webserver-agnostic package that can be used with any +httpd, and we don't want it to conflict with the httpd-specific packages +such as libapache2-mod-php5. If both were installed side-by-side and both +were automatically enabled, the results would be a bit confusing, obviously. + +To use php5-cgi with apache2 + 1) activate CGI (it's on by default in default debian setups) + a) If using the prefork MPM, use 'a2enmod cgi' + b) If using a threaded MPM, use 'a2enmod cgid' + 2) activate mod_actions (a2enmod actions) + 3) Add the following to a config snippet in /etc/apache2/conf.d + + Action application/x-httpd-php /cgi-bin/php5 + + +Adam Conrad Sat, 04 Sep 2004 23:04:26 -0600 + +Restarting your web server after installing modules +--------------------------------------------------------------------- + +Many of the php modules (php5-mysql, for example) require that you +restart your webserver after installation. This currently isn't +done automatically, so changes won't take affect until you run +/etc/init.d/apache2 reload or your webserver's equivalent (some cases +may need to use "restart" instead of "reload" too) + +sean finney Sat, 09 Dec 2006 12:42:21 +0100 + +Configuration Layout +--------------------------------------------------------------------- + +Each of the 3 SAPI's (apache2/cgi/cli) have a different +central configuration file /etc/php5/$SAPI/php.ini. + +Additionally, each SAPI is configured with the compile-time option + + --with-config-file-scan-dir=/etc/php5/$SAPI/conf.d + +which for all SAPI's is actually a symlink pointing to a central +directory /etc/php5/conf.d. Any file found in this directory ending +in .ini will be treated as a configuration file by the php SAPI. + +The rationale with this method is that each SAPI can thus be +identically configured with a minimal amount of conffile handling, +but at the same time if you want to have SAPI-specific configuration, +you can just remove the symlink. + +sean finney Thu, 19 Oct 2006 23:33:05 +0200 + +Timezone data from system timezone database +--------------------------------------------------------------------- + +Debian PHP has been patched to use of the system wide timezone database +from the tzdata package, making sure any updates there are automatically +used by PHP aswell. + +Note that this requires that the PHP process has access to /etc/localtime +and /usr/share/zoneinfo. For any regular installation this should be the +case, but in specific secured environments when reading the timezone +database is impossible PHP will give a "Timezone database is corrupt - +this should *never* happen!" error. + +Thijs Kinkhorst Wed, 23 Jul 2008 17:42:06 +0200 + +Further documentation, errata, etc +--------------------------------------------------------------------- + +Errata and other general information about PHP in Debian can be found +in the debian wiki at: + + http://wiki.debian.org/PHP + +If after reading the documentation in this file you still have unanswered +questions, that's a good next place to go. + +sean finney Thu, 19 Oct 2006 22:57:52 +0200 --- php5-5.2.10.dfsg.1.orig/debian/watch +++ php5-5.2.10.dfsg.1/debian/watch @@ -0,0 +1,5 @@ +version=3 +opts=downloadurlmangle=s#/a/#/this/#,\ +filenamemangle=s#/get/(php-(5\.[0-9\.]*)\.tar\.gz)/.*#$1#,\ +dversionmangle=s/\.dfsg\.\d+// \ +http://www.php.net/downloads.php /get/php-(5\.[0-9\.]*)\.tar\.gz/from/a/mirror debian bash debian/dfsg-repack.sh --- php5-5.2.10.dfsg.1.orig/debian/compat +++ php5-5.2.10.dfsg.1/debian/compat @@ -0,0 +1 @@ +5 --- php5-5.2.10.dfsg.1.orig/debian/suhosin_patch.watch +++ php5-5.2.10.dfsg.1/debian/suhosin_patch.watch @@ -0,0 +1,7 @@ +# Check for new versions with: +# uscan --watchfile debian/suhosin_patch.watch --package suhosin-patch +# don't forget to update the version in this file when updating the patch! +version=3 + +http://www.hardened-php.net/suhosin/download.html \ + http://download.suhosin.org/suhosin-patch-(.*)\.patch\.gz 5.2.6-0.9.6.2 --- php5-5.2.10.dfsg.1.orig/debian/php5-mcrypt.substvars +++ php5-5.2.10.dfsg.1/debian/php5-mcrypt.substvars @@ -0,0 +1 @@ +php:Depends=phpapi-20060613 --- php5-5.2.10.dfsg.1.orig/debian/php5-common.TODO +++ php5-5.2.10.dfsg.1/debian/php5-common.TODO @@ -0,0 +1,7 @@ +- Debconf: support removing of extension lines from php.ini on + dpkg-reconfigure, not just adding. Adjust wording of debconf template + to match. +- move default config files out of /usr/share/doc/php5/examples, per + policy +- more modules +- roxen support (oh my) --- php5-5.2.10.dfsg.1.orig/debian/php5-sapi.postrm +++ php5-5.2.10.dfsg.1/debian/php5-sapi.postrm @@ -0,0 +1,18 @@ +#! /bin/sh + +set -e + +phpini=/etc/php5/@sapi@/php.ini + +case "$1" in +purge) + if which ucf >/dev/null 2>&1; then + ucf --purge $phpini + fi + rm -f $phpini + ;; +esac + +#DEBHELPER# + +exit 0 --- php5-5.2.10.dfsg.1.orig/debian/dfsg-repack.sh +++ php5-5.2.10.dfsg.1/debian/dfsg-repack.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +set -e + +if [ ! -f "$3" ] && [ ! -f "$1" ]; then + echo "This script must be run via uscan or by manually specifying the tarball" >&2 + exit 1 +fi + +tarball= + +[ -f "$3" ] && tarball="$3" +[ -z "$tarball" -a -f "$1" ] && tarball="$1" + +fname="$(basename "$tarball")" +tarball="$(readlink -f "$tarball")" + +tdir="$(mktemp -d)" +trap '[ ! -d "$tdir" ] || rm -r "$tdir"' EXIT + +zcat "$tarball" | tar --wildcards --delete '*/ext/dbase' > "$tdir/${fname/.gz}" +#touch -m -r "$tarball" "$tdir/${fname/.gz}" +gzip -9 "$tdir/${fname/.gz}" + +mv "$tarball" "$tarball.bkp" +mv "$tdir/$fname" "$tarball" --- php5-5.2.10.dfsg.1.orig/debian/source.lintian-overrides +++ php5-5.2.10.dfsg.1/debian/source.lintian-overrides @@ -0,0 +1,2 @@ +# The file belongs to an unused convinient code copy +php5 source: ancient-libtool ext/pdo_sqlite/sqlite/ltmain.sh 1.5.2 --- php5-5.2.10.dfsg.1.orig/debian/php5-sybase.preinst +++ php5-5.2.10.dfsg.1/debian/php5-sybase.preinst @@ -0,0 +1,12 @@ +#!/bin/sh +set -e + +OLD_CONFFILE=/etc/php5/conf.d/sybase_ct.ini +NEW_CONFFILE=/etc/php5/conf.d/mssql.ini +if [ -e "$OLD_CONFFILE" ] && dpkg --compare-versions "$2" lt-nl 5.2.3-2 +then + sed -e's/\(extension=[[:space:]]*\)sybase_ct\.so/\1mssql.so/' \ + $OLD_CONFFILE > $NEW_CONFFILE +fi + +#DEBHELPER# --- php5-5.2.10.dfsg.1.orig/debian/copyright.header +++ php5-5.2.10.dfsg.1/debian/copyright.header @@ -0,0 +1,42 @@ +This package was debianized by Gergely Madarasz on +Tue, 16 Nov 1999 19:33:42 +0100. + +Previous maintainers of the package also include: + Petr Cech , who did a LOT of work on these packages. + Adam Conrad , who got a significant chunk of input and + help from Steve Langasek and + Andres Salomon . + +The current maintainers can be contacted via the debian php packaging list: + pkg-php-maint@lists.alioth.debian.org + +It was downloaded from www.php.net/version5/downloads +Changes: removed ext/dbase dir (non-free) + +Noteworthy/non-trivial patches: + patch: suhosin.patch + contributor: http://www.hardened-php.net/ + copyright © 2006-2007 Stefan Esser + may be used/modified/redistributed under the terms of PHP itself + + patch: use_embedded_timezonedb.patch + contributor: Joe Orton + copyright © 2008 Red Hat, Inc. + may be used/modified/redistributed under the terms of PHP itself + +Upstream Authors: The PHP group for PHP5, Andi Gutmans and Zeev Suraski +for libzend + +The file ext/standard/rand.c contains the following clause with a statement +that isn't compatible with the DFSG: + "The code as Shawn received it included the following notice: + + Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura. When + you use this, send an e-mail to with + an appropriate reference to your work." +However, this requirement has been rescinded by the copyright holder in +message <48E334A2.6050301@math.sci.hiroshima-u.ac.jp> to bug #498621. + +Two different licences apply to this package, one for PHP5, the other for +libzend. Both licences are shown here below. + --- php5-5.2.10.dfsg.1.orig/debian/php5-common.postrm +++ php5-5.2.10.dfsg.1/debian/php5-common.postrm @@ -0,0 +1,12 @@ +#! /bin/bash + +set -e + +if [ "$1" = "purge" ] +then + rm -rf /var/lib/php5 +fi + +#DEBHELPER# + +exit 0 --- php5-5.2.10.dfsg.1.orig/debian/php5-interbase.substvars +++ php5-5.2.10.dfsg.1/debian/php5-interbase.substvars @@ -0,0 +1 @@ +php:Depends=phpapi-20060613 --- php5-5.2.10.dfsg.1.orig/debian/php5-imap/etc/php5/conf.d/imap.ini +++ php5-5.2.10.dfsg.1/debian/php5-imap/etc/php5/conf.d/imap.ini @@ -0,0 +1,2 @@ +# configuration for php IMAP module +extension=imap.so --- php5-5.2.10.dfsg.1.orig/debian/php5-interbase/etc/php5/conf.d/interbase.ini +++ php5-5.2.10.dfsg.1/debian/php5-interbase/etc/php5/conf.d/interbase.ini @@ -0,0 +1,2 @@ +# configuration for php Interbase module +extension=interbase.so --- php5-5.2.10.dfsg.1.orig/debian/php5-mcrypt/etc/php5/conf.d/mcrypt.ini +++ php5-5.2.10.dfsg.1/debian/php5-mcrypt/etc/php5/conf.d/mcrypt.ini @@ -0,0 +1,2 @@ +# configuration for php MCrypt module +extension=mcrypt.so --- php5-5.2.10.dfsg.1.orig/debian/patches/CVE-2009-3291.patch +++ php5-5.2.10.dfsg.1/debian/patches/CVE-2009-3291.patch @@ -0,0 +1,36 @@ +Description: fix certificate spoofing via null-byte certs +upstream, Origin: http://svn.php.net/viewvc?view=revision&revision=288329 +Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/php5/+bug/446313 + +diff -Nur php5-5.2.10.dfsg.1/ext/openssl/openssl.c php5-5.2.10.dfsg.1.new/ext/openssl/openssl.c +--- php5-5.2.10.dfsg.1/ext/openssl/openssl.c 2009-04-20 06:00:41.000000000 -0400 ++++ php5-5.2.10.dfsg.1.new/ext/openssl/openssl.c 2009-11-24 15:16:57.000000000 -0500 +@@ -3838,8 +3838,15 @@ + GET_VER_OPT_STRING("CN_match", cnmatch); + if (cnmatch) { + int match = 0; ++ int name_len = X509_NAME_get_text_by_NID(name, NID_commonName, buf, sizeof(buf)); + +- X509_NAME_get_text_by_NID(name, NID_commonName, buf, sizeof(buf)); ++ if (name_len == -1) { ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to locate peer certificate CN"); ++ return FAILURE; ++ } else if (name_len != strlen(buf)) { ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Peer certificate CN=`%.*s' is malformed", name_len, buf); ++ return FAILURE; ++ } + + match = strcmp(cnmatch, buf) == 0; + if (!match && strlen(buf) > 3 && buf[0] == '*' && buf[1] == '.') { +@@ -3854,10 +3861,7 @@ + + if (!match) { + /* didn't match */ +- php_error_docref(NULL TSRMLS_CC, E_WARNING, +- "Peer certificate CN=`%s' did not match expected CN=`%s'", +- buf, cnmatch); +- ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Peer certificate CN=`%.*s' did not match expected CN=`%s'", name_len, buf, cnmatch); + return FAILURE; + } + } --- php5-5.2.10.dfsg.1.orig/debian/patches/107-reflection_is_ext.patch +++ php5-5.2.10.dfsg.1/debian/patches/107-reflection_is_ext.patch @@ -0,0 +1,11 @@ +--- php.orig/ext/reflection/config.m4 ++++ php/ext/reflection/config.m4 +@@ -2,7 +2,7 @@ dnl $Id: config.m4,v 1.4.2.3.2.1 2006/08 + dnl config.m4 for extension reflection + + PHP_ARG_ENABLE(reflection, whether to enable reflection support, +-[ --disable-reflection Disable reflection support], yes, no) ++[ --disable-reflection Disable reflection support], yes) + + if test "$PHP_REFLECTION" != "no"; then + AC_DEFINE(HAVE_REFLECTION, 1, [Whether Reflection is enabled]) --- php5-5.2.10.dfsg.1.orig/debian/patches/033-we_WANT_libtool.patch +++ php5-5.2.10.dfsg.1/debian/patches/033-we_WANT_libtool.patch @@ -0,0 +1,20 @@ +upstream ships an out of date version of libtool. this ensures that +we build against an up-to-date version of libtool by running libtoolize +as part of our build process (this is called indirectly via ./buildconf.sh +from debian/rules) + +note that we don't touch the libtool.m4 that they ship here, and this file +gets included in the build process as part of the phpize stuff. however, +this is solved in ./debian/rules where it's overwritten with a symlink. +--- php.orig/build/build2.mk ++++ php/build/build2.mk +@@ -52,7 +52,8 @@ $(TOUCH_FILES): + + aclocal.m4: configure.in acinclude.m4 + @echo rebuilding $@ +- cat acinclude.m4 ./build/libtool.m4 > $@ ++ libtoolize --copy --install --automake --force ++ aclocal + + configure: aclocal.m4 configure.in $(config_m4_files) + @echo rebuilding $@ --- php5-5.2.10.dfsg.1.orig/debian/patches/force_libmysqlclient_r.patch +++ php5-5.2.10.dfsg.1/debian/patches/force_libmysqlclient_r.patch @@ -0,0 +1,33 @@ +--- php.orig/ext/mysql/config.m4 ++++ php/ext/mysql/config.m4 +@@ -86,7 +86,7 @@ if test "$PHP_MYSQL" != "no"; then + Note that the MySQL client library is not bundled anymore!]) + fi + +- if test "$enable_maintainer_zts" = "yes"; then ++ if true || test "$enable_maintainer_zts" = "yes"; then + MYSQL_LIBNAME=mysqlclient_r + else + MYSQL_LIBNAME=mysqlclient +--- php.orig/ext/mysqli/config.m4 ++++ php/ext/mysqli/config.m4 +@@ -26,7 +26,7 @@ dnl fi + if test "$PHP_EMBEDDED_MYSQLI" = "yes"; then + AC_DEFINE(HAVE_EMBEDDED_MYSQLI, 1, [embedded MySQL support enabled]) + MYSQL_LIB_CFG='--libmysqld-libs' +- elif test "$enable_maintainer_zts" = "yes"; then ++ elif true || test "$enable_maintainer_zts" = "yes"; then + MYSQL_LIB_CFG='--libs_r' + MYSQL_LIB_NAME='mysqlclient_r' + else +--- php.orig/ext/pdo_mysql/config.m4 ++++ php/ext/pdo_mysql/config.m4 +@@ -58,7 +58,7 @@ if test "$PHP_PDO_MYSQL" != "no"; then + if test "x$SED" = "x"; then + AC_PATH_PROG(SED, sed) + fi +- if test "$enable_maintainer_zts" = "yes"; then ++ if true || test "$enable_maintainer_zts" = "yes"; then + PDO_MYSQL_LIBNAME=mysqlclient_r + PDO_MYSQL_LIBS=`$PDO_MYSQL_CONFIG --libs_r | $SED -e "s/'//g"` + else --- php5-5.2.10.dfsg.1.orig/debian/patches/CVE-2008-5625.patch +++ php5-5.2.10.dfsg.1/debian/patches/CVE-2008-5625.patch @@ -0,0 +1,92 @@ +# +# Description: fix arbitrary file write by placing a "php_value error_log" +# entry in a .htaccess file. +# Patch: http://cvs.php.net/viewvc.cgi/php-src/sapi/apache/mod_php5.c?hideattic=0&r1=1.19.2.7.2.14&r2=1.19.2.7.2.15 +# Patch: http://cvs.php.net/viewvc.cgi/php-src/sapi/apache2handler/apache_config.c?hideattic=0&r1=1.7.2.1.2.5&r2=1.7.2.1.2.6 +# +diff -Nur php5-5.2.6.dfsg.1/sapi/apache/mod_php5.c php5-5.2.6.dfsg.1.new/sapi/apache/mod_php5.c +--- php5-5.2.6.dfsg.1/sapi/apache/mod_php5.c 2009-03-30 19:18:50.000000000 -0400 ++++ php5-5.2.6.dfsg.1.new/sapi/apache/mod_php5.c 2009-03-30 19:19:08.000000000 -0400 +@@ -729,11 +729,11 @@ + return 1; /* does not exist in dest, copy from source */ + } + +- if (new_per_dir_entry->type==PHP_INI_SYSTEM +- && orig_per_dir_entry->type!=PHP_INI_SYSTEM) { +- return 1; +- } else { ++ if (orig_per_dir_entry->type==PHP_INI_SYSTEM ++ && new_per_dir_entry->type!=PHP_INI_SYSTEM) { + return 0; ++ } else { ++ return 1; + } + } + /* }}} */ +@@ -770,9 +770,9 @@ + + /* need a copy of addv to merge */ + new = php_create_dir(p, "php_merge_dir"); +- zend_hash_copy(new, (HashTable *) addv, (copy_ctor_func_t) copy_per_dir_entry, NULL, sizeof(php_per_dir_entry)); ++ zend_hash_copy(new, (HashTable *) basev, (copy_ctor_func_t) copy_per_dir_entry, NULL, sizeof(php_per_dir_entry)); + +- zend_hash_merge_ex(new, (HashTable *) basev, (copy_ctor_func_t) copy_per_dir_entry, sizeof(php_per_dir_entry), (merge_checker_func_t) should_overwrite_per_dir_entry, NULL); ++ zend_hash_merge_ex(new, (HashTable *) addv, (copy_ctor_func_t) copy_per_dir_entry, sizeof(php_per_dir_entry), (merge_checker_func_t) should_overwrite_per_dir_entry, NULL); + return new; + } + /* }}} */ +diff -Nur php5-5.2.6.dfsg.1/sapi/apache2handler/apache_config.c php5-5.2.6.dfsg.1.new/sapi/apache2handler/apache_config.c +--- php5-5.2.6.dfsg.1/sapi/apache2handler/apache_config.c 2007-12-31 02:20:15.000000000 -0500 ++++ php5-5.2.6.dfsg.1.new/sapi/apache2handler/apache_config.c 2009-03-30 19:19:08.000000000 -0400 +@@ -117,6 +117,23 @@ + return NULL; + } + ++static zend_bool should_overwrite_per_dir_entry(HashTable *target_ht, php_dir_entry *new_per_dir_entry, zend_hash_key *hash_key, void *pData) ++{ ++ php_dir_entry *orig_per_dir_entry; ++ ++ if (zend_hash_find(target_ht, hash_key->arKey, hash_key->nKeyLength, (void **) &orig_per_dir_entry)==FAILURE) { ++ return 1; /* does not exist in dest, copy from source */ ++ } ++ ++ if (new_per_dir_entry->status >= orig_per_dir_entry->status) { ++ /* use new entry */ ++ phpapdebug((stderr, "ADDING/OVERWRITING %s (%d vs. %d)\n", hash_key->arKey, new_per_dir_entry->status, orig_per_dir_entry->status)); ++ return 1; ++ } else { ++ return 0; ++ } ++} ++ + + void *merge_php_config(apr_pool_t *p, void *base_conf, void *new_conf) + { +@@ -128,9 +145,12 @@ + ulong num_index; + + n = create_php_config(p, "merge_php_config"); +- zend_hash_copy(&n->config, &e->config, NULL, NULL, sizeof(php_dir_entry)); +- ++ /* copy old config */ ++ zend_hash_copy(&n->config, &d->config, NULL, NULL, sizeof(php_dir_entry)); ++ /* merge new config */ + phpapdebug((stderr, "Merge dir (%p)+(%p)=(%p)\n", base_conf, new_conf, n)); ++ zend_hash_merge_ex(&n->config, &e->config, NULL, sizeof(php_dir_entry), (merge_checker_func_t) should_overwrite_per_dir_entry, NULL); ++#if STAS_0 + for (zend_hash_internal_pointer_reset(&d->config); + zend_hash_get_current_key_ex(&d->config, &str, &str_len, + &num_index, 0, NULL) == HASH_KEY_IS_STRING; +@@ -140,10 +160,10 @@ + if (zend_hash_find(&n->config, str, str_len, (void **) &pe) == SUCCESS) { + if (pe->status >= data->status) continue; + } +- zend_hash_update(&n->config, str, str_len, data, sizeof(*data), NULL); + phpapdebug((stderr, "ADDING/OVERWRITING %s (%d vs. %d)\n", str, data->status, pe?pe->status:-1)); ++ zend_hash_update(&n->config, str, str_len, data, sizeof(*data), NULL); + } +- ++#endif + return n; + } + --- php5-5.2.10.dfsg.1.orig/debian/patches/libdb_is_-ldb +++ php5-5.2.10.dfsg.1/debian/patches/libdb_is_-ldb @@ -0,0 +1,11 @@ +--- php.orig/ext/dba/config.m4 ++++ php/ext/dba/config.m4 +@@ -306,7 +306,7 @@ if test "$PHP_DB4" != "no"; then + break + fi + done +- PHP_DBA_DB_CHECK(4, db-4.6 db-4.5 db-4.4 db-4.3 db-4.2 db-4.1 db-4.0 db-4 db4 db, [(void)db_create((DB**)0, (DB_ENV*)0, 0)]) ++ PHP_DBA_DB_CHECK(4, db db-4.6 db-4.5 db-4.4 db-4.3 db-4.2 db-4.1 db-4.0 db-4 db4, [(void)db_create((DB**)0, (DB_ENV*)0, 0)]) + fi + PHP_DBA_STD_RESULT(db4,Berkeley DB4) + --- php5-5.2.10.dfsg.1.orig/debian/patches/exif_read_data-segfault.patch +++ php5-5.2.10.dfsg.1/debian/patches/exif_read_data-segfault.patch @@ -0,0 +1,15 @@ +Index: php/ext/exif/exif.c +=================================================================== +--- php.orig/ext/exif/exif.c ++++ php/ext/exif/exif.c +@@ -3219,6 +3219,10 @@ static void exif_process_TIFF_in_JPEG(im + exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Invalid IFD start"); + return; + } ++ if (offset_of_ifd > length) { ++ exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Invalid IFD start"); ++ return; ++ } + + ImageInfo->sections_found |= FOUND_IFD0; + /* First directory starts at offset 8. Offsets starts at 0. */ --- php5-5.2.10.dfsg.1.orig/debian/patches/113-php.ini_securitynotes.patch +++ php5-5.2.10.dfsg.1/debian/patches/113-php.ini_securitynotes.patch @@ -0,0 +1,40 @@ +--- php.orig/php.ini-dist ++++ php/php.ini-dist +@@ -166,6 +166,11 @@ allow_call_time_pass_reference = On + ; + ; Safe Mode + ; ++; NOTE: this is considered a "broken" security measure. ++; Applications relying on this feature will not recieve full ++; support by the security team. For more information please ++; see /usr/share/doc/php5-common/README.Debian.security ++; + safe_mode = Off + + ; By default, Safe Mode does a UID compare check when +@@ -202,6 +207,13 @@ safe_mode_protected_env_vars = LD_LIBRAR + ; and below. This directive makes most sense if used in a per-directory + ; or per-virtualhost web server configuration file. This directive is + ; *NOT* affected by whether Safe Mode is turned On or Off. ++ ++; NOTE: this is considered a "broken" security measure. ++; Applications relying on this feature will not recieve full ++; support by the security team. For more information please ++; see /usr/share/doc/php5-common/README.Debian.security ++; ++ + ;open_basedir = + + ; This directive allows you to disable certain functions for security reasons. +@@ -416,6 +428,11 @@ variables_order = "EGPCS" + ; You should do your best to write your scripts so that they do not require + ; register_globals to be on; Using form variables as globals can easily lead + ; to possible security problems, if the code is not very well thought of. ++ ++; NOTE: applications relying on this feature will not recieve full ++; support by the security team. For more information please ++; see /usr/share/doc/php5-common/README.Debian.security ++; + register_globals = Off + + ; Whether or not to register the old-style input arrays, HTTP_GET_VARS --- php5-5.2.10.dfsg.1.orig/debian/patches/017-pread_pwrite_disable.patch +++ php5-5.2.10.dfsg.1/debian/patches/017-pread_pwrite_disable.patch @@ -0,0 +1,20 @@ +--- php.orig/acinclude.m4 ++++ php/acinclude.m4 +@@ -1219,7 +1219,7 @@ $1 + } + + ],[ +- ac_cv_pwrite=yes ++ ac_cv_pwrite=no + ],[ + ac_cv_pwrite=no + ],[ +@@ -1248,7 +1248,7 @@ $1 + exit(0); + } + ],[ +- ac_cv_pread=yes ++ ac_cv_pread=no + ],[ + ac_cv_pread=no + ],[ --- php5-5.2.10.dfsg.1.orig/debian/patches/php5-CVE-2011-1092.patch +++ php5-5.2.10.dfsg.1/debian/patches/php5-CVE-2011-1092.patch @@ -0,0 +1,21 @@ +Subject: Fixed bug #54193 (Integer overflow in shmop_read()) +Origin: http://svn.php.net/viewvc/?view=revision&revision=309018 + +CVE-2011-1092 + +Patch differs from upstream commit in that the change to the NEWS file +was removed to reduce conflicts. + +Index: ext/shmop/shmop.c +=================================================================== +--- ext/shmop/shmop.c (revision 309017) ++++ ext/shmop/shmop.c (revision 309018) +@@ -256,7 +256,7 @@ + RETURN_FALSE; + } + +- if (start + count > shmop->size || count < 0) { ++ if (count < 0 || start > (INT_MAX - count) || start + count > shmop->size) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "count is out of range"); + RETURN_FALSE; + } --- php5-5.2.10.dfsg.1.orig/debian/patches/056-mime_magic_liberal.patch +++ php5-5.2.10.dfsg.1/debian/patches/056-mime_magic_liberal.patch @@ -0,0 +1,36 @@ +--- php.orig/ext/mime_magic/mime_magic.c ++++ php/ext/mime_magic/mime_magic.c +@@ -501,7 +501,7 @@ static int is_valid_mimetype(char *p, in + } while (*(++p) != '/'); + ++p; + do { +- if (!isalnum(*p) && (*p != '-') && (*p != '.') && !isspace(*p)) { ++ if (!isalnum(*p) && (*p != '-') && (*p != '.') && (*p != '+') && !isspace(*p)) { + return 0; + } + } while (*(++p)); +@@ -634,6 +634,15 @@ static int parse(char *l, int lineno) + else if (strncmp(l, "string", NSTRING) == 0) { + m->type = STRING; + l += NSTRING; ++ if (*l == '/') { ++ ++l; ++ if ((*l == 'B') || (*l == 'b') || (*l == 'c')) { ++ ++l; ++ if ((*l == 'B') || (*l == 'b') || (*l == 'c')) { ++ ++l; ++ } ++ } ++ } + } + else if (strncmp(l, "date", NDATE) == 0) { + m->type = DATE; +@@ -727,7 +736,7 @@ static int parse(char *l, int lineno) + if (!is_valid_mimetype(l, strlen(l))) { + if(MIME_MAGIC_G(debug)) + php_error_docref("http://www.php.net/mime_magic" TSRMLS_CC, E_WARNING, ": (%s:%d) '%s' is not a valid mimetype, entry skipped", MIME_MAGIC_G(magicfile), lineno, l); +- return -1; ++ return 0; + } + + strlcpy(m->desc, l, sizeof(m->desc)); --- php5-5.2.10.dfsg.1.orig/debian/patches/043-recode_size_t.patch +++ php5-5.2.10.dfsg.1/debian/patches/043-recode_size_t.patch @@ -0,0 +1,11 @@ +--- php.orig/ext/recode/recode.c ++++ php/ext/recode/recode.c +@@ -136,7 +136,7 @@ PHP_FUNCTION(recode_string) + int req_len, str_len; + char *req, *str; + +- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &req, &req_len, &str, &str_len) == FAILURE) { ++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &req, &req_len, &str, &str_len) == FAILURE || str_len < 0) { + return; + } + --- php5-5.2.10.dfsg.1.orig/debian/patches/052-phpinfo_no_configure.patch +++ php5-5.2.10.dfsg.1/debian/patches/052-phpinfo_no_configure.patch @@ -0,0 +1,21 @@ +--- php.orig/ext/standard/info.c ++++ php/ext/standard/info.c +@@ -487,7 +487,7 @@ PHPAPI void php_print_info(int flag TSRM + php_info_print_table_start(); + php_info_print_table_row(2, "System", php_uname ); + php_info_print_table_row(2, "Build Date", __DATE__ " " __TIME__ ); +-#ifdef CONFIGURE_COMMAND ++#if 0 + php_info_print_table_row(2, "Configure Command", CONFIGURE_COMMAND ); + #endif + if (sapi_module.pretty_name) { +--- php.orig/ext/standard/tests/general_functions/phpinfo.phpt ++++ php/ext/standard/tests/general_functions/phpinfo.phpt +@@ -20,7 +20,6 @@ PHP Version => %s + + System => %s + Build Date => %s +-Configure Command => %s + Server API => Command Line Interface + Virtual Directory Support => %s + Configuration File (php.ini) Path => %s --- php5-5.2.10.dfsg.1.orig/debian/patches/100-recode_is_shared.patch +++ php5-5.2.10.dfsg.1/debian/patches/100-recode_is_shared.patch @@ -0,0 +1,10 @@ +--- php.orig/ext/recode/config9.m4 ++++ php/ext/recode/config9.m4 +@@ -8,6 +8,6 @@ if test "$PHP_RECODE" != "no"; then + test "$PHP_MYSQL" != "no" && recode_conflict="$recode_conflict mysql" + + if test -n "$recode_conflict"; then +- AC_MSG_ERROR([recode extension can not be configured together with:$recode_conflict]) ++ AC_MSG_WARN([recode extension can not be used together with:$recode_conflict]) + fi + fi --- php5-5.2.10.dfsg.1.orig/debian/patches/119-sybase-alias.patch +++ php5-5.2.10.dfsg.1/debian/patches/119-sybase-alias.patch @@ -0,0 +1,42 @@ +diff -Naur php-5.2.6.orig/ext/mssql/php_mssql.c php-5.2.6/ext/mssql/php_mssql.c +--- php-5.2.6.orig/ext/mssql/php_mssql.c 2008-03-05 23:53:23.000000000 +0000 ++++ php-5.2.6/ext/mssql/php_mssql.c 2008-06-20 14:06:35.000000000 +0000 +@@ -78,6 +78,38 @@ + PHP_FE(mssql_execute, NULL) + PHP_FE(mssql_free_statement, NULL) + PHP_FE(mssql_guid_string, NULL) ++#if !defined(PHP_WIN32) && !defined(HAVE_SYBASE_CT) ++ PHP_FALIAS(sybase_connect, mssql_connect, NULL) ++ PHP_FALIAS(sybase_pconnect, mssql_pconnect, NULL) ++ PHP_FALIAS(sybase_close, mssql_close, NULL) ++ PHP_FALIAS(sybase_select_db, mssql_select_db, NULL) ++ PHP_FALIAS(sybase_query, mssql_query, NULL) ++ PHP_FALIAS(sybase_fetch_batch, mssql_fetch_batch, NULL) ++ PHP_FALIAS(sybase_rows_affected, mssql_rows_affected, NULL) ++ PHP_FALIAS(sybase_free_result, mssql_free_result, NULL) ++ PHP_FALIAS(sybase_get_last_message, mssql_get_last_message, NULL) ++ PHP_FALIAS(sybase_num_rows, mssql_num_rows, NULL) ++ PHP_FALIAS(sybase_num_fields, mssql_num_fields, NULL) ++ PHP_FALIAS(sybase_fetch_field, mssql_fetch_field, NULL) ++ PHP_FALIAS(sybase_fetch_row, mssql_fetch_row, NULL) ++ PHP_FALIAS(sybase_fetch_array, mssql_fetch_array, NULL) ++ PHP_FALIAS(sybase_fetch_assoc, mssql_fetch_assoc, NULL) ++ PHP_FALIAS(sybase_fetch_object, mssql_fetch_object, NULL) ++ PHP_FALIAS(sybase_field_length, mssql_field_length, NULL) ++ PHP_FALIAS(sybase_field_name, mssql_field_name, NULL) ++ PHP_FALIAS(sybase_field_type, mssql_field_type, NULL) ++ PHP_FALIAS(sybase_data_seek, mssql_data_seek, NULL) ++ PHP_FALIAS(sybase_field_seek, mssql_field_seek, NULL) ++ PHP_FALIAS(sybase_result, mssql_result, NULL) ++ PHP_FALIAS(sybase_next_result, mssql_next_result, NULL) ++ PHP_FALIAS(sybase_min_error_severity, mssql_min_error_severity, NULL) ++ PHP_FALIAS(sybase_min_message_severity, mssql_min_message_severity, NULL) ++ PHP_FALIAS(sybase_init, mssql_init, NULL) ++ PHP_FALIAS(sybase_bind, mssql_bind, third_arg_force_ref) ++ PHP_FALIAS(sybase_execute, mssql_execute, NULL) ++ PHP_FALIAS(sybase_free_statement, mssql_free_statement, NULL) ++ PHP_FALIAS(sybase_guid_string, mssql_guid_string, NULL) ++#endif + {NULL, NULL, NULL} + }; + --- php5-5.2.10.dfsg.1.orig/debian/patches/fix-autoconf-ftbfs.patch +++ php5-5.2.10.dfsg.1/debian/patches/fix-autoconf-ftbfs.patch @@ -0,0 +1,11 @@ +diff -Naurp php5-5.2.6.dfsg.1.orig/ext/posix/posix.c php5-5.2.6.dfsg.1/ext/posix/posix.c +--- php5-5.2.6.dfsg.1.orig/ext/posix/posix.c 2008-04-11 07:00:24.000000000 -0400 ++++ php5-5.2.6.dfsg.1/ext/posix/posix.c 2009-02-13 13:52:23.000000000 -0500 +@@ -18,6 +18,7 @@ + + /* $Id: posix.c,v 1.70.2.3.2.18 2008/04/11 11:00:24 tony2001 Exp $ */ + ++#define _GNU_SOURCE + #ifdef HAVE_CONFIG_H + #include "config.h" + #endif --- php5-5.2.10.dfsg.1.orig/debian/patches/057-no_apache_installed.patch +++ php5-5.2.10.dfsg.1/debian/patches/057-no_apache_installed.patch @@ -0,0 +1,84 @@ +--- php.orig/sapi/apache2handler/config.m4 ++++ php/sapi/apache2handler/config.m4 +@@ -59,13 +59,13 @@ if test "$PHP_APXS2" != "no"; then + + APACHE_CFLAGS="$APACHE_CPPFLAGS -I$APXS_INCLUDEDIR $APR_CFLAGS $APU_CFLAGS" + +- # Test that we're trying to configure with apache 2.x +- PHP_AP_EXTRACT_VERSION($APXS_HTTPD) +- if test "$APACHE_VERSION" -le 2000000; then +- AC_MSG_ERROR([You have enabled Apache 2 support while your server is Apache 1.3. Please use the appropiate switch --with-apxs (without the 2)]) +- elif test "$APACHE_VERSION" -lt 2000044; then +- AC_MSG_ERROR([Please note that Apache version >= 2.0.44 is required]) +- fi ++dnl # Test that we're trying to configure with apache 2.x ++dnl PHP_AP_EXTRACT_VERSION($APXS_HTTPD) ++dnl if test "$APACHE_VERSION" -le 2000000; then ++dnl AC_MSG_ERROR([You have enabled Apache 2 support while your server is Apache 1.3. Please use the appropiate switch --with-apxs (without the 2)]) ++dnl elif test "$APACHE_VERSION" -lt 2000044; then ++dnl AC_MSG_ERROR([Please note that Apache version >= 2.0.44 is required]) ++dnl fi + + APXS_LIBEXECDIR='$(INSTALL_ROOT)'`$APXS -q LIBEXECDIR` + if test -z `$APXS -q SYSCONFDIR`; then +--- php.orig/sapi/apache/config.m4 ++++ php/sapi/apache/config.m4 +@@ -56,11 +56,11 @@ if test "$PHP_APXS" != "no"; then + APXS_HTTPD=`$APXS -q SBINDIR`/`$APXS -q TARGET` + APACHE_INCLUDE=-I$APXS_INCLUDEDIR + +- # Test that we're trying to configure with apache 1.x +- PHP_AP_EXTRACT_VERSION($APXS_HTTPD) +- if test "$APACHE_VERSION" -ge 2000000; then +- AC_MSG_ERROR([You have enabled Apache 1.3 support while your server is Apache 2. Please use the appropiate switch --with-apxs2]) +- fi ++dnl # Test that we're trying to configure with apache 1.x ++dnl PHP_AP_EXTRACT_VERSION($APXS_HTTPD) ++dnl if test "$APACHE_VERSION" -ge 2000000; then ++dnl AC_MSG_ERROR([You have enabled Apache 1.3 support while your server is Apache 2. Please use the appropiate switch --with-apxs2]) ++dnl fi + + for flag in $APXS_CFLAGS; do + case $flag in +--- php.orig/sapi/apache2filter/config.m4 ++++ php/sapi/apache2filter/config.m4 +@@ -60,13 +60,13 @@ if test "$PHP_APXS2FILTER" != "no"; then + + APACHE_CFLAGS="$APACHE_CPPFLAGS -I$APXS_INCLUDEDIR $APR_CFLAGS $APU_CFLAGS" + +- # Test that we're trying to configure with apache 2.x +- PHP_AP_EXTRACT_VERSION($APXS_HTTPD) +- if test "$APACHE_VERSION" -le 2000000; then +- AC_MSG_ERROR([You have enabled Apache 2 support while your server is Apache 1.3. Please use the appropiate switch --with-apxs (without the 2)]) +- elif test "$APACHE_VERSION" -lt 2000040; then +- AC_MSG_ERROR([Please note that Apache version >= 2.0.40 is required]) +- fi ++dnl # Test that we're trying to configure with apache 2.x ++dnl PHP_AP_EXTRACT_VERSION($APXS_HTTPD) ++dnl if test "$APACHE_VERSION" -le 2000000; then ++dnl AC_MSG_ERROR([You have enabled Apache 2 support while your server is Apache 1.3. Please use the appropiate switch --with-apxs (without the 2)]) ++dnl elif test "$APACHE_VERSION" -lt 2000040; then ++dnl AC_MSG_ERROR([Please note that Apache version >= 2.0.40 is required]) ++dnl fi + + APXS_LIBEXECDIR='$(INSTALL_ROOT)'`$APXS -q LIBEXECDIR` + if test -z `$APXS -q SYSCONFDIR`; then +--- php.orig/sapi/apache_hooks/config.m4 ++++ php/sapi/apache_hooks/config.m4 +@@ -57,11 +57,11 @@ if test "$PHP_APACHE_HOOKS" != "no"; the + APXS_HTTPD=`$APXS -q SBINDIR`/`$APXS -q TARGET` + APACHE_INCLUDE=-I$APXS_INCLUDEDIR + +- # Test that we're trying to configure with apache 1.x +- PHP_AP_EXTRACT_VERSION($APXS_HTTPD) +- if test "$APACHE_VERSION" -ge 2000000; then +- AC_MSG_ERROR([You have enabled Apache 1.3 support while your server is Apache 2. Please use the appropiate switch --with-apxs2]) +- fi ++dnl # Test that we're trying to configure with apache 1.x ++dnl PHP_AP_EXTRACT_VERSION($APXS_HTTPD) ++dnl if test "$APACHE_VERSION" -ge 2000000; then ++dnl AC_MSG_ERROR([You have enabled Apache 1.3 support while your server is Apache 2. Please use the appropiate switch --with-apxs2]) ++dnl fi + + for flag in $APXS_CFLAGS; do + case $flag in --- php5-5.2.10.dfsg.1.orig/debian/patches/php5-CVE-2011-1471.patch +++ php5-5.2.10.dfsg.1/debian/patches/php5-CVE-2011-1471.patch @@ -0,0 +1,39 @@ +Subject: Fixed bug #49072 (feof never returns true for damaged file in zip). +Origin: http://svn.php.net/viewvc?view=revision&revision=307917 +Bug: http://bugs.php.net/bug.php?id=49072 + +CVE-2011-1471 + +Patch differs from upstream commit in that it drops the add NEWS file +entry to reduce patch conflicts and is backported to php 5.2.x. + +Index: ext/zip/zip_stream.c +=================================================================== +--- ext/zip/zip_stream.c (revision 307916) ++++ ext/zip/zip_stream.c (revision 307917) +@@ -30,19 +30,21 @@ + /* {{{ php_zip_ops_read */ + static size_t php_zip_ops_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) + { +- int n = 0; ++ ssize_t n = 0; + STREAM_DATA_FROM_STREAM(); + + if (self->za && self->zf) { +- n = (size_t)zip_fread(self->zf, buf, (int)count); ++ n = zip_fread(self->zf, buf, count); + +- if (n == 0) { ++ /* cast count to signed value to avoid possibly negative n ++ * being cast to unsigned value */ ++ if (n == 0 || n < (ssize_t)count) { + stream->eof = 1; + } else { + self->cursor += n; + } + } +- return n<1 ? 0 : n; ++ return (n < 1 ? 0 : (size_t)n); + } + /* }}} */ + --- php5-5.2.10.dfsg.1.orig/debian/patches/fix-zlib-compression.patch +++ php5-5.2.10.dfsg.1/debian/patches/fix-zlib-compression.patch @@ -0,0 +1,68 @@ +diff -Naurp php-5.2.10.orig/ext/zlib/zlib_filter.c php-5.2.10/ext/zlib/zlib_filter.c +--- php-5.2.10.orig/ext/zlib/zlib_filter.c 2008-12-31 06:17:47.000000000 -0500 ++++ php-5.2.10/ext/zlib/zlib_filter.c 2009-10-13 12:58:02.000000000 -0400 +@@ -353,7 +353,7 @@ static php_stream_filter *php_zlib_filte + + + if (filterparams) { +- zval **tmpzval; ++ zval **tmpzval, tmp; + + /* filterparams can either be a scalar value to indicate compression level (shortcut method) + Or can be a hash containing one or more of 'window', 'memory', and/or 'level' members. */ +@@ -362,8 +362,6 @@ static php_stream_filter *php_zlib_filte + case IS_ARRAY: + case IS_OBJECT: + if (zend_hash_find(HASH_OF(filterparams), "memory", sizeof("memory"), (void**) &tmpzval) == SUCCESS) { +- zval tmp; +- + tmp = **tmpzval; + zval_copy_ctor(&tmp); + convert_to_long(&tmp); +@@ -377,8 +375,6 @@ static php_stream_filter *php_zlib_filte + } + + if (zend_hash_find(HASH_OF(filterparams), "window", sizeof("window"), (void**) &tmpzval) == SUCCESS) { +- zval tmp; +- + tmp = **tmpzval; + zval_copy_ctor(&tmp); + convert_to_long(&tmp); +@@ -392,6 +388,8 @@ static php_stream_filter *php_zlib_filte + } + + if (zend_hash_find(HASH_OF(filterparams), "level", sizeof("level"), (void**) &tmpzval) == SUCCESS) { ++ tmp = **tmpzval; ++ + /* Psuedo pass through to catch level validating code */ + goto factory_setlevel; + } +@@ -399,19 +397,16 @@ static php_stream_filter *php_zlib_filte + case IS_STRING: + case IS_DOUBLE: + case IS_LONG: +- { +- zval tmp; +- +- tmp = *filterparams; +- zval_copy_ctor(&tmp); +- convert_to_long(&tmp); ++ tmp = *filterparams; + factory_setlevel: +- /* Set compression level within reason (-1 == default, 0 == none, 1-9 == least to most compression */ +- if (Z_LVAL(tmp) < -1 || Z_LVAL(tmp) > 9) { +- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid compression level specified. (%ld)", Z_LVAL(tmp)); +- } else { +- level = Z_LVAL(tmp); +- } ++ zval_copy_ctor(&tmp); ++ convert_to_long(&tmp); ++ ++ /* Set compression level within reason (-1 == default, 0 == none, 1-9 == least to most compression */ ++ if (Z_LVAL(tmp) < -1 || Z_LVAL(tmp) > 9) { ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid compression level specified. (%ld)", Z_LVAL(tmp)); ++ } else { ++ level = Z_LVAL(tmp); + } + break; + default: --- php5-5.2.10.dfsg.1.orig/debian/patches/bad_whatis_entries.patch +++ php5-5.2.10.dfsg.1/debian/patches/bad_whatis_entries.patch @@ -0,0 +1,29 @@ +--- php.orig/sapi/cli/php.1.in ++++ php/sapi/cli/php.1.in +@@ -1,6 +1,5 @@ + .TH PHP 1 "2008" "The PHP Group" "Scripting Language" + .SH NAME +-.TP 15 + php \- PHP Command Line Interface 'CLI' + .SH SYNOPSIS + .B php +--- php.orig/scripts/man1/php-config.1.in ++++ php/scripts/man1/php-config.1.in +@@ -1,6 +1,5 @@ + .TH php\-config 1 "2006" "The PHP Group" "Scripting Language" + .SH NAME +-.TP 15 + php\-config \- get information about PHP configuration and compile options + .SH SYNOPSIS + .B php\-config +--- php.orig/scripts/man1/phpize.1.in ++++ php/scripts/man1/phpize.1.in +@@ -1,7 +1,6 @@ + .TH phpize 1 "2006" "The PHP Group" "Scripting Language" + .SH NAME +-.TP 15 +-phpize - prepare a PHP extension for compiling ++phpize \- prepare a PHP extension for compiling + .SH SYNOPSIS + .B phpize + [options] --- php5-5.2.10.dfsg.1.orig/debian/patches/002-static_openssl.patch +++ php5-5.2.10.dfsg.1/debian/patches/002-static_openssl.patch @@ -0,0 +1,13 @@ +--- php.orig/acinclude.m4 ++++ php/acinclude.m4 +@@ -2373,9 +2373,7 @@ AC_DEFUN([PHP_SETUP_OPENSSL],[ + + PHP_ADD_INCLUDE($OPENSSL_INCDIR) + +- PHP_CHECK_LIBRARY(crypto, CRYPTO_free, [ +- PHP_ADD_LIBRARY(crypto,,$1) +- ],[ ++ PHP_CHECK_LIBRARY(crypto, CRYPTO_free, [:],[ + AC_MSG_ERROR([libcrypto not found!]) + ],[ + -L$OPENSSL_LIBDIR --- php5-5.2.10.dfsg.1.orig/debian/patches/deprecated_freetds_check.patch +++ php5-5.2.10.dfsg.1/debian/patches/deprecated_freetds_check.patch @@ -0,0 +1,82 @@ +diff -Naur php-5.2.6.orig/ext/mssql/config.m4 php-5.2.6/ext/mssql/config.m4 +--- php-5.2.6.orig/ext/mssql/config.m4 2007-07-03 13:25:34.000000000 -0400 ++++ php-5.2.6/ext/mssql/config.m4 2008-08-12 13:14:20.000000000 -0400 +@@ -10,11 +10,11 @@ + + if test "$PHP_MSSQL" = "yes"; then + for i in /usr/local /usr; do +- if test -f $i/include/tds.h; then ++ if test -f $i/include/sybdb.h; then + FREETDS_INSTALLATION_DIR=$i + FREETDS_INCLUDE_DIR=$i/include + break +- elif test -f $i/include/freetds/tds.h; then ++ elif test -f $i/include/freetds/sybdb.h; then + FREETDS_INSTALLATION_DIR=$i + FREETDS_INCLUDE_DIR=$i/include/freetds + break +@@ -27,10 +27,10 @@ + + elif test "$PHP_MSSQL" != "no"; then + +- if test -f $PHP_MSSQL/include/tds.h; then ++ if test -f $PHP_MSSQL/include/sybdb.h; then + FREETDS_INSTALLATION_DIR=$PHP_MSSQL + FREETDS_INCLUDE_DIR=$PHP_MSSQL/include +- elif test -f $PHP_MSSQL/include/freetds/tds.h; then ++ elif test -f $PHP_MSSQL/include/freetds/sybdb.h; then + FREETDS_INSTALLATION_DIR=$PHP_MSSQL + FREETDS_INCLUDE_DIR=$PHP_MSSQL/include/freetds + else +@@ -38,8 +38,8 @@ + fi + fi + +- if test ! -r "$FREETDS_INSTALLATION_DIR/$PHP_LIBDIR/libtds.a" && test ! -r "$FREETDS_INSTALLATION_DIR/$PHP_LIBDIR/libtds.so"; then +- AC_MSG_ERROR(Could not find $FREETDS_INSTALLATION_DIR/$PHP_LIBDIR/libtds.[a|so]) ++ if test ! -r "$FREETDS_INSTALLATION_DIR/$PHP_LIBDIR/libsybdb.a" && test ! -r "$FREETDS_INSTALLATION_DIR/$PHP_LIBDIR/libsybdb.so"; then ++ AC_MSG_ERROR(Could not find $FREETDS_INSTALLATION_DIR/$PHP_LIBDIR/libsybdb.[a|so]) + fi + + PHP_ADD_INCLUDE($FREETDS_INCLUDE_DIR) +diff -Naur php-5.2.6.orig/ext/pdo_dblib/config.m4 php-5.2.6/ext/pdo_dblib/config.m4 +--- php-5.2.6.orig/ext/pdo_dblib/config.m4 2007-07-03 13:25:34.000000000 -0400 ++++ php-5.2.6/ext/pdo_dblib/config.m4 2008-08-12 13:14:20.000000000 -0400 +@@ -13,11 +13,11 @@ + if test "$PHP_PDO_DBLIB" = "yes"; then + + for i in /usr/local /usr; do +- if test -f $i/include/tds.h; then ++ if test -f $i/include/sybdb.h; then + PDO_FREETDS_INSTALLATION_DIR=$i + PDO_FREETDS_INCLUDE_DIR=$i/include + break +- elif test -f $i/include/freetds/tds.h; then ++ elif test -f $i/include/freetds/sybdb.h; then + PDO_FREETDS_INSTALLATION_DIR=$i + PDO_FREETDS_INCLUDE_DIR=$i/include/freetds + break; +@@ -30,10 +30,10 @@ + + elif test "$PHP_PDO_DBLIB" != "no"; then + +- if test -f $PHP_PDO_DBLIB/include/tds.h; then ++ if test -f $PHP_PDO_DBLIB/include/sybdb.h; then + PDO_FREETDS_INSTALLATION_DIR=$PHP_PDO_DBLIB + PDO_FREETDS_INCLUDE_DIR=$PHP_PDO_DBLIB/include +- elif test -f $PHP_PDO_DBLIB/include/freetds/tds.h; then ++ elif test -f $PHP_PDO_DBLIB/include/freetds/sybdb.h; then + PDO_FREETDS_INSTALLATION_DIR=$PHP_PDO_DBLIB + PDO_FREETDS_INCLUDE_DIR=$PHP_PDO_DBLIB/include/freetds + else +@@ -45,8 +45,8 @@ + PHP_LIBDIR=lib + fi + +- if test ! -r "$PDO_FREETDS_INSTALLATION_DIR/$PHP_LIBDIR/libtds.a" && test ! -r "$PDO_FREETDS_INSTALLATION_DIR/$PHP_LIBDIR/libtds.so"; then +- AC_MSG_ERROR(Could not find $PDO_FREETDS_INSTALLATION_DIR/$PHP_LIBDIR/libtds.[a|so]) ++ if test ! -r "$PDO_FREETDS_INSTALLATION_DIR/$PHP_LIBDIR/libsybdb.a" && test ! -r "$PDO_FREETDS_INSTALLATION_DIR/$PHP_LIBDIR/libsybdb.so"; then ++ AC_MSG_ERROR(Could not find $PDO_FREETDS_INSTALLATION_DIR/$PHP_LIBDIR/libsybdb.[a|so]) + fi + + PHP_ADD_INCLUDE($PDO_FREETDS_INCLUDE_DIR) --- php5-5.2.10.dfsg.1.orig/debian/patches/CVE-2010-2225.patch +++ php5-5.2.10.dfsg.1/debian/patches/CVE-2010-2225.patch @@ -0,0 +1,71 @@ +Description: fix sensitive information disclosure or arbitrary code + execution via use-after-free in SplObjectStorage unserializer +Origin: upstream, http://svn.php.net/viewvc?view=revision&revision=300843 + +diff -Nur php5-5.2.10.dfsg.1/ext/spl/spl_observer.c php5-5.2.10.dfsg.1.new/ext/spl/spl_observer.c +--- php5-5.2.10.dfsg.1/ext/spl/spl_observer.c 2008-12-31 06:17:44.000000000 -0500 ++++ php5-5.2.10.dfsg.1.new/ext/spl/spl_observer.c 2010-09-14 14:39:09.000000000 -0400 +@@ -182,6 +182,21 @@ + intern->index = 0; + } /* }}} */ + ++int spl_object_storage_contains(spl_SplObjectStorage *intern, zval *obj TSRMLS_DC) /* {{{ */ ++{ ++#if HAVE_PACKED_OBJECT_VALUE ++ return zend_hash_exists(&intern->storage, (char*)&Z_OBJVAL_P(obj), sizeof(zend_object_value)); ++#else ++ { ++ zend_object_value zvalue; ++ memset(&zvalue, 0, sizeof(zend_object_value)); ++ zvalue.handle = Z_OBJ_HANDLE_P(obj); ++ zvalue.handlers = Z_OBJ_HT_P(obj); ++ return zend_hash_exists(&intern->storage, (char*)&zvalue, sizeof(zend_object_value)); ++ } ++#endif ++} /* }}} */ ++ + /* {{{ proto bool SplObjectStorage::contains($obj) + Determine whethe an object is contained in the storage */ + SPL_METHOD(SplObjectStorage, contains) +@@ -193,17 +208,7 @@ + return; + } + +-#if HAVE_PACKED_OBJECT_VALUE +- RETURN_BOOL(zend_hash_exists(&intern->storage, (char*)&Z_OBJVAL_P(obj), sizeof(zend_object_value))); +-#else +- { +- zend_object_value zvalue; +- memset(&zvalue, 0, sizeof(zend_object_value)); +- zvalue.handle = Z_OBJ_HANDLE_P(obj); +- zvalue.handlers = Z_OBJ_HT_P(obj); +- RETURN_BOOL(zend_hash_exists(&intern->storage, (char*)&zvalue, sizeof(zend_object_value))); +- } +-#endif ++ RETURN_BOOL(spl_object_storage_contains(intern, obj TSRMLS_CC)); + } /* }}} */ + + /* {{{ proto int SplObjectStorage::count() +@@ -362,11 +367,22 @@ + goto outexcept; + } + ++p; ++ if(*p != 'O' && *p != 'C' && *p != 'r') { ++ goto outexcept; ++ } + ALLOC_INIT_ZVAL(pentry); + if (!php_var_unserialize(&pentry, &p, s + buf_len, &var_hash TSRMLS_CC)) { + zval_ptr_dtor(&pentry); + goto outexcept; + } ++ if(Z_TYPE_P(pentry) != IS_OBJECT) { ++ zval_ptr_dtor(&pentry); ++ goto outexcept; ++ } ++ if(spl_object_storage_contains(intern, pentry TSRMLS_CC)) { ++ zval_ptr_dtor(&pentry); ++ continue; ++ } + spl_object_storage_attach(intern, pentry TSRMLS_CC); + zval_ptr_dtor(&pentry); + } --- php5-5.2.10.dfsg.1.orig/debian/patches/CVE-2010-2531.patch +++ php5-5.2.10.dfsg.1/debian/patches/CVE-2010-2531.patch @@ -0,0 +1,286 @@ +Description: fix sensitive information disclosure via error messages +Origin: upstream, http://svn.php.net/viewvc?view=revision&revision=301245 + +diff -Nur php5-5.2.10.dfsg.1/ext/standard/php_var.h php5-5.2.10.dfsg.1.new/ext/standard/php_var.h +--- php5-5.2.10.dfsg.1/ext/standard/php_var.h 2008-12-31 06:17:45.000000000 -0500 ++++ php5-5.2.10.dfsg.1.new/ext/standard/php_var.h 2010-09-14 14:40:40.000000000 -0400 +@@ -33,6 +33,8 @@ + + PHPAPI void php_var_dump(zval **struc, int level TSRMLS_DC); + PHPAPI void php_var_export(zval **struc, int level TSRMLS_DC); ++PHPAPI void php_var_export_ex(zval **struc, int level, smart_str *buf TSRMLS_DC); ++ + PHPAPI void php_debug_zval_dump(zval **struc, int level TSRMLS_DC); + + /* typdef HashTable php_serialize_data_t; */ +diff -Nur php5-5.2.10.dfsg.1/ext/standard/tests/general_functions/var_export_error2.phpt php5-5.2.10.dfsg.1.new/ext/standard/tests/general_functions/var_export_error2.phpt +--- php5-5.2.10.dfsg.1/ext/standard/tests/general_functions/var_export_error2.phpt 2009-01-26 17:27:00.000000000 -0500 ++++ php5-5.2.10.dfsg.1.new/ext/standard/tests/general_functions/var_export_error2.phpt 2010-09-14 14:40:43.000000000 -0400 +@@ -14,12 +14,5 @@ + ?> + ===DONE=== + --EXPECTF-- +-stdClass::__set_state(array( +- 'p' => +- stdClass::__set_state(array( +- 'p' => +- stdClass::__set_state(array( +- 'p' => +- stdClass::__set_state(array( + + Fatal error: Nesting level too deep - recursive dependency? in %s on line 9 +\ No newline at end of file +diff -Nur php5-5.2.10.dfsg.1/ext/standard/tests/general_functions/var_export_error3.phpt php5-5.2.10.dfsg.1.new/ext/standard/tests/general_functions/var_export_error3.phpt +--- php5-5.2.10.dfsg.1/ext/standard/tests/general_functions/var_export_error3.phpt 2009-01-26 17:27:00.000000000 -0500 ++++ php5-5.2.10.dfsg.1.new/ext/standard/tests/general_functions/var_export_error3.phpt 2010-09-14 14:40:45.000000000 -0400 +@@ -14,14 +14,5 @@ + ?> + ===DONE=== + --EXPECTF-- +-array ( +- 0 => +- array ( +- 0 => +- array ( +- 0 => +- array ( +- 0 => +- array ( + + Fatal error: Nesting level too deep - recursive dependency? in %s on line 9 +\ No newline at end of file +diff -Nur php5-5.2.10.dfsg.1/ext/standard/var.c php5-5.2.10.dfsg.1.new/ext/standard/var.c +--- php5-5.2.10.dfsg.1/ext/standard/var.c 2009-01-07 09:36:49.000000000 -0500 ++++ php5-5.2.10.dfsg.1.new/ext/standard/var.c 2010-09-14 14:40:49.000000000 -0400 +@@ -343,54 +343,83 @@ + } + /* }}} */ + ++#define buffer_append_spaces(buf, num_spaces) \ ++ do { \ ++ char *tmp_spaces; \ ++ int tmp_spaces_len; \ ++ tmp_spaces_len = spprintf(&tmp_spaces, 0,"%*c", num_spaces, ' '); \ ++ smart_str_appendl(buf, tmp_spaces, tmp_spaces_len); \ ++ efree(tmp_spaces); \ ++ } while(0); + /* {{{ php_var_export */ + + static int php_array_element_export(zval **zv, int num_args, va_list args, zend_hash_key *hash_key) + { + int level; ++ smart_str *buf; ++ + TSRMLS_FETCH(); + + level = va_arg(args, int); ++ buf = va_arg(args, smart_str *); + +- if (hash_key->nKeyLength==0) { /* numeric key */ +- php_printf("%*c%ld => ", level + 1, ' ', hash_key->h); ++ if (hash_key->nKeyLength == 0) { /* numeric key */ ++ buffer_append_spaces(buf, level+1); ++ smart_str_append_long(buf, hash_key->h); ++ smart_str_appendl(buf, " => ", 4); + } else { /* string key */ + char *key, *tmp_str; + int key_len, tmp_len; + key = php_addcslashes(hash_key->arKey, hash_key->nKeyLength - 1, &key_len, 0, "'\\", 2 TSRMLS_CC); + tmp_str = php_str_to_str_ex(key, key_len, "\0", 1, "' . \"\\0\" . '", 12, &tmp_len, 0, NULL); +- php_printf("%*c'", level + 1, ' '); +- PHPWRITE(tmp_str, tmp_len); +- php_printf("' => "); ++ ++ buffer_append_spaces(buf, level + 1); ++ ++ smart_str_appendc(buf, '\''); ++ smart_str_appendl(buf, tmp_str, tmp_len); ++ smart_str_appendl(buf, "' => ", 5); ++ + efree(key); + efree(tmp_str); + } +- php_var_export(zv, level + 2 TSRMLS_CC); +- PUTS (",\n"); ++ php_var_export_ex(zv, level + 2, buf TSRMLS_CC); ++ ++ smart_str_appendc(buf, ','); ++ smart_str_appendc(buf, '\n'); ++ + return 0; + } + + static int php_object_element_export(zval **zv, int num_args, va_list args, zend_hash_key *hash_key) + { + int level; ++ smart_str *buf; + char *prop_name, *class_name; + TSRMLS_FETCH(); + + level = va_arg(args, int); ++ buf = va_arg(args, smart_str *); + +- php_printf("%*c", level + 1, ' '); ++ buffer_append_spaces(buf, level + 2); + if (hash_key->nKeyLength != 0) { + zend_unmangle_property_name(hash_key->arKey, hash_key->nKeyLength - 1, &class_name, &prop_name); +- php_printf(" '%s' => ", prop_name); ++ ++ smart_str_appendc(buf, '\''); ++ smart_str_appends(buf, prop_name); ++ smart_str_appendc(buf, '\''); + } else { +- php_printf(" %ld => ", hash_key->h); ++ smart_str_append_long(buf, hash_key->h); + } +- php_var_export(zv, level + 2 TSRMLS_CC); +- PUTS (",\n"); ++ ++ smart_str_appendl(buf, " => ", 4); ++ php_var_export_ex(zv, level + 2, buf TSRMLS_CC); ++ smart_str_appendc(buf, ','); ++ smart_str_appendc(buf, '\n'); ++ + return 0; + } + +-PHPAPI void php_var_export(zval **struc, int level TSRMLS_DC) ++PHPAPI void php_var_export_ex(zval **struc, int level, smart_str *buf TSRMLS_DC) /* {{{ */ + { + HashTable *myht; + char *tmp_str, *tmp_str2; +@@ -400,60 +429,85 @@ + + switch (Z_TYPE_PP(struc)) { + case IS_BOOL: +- php_printf("%s", Z_LVAL_PP(struc) ? "true" : "false"); ++ if (Z_LVAL_PP(struc)) { ++ smart_str_appendl(buf, "true", 4); ++ } else { ++ smart_str_appendl(buf, "false", 5); ++ } + break; + case IS_NULL: +- php_printf("NULL"); ++ smart_str_appendl(buf, "NULL", 4); + break; + case IS_LONG: +- php_printf("%ld", Z_LVAL_PP(struc)); ++ smart_str_append_long(buf, Z_LVAL_PP(struc)); + break; + case IS_DOUBLE: +- php_printf("%.*H", (int) EG(precision), Z_DVAL_PP(struc)); ++ tmp_len = spprintf(&tmp_str, 0,"%.*H", (int) EG(precision), Z_DVAL_PP(struc)); ++ smart_str_appendl(buf, tmp_str, tmp_len); ++ efree(tmp_str); + break; + case IS_STRING: + tmp_str = php_addcslashes(Z_STRVAL_PP(struc), Z_STRLEN_PP(struc), &tmp_len, 0, "'\\", 2 TSRMLS_CC); + tmp_str2 = php_str_to_str_ex(tmp_str, tmp_len, "\0", 1, "' . \"\\0\" . '", 12, &tmp_len2, 0, NULL); +- PUTS ("'"); +- PHPWRITE(tmp_str2, tmp_len2); +- PUTS ("'"); ++ ++ smart_str_appendc(buf, '\''); ++ smart_str_appendl(buf, tmp_str2, tmp_len2); ++ smart_str_appendc(buf, '\''); ++ + efree(tmp_str2); + efree(tmp_str); + break; + case IS_ARRAY: + myht = Z_ARRVAL_PP(struc); + if (level > 1) { +- php_printf("\n%*c", level - 1, ' '); ++ smart_str_appendc(buf, '\n'); ++ buffer_append_spaces(buf, level - 1); + } +- PUTS ("array (\n"); +- zend_hash_apply_with_arguments(myht, (apply_func_args_t) php_array_element_export, 1, level, 0); ++ smart_str_appendl(buf, "array (\n", 8); ++ zend_hash_apply_with_arguments(myht, (apply_func_args_t) php_array_element_export, 2, level, buf); ++ + if (level > 1) { +- php_printf("%*c", level - 1, ' '); ++ buffer_append_spaces(buf, level - 1); + } +- PUTS(")"); ++ smart_str_appendc(buf, ')'); ++ + break; + case IS_OBJECT: + myht = Z_OBJPROP_PP(struc); + if (level > 1) { +- php_printf("\n%*c", level - 1, ' '); ++ smart_str_appendc(buf, '\n'); ++ buffer_append_spaces(buf, level - 1); + } + Z_OBJ_HANDLER(**struc, get_class_name)(*struc, &class_name, &class_name_len, 0 TSRMLS_CC); +- php_printf ("%s::__set_state(array(\n", class_name); ++ ++ smart_str_appendl(buf, class_name, class_name_len); ++ smart_str_appendl(buf, "::__set_state(array(\n", 21); ++ + efree(class_name); + if (myht) { +- zend_hash_apply_with_arguments(myht, (apply_func_args_t) php_object_element_export, 1, level); ++ zend_hash_apply_with_arguments(myht, (apply_func_args_t) php_object_element_export, 2, level, buf); + } + if (level > 1) { +- php_printf("%*c", level - 1, ' '); ++ buffer_append_spaces(buf, level - 1); + } +- php_printf ("))"); ++ smart_str_appendl(buf, "))", 2); ++ + break; + default: +- PUTS ("NULL"); ++ smart_str_appendl(buf, "NULL", 4); + break; + } + } + ++/* FOR BC reasons, this will always perform and then print */ ++PHPAPI void php_var_export(zval **struc, int level TSRMLS_DC) /* {{{ */ ++{ ++ smart_str buf = {0}; ++ php_var_export_ex(struc, level, &buf TSRMLS_CC); ++ smart_str_0 (&buf); ++ PHPWRITE(buf.c, buf.len); ++ smart_str_free(&buf); ++} + /* }}} */ + + /* {{{ proto mixed var_export(mixed var [, bool return]) +@@ -462,21 +516,21 @@ + { + zval *var; + zend_bool return_output = 0; +- ++ smart_str buf = {0}; ++ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|b", &var, &return_output) == FAILURE) { + return; + } +- +- if (return_output) { +- php_start_ob_buffer (NULL, 0, 1 TSRMLS_CC); +- } +- +- php_var_export(&var, 1 TSRMLS_CC); ++ ++ php_var_export_ex(&var, 1, &buf TSRMLS_CC); ++ smart_str_0 (&buf); + + if (return_output) { +- php_ob_get_buffer (return_value TSRMLS_CC); +- php_end_ob_buffer (0, 0 TSRMLS_CC); ++ RETVAL_STRINGL(buf.c, buf.len, 1); ++ } else { ++ PHPWRITE(buf.c, buf.len); + } ++ smart_str_free(&buf); + } + /* }}} */ + --- php5-5.2.10.dfsg.1.orig/debian/patches/php5-pear-CVE-2011-1144.patch +++ php5-5.2.10.dfsg.1/debian/patches/php5-pear-CVE-2011-1144.patch @@ -0,0 +1,131 @@ +Subject: Introduce a time-of-check-time-of-use (TOCTOU) save file + handler, this makes sure that from the time we check it is available + until we get the file handler that no one attempted to put in a + soft / hard link instead of what we checked for. +Origin: http://svn.php.net/viewvc?view=revision&revision=309042 + +CVE-2011-1144 + +Index: PEAR/REST.php +=================================================================== +--- PEAR/REST.php (revision 309041) ++++ PEAR/REST.php (revision 309042) +@@ -228,59 +228,75 @@ + $cacheidfile = $d . 'rest.cacheid'; + $cachefile = $d . 'rest.cachefile'; + ++ if (!is_dir($cache_dir)) { ++ if (System::mkdir(array('-p', $cache_dir) === false)) { ++ return PEAR::raiseError("The value of config option cache_dir ($cache_dir) is not a directory and attempts to create the directory failed."); ++ } ++ } ++ + if ($cacheid === null && $nochange) { + $cacheid = unserialize(implode('', file($cacheidfile))); + } + +- if (is_link($cacheidfile)) { +- return PEAR::raiseError('SECURITY ERROR: Will not write to ' . $cacheidfile . ' as it is symlinked to ' . readlink($cacheidfile) . ' - Possible symlink attack'); +- } ++ $idData = serialize(array( ++ 'age' => time(), ++ 'lastChange' => ($nochange ? $cacheid['lastChange'] : $lastmodified), ++ )); + +- if (is_link($cachefile)) { +- return PEAR::raiseError('SECURITY ERROR: Will not write to ' . $cacheidfile . ' as it is symlinked to ' . readlink($cacheidfile) . ' - Possible symlink attack'); ++ $result = $this->saveCacheFile($cacheidfile, $idData); ++ if (PEAR::isError($result)) { ++ return $result; ++ } elseif ($nochange) { ++ return true; + } + +- $cacheidfile_fp = @fopen($cacheidfile, 'wb'); +- if (!$cacheidfile_fp) { +- if (is_dir($cache_dir)) { +- return PEAR::raiseError("The value of config option cache_dir ($cache_dir) is not a directory. "); ++ $result = $this->saveCacheFile($cachefile, serialize($contents)); ++ if (PEAR::isError($result)) { ++ if (file_exists($cacheidfile)) { ++ @unlink($cacheidfile); + } + +- System::mkdir(array('-p', $cache_dir)); +- $cacheidfile_fp = @fopen($cacheidfile, 'wb'); +- if (!$cacheidfile_fp) { +- return PEAR::raiseError("Could not open $cacheidfile for writing."); +- } ++ return $result; + } + +- if ($nochange) { +- fwrite($cacheidfile_fp, serialize(array( +- 'age' => time(), +- 'lastChange' => $cacheid['lastChange'], +- )) +- ); ++ return true; ++ } + +- fclose($cacheidfile_fp); +- return true; +- } ++ function saveCacheFile($file, $contents) ++ { ++ $len = strlen($contents); + +- fwrite($cacheidfile_fp, serialize(array( +- 'age' => time(), +- 'lastChange' => $lastmodified, +- )) +- ); +- fclose($cacheidfile_fp); ++ $cachefile_fp = @fopen($file, 'xb'); // x is the O_CREAT|O_EXCL mode ++ if ($cachefile_fp !== false) { // create file ++ if (fwrite($cachefile_fp, $contents, $len) < $len) { ++ fclose($cachefile_fp); ++ return PEAR::raiseError("Could not write $file."); ++ } ++ } else { // update file ++ $cachefile_lstat = lstat($file); ++ $cachefile_fp = @fopen($file, 'wb'); ++ if (!$cachefile_fp) { ++ return PEAR::raiseError("Could not open $file for writing."); ++ } + +- $cachefile_fp = @fopen($cachefile, 'wb'); +- if (!$cachefile_fp) { +- if (file_exists($cacheidfile)) { +- @unlink($cacheidfile); ++ $cachefile_fstat = fstat($cachefile_fp); ++ if ( ++ $cachefile_lstat['mode'] == $cachefile_fstat['mode'] && ++ $cachefile_lstat['ino'] == $cachefile_fstat['ino'] && ++ $cachefile_lstat['dev'] == $cachefile_fstat['dev'] && ++ $cachefile_fstat['nlink'] === 1 ++ ) { ++ if (fwrite($cachefile_fp, $contents, $len) < $len) { ++ fclose($cachefile_fp); ++ return PEAR::raiseError("Could not write $file."); ++ } ++ } else { ++ fclose($cachefile_fp); ++ $link = function_exists('readlink') ? readlink($file) : $file; ++ return PEAR::raiseError('SECURITY ERROR: Will not write to ' . $file . ' as it is symlinked to ' . $link . ' - Possible symlink attack'); + } +- +- return PEAR::raiseError("Could not open $cacheidfile for writing."); + } + +- fwrite($cachefile_fp, serialize($contents)); + fclose($cachefile_fp); + return true; + } +@@ -464,4 +480,4 @@ + + return $data; + } +-} +\ No newline at end of file ++} --- php5-5.2.10.dfsg.1.orig/debian/patches/CVE-2009-3558.patch +++ php5-5.2.10.dfsg.1/debian/patches/CVE-2009-3558.patch @@ -0,0 +1,16 @@ +Description: fix open_basedir restrictions bypass via posix_mkfifo +upstream, Origin: http://svn.php.net/viewvc?view=revision&revision=288943 + +diff -Nur php5-5.2.10.dfsg.1/ext/posix/posix.c php5-5.2.10.dfsg.1.new/ext/posix/posix.c +--- php5-5.2.10.dfsg.1/ext/posix/posix.c 2009-11-24 15:17:36.000000000 -0500 ++++ php5-5.2.10.dfsg.1.new/ext/posix/posix.c 2009-11-24 15:17:41.000000000 -0500 +@@ -680,7 +680,8 @@ + RETURN_FALSE; + } + +- if (PG(safe_mode) && (!php_checkuid(path, NULL, CHECKUID_ALLOW_ONLY_DIR))) { ++ if (php_check_open_basedir_ex(path, 0 TSRMLS_CC) || ++ (PG(safe_mode) && (!php_checkuid(path, NULL, CHECKUID_ALLOW_ONLY_DIR)))) { + RETURN_FALSE; + } + --- php5-5.2.10.dfsg.1.orig/debian/patches/fix_64bit_time.patch +++ php5-5.2.10.dfsg.1/debian/patches/fix_64bit_time.patch @@ -0,0 +1,106 @@ +Index: php5-5.2.4/ext/date/lib/parse_date.c +=================================================================== +--- php5-5.2.4.orig/ext/date/lib/parse_date.c 2008-02-27 12:58:25.768431881 -0500 ++++ php5-5.2.4/ext/date/lib/parse_date.c 2008-02-27 12:58:58.973467615 -0500 +@@ -668,7 +668,7 @@ + long value = 0; + const timelib_tz_lookup_table *tp; + +- while (**ptr != '\0' && **ptr != ')') { ++ while (**ptr != '\0' && **ptr != ')' && **ptr != ' ') { + ++*ptr; + } + end = *ptr; +Index: php5-5.2.4/ext/date/lib/parse_date.re +=================================================================== +--- php5-5.2.4.orig/ext/date/lib/parse_date.re 2008-02-27 12:58:25.800458866 -0500 ++++ php5-5.2.4/ext/date/lib/parse_date.re 2008-02-27 12:58:58.981470555 -0500 +@@ -667,7 +667,7 @@ + long value = 0; + const timelib_tz_lookup_table *tp; + +- while (**ptr != '\0' && **ptr != ')') { ++ while (**ptr != '\0' && **ptr != ')' && **ptr != ' ') { + ++*ptr; + } + end = *ptr; +Index: php5-5.2.4/ext/date/lib/timelib.h +=================================================================== +--- php5-5.2.4.orig/ext/date/lib/timelib.h 2008-02-27 12:58:25.868430735 -0500 ++++ php5-5.2.4/ext/date/lib/timelib.h 2008-02-27 12:58:58.905465712 -0500 +@@ -22,6 +22,9 @@ + #define __TIMELIB_H__ + + #include "timelib_structs.h" ++#if HAVE_LIMITS_H ++#include ++#endif + + #define TIMELIB_NONE 0x00 + #define TIMELIB_OVERRIDE_TIME 0x01 +Index: php5-5.2.4/ext/date/tests/bug41523.phpt +=================================================================== +--- php5-5.2.4.orig/ext/date/tests/bug41523.phpt 2008-02-27 12:58:25.936460995 -0500 ++++ php5-5.2.4/ext/date/tests/bug41523.phpt 2008-02-27 12:58:58.925463597 -0500 +@@ -1,5 +1,7 @@ + --TEST-- +-Bug #41523 (strtotime('0000-00-00 00:00:00') is parsed as 1999-11-30) ++Bug #41523 (strtotime('0000-00-00 00:00:00') is parsed as 1999-11-30) (32 bit) ++--SKIPIF-- ++ + --FILE-- + + --INI-- + error_reporting=2047 + --FILE-- +Index: php5-5.2.4/ext/date/tests/strtotime-mysql.phpt +=================================================================== +--- php5-5.2.4.orig/ext/date/tests/strtotime-mysql.phpt 2008-02-27 12:58:26.060432838 -0500 ++++ php5-5.2.4/ext/date/tests/strtotime-mysql.phpt 2008-02-27 12:58:58.949459635 -0500 +@@ -1,5 +1,7 @@ + --TEST-- +-strtotime() and mysql timestamps ++strtotime() and mysql timestamps (32 bit) ++--SKIPIF-- ++ + --FILE-- + + --FILE-- + ++ + --INI-- + precision=14 + --FILE-- --- php5-5.2.10.dfsg.1.orig/debian/patches/series +++ php5-5.2.10.dfsg.1/debian/patches/series @@ -0,0 +1,79 @@ +001-libtool_fixes.patch +002-static_openssl.patch +004-ldap_fix.patch +006-debian_quirks.patch +libtool2.2.patch +013-force_getaddrinfo.patch +017-pread_pwrite_disable.patch +019-z_off_t_as_long.patch +029-php.ini_paranoid.patch +#033-we_WANT_libtool.patch +034-apache2_umask_fix.patch +036-fd_setsize_fix.patch +043-recode_size_t.patch +044-strtod_arm_fix.patch +045-exif_nesting_level.patch +047-zts_with_dl.patch +052-phpinfo_no_configure.patch +053-extension_api.patch +056-mime_magic_liberal.patch +057-no_apache_installed.patch +100-recode_is_shared.patch +101-sqlite_is_shared.patch +107-reflection_is_ext.patch +108-64_bit_datetime.patch +112-proc_open.patch +113-php.ini_securitynotes.patch +disable_dl_by_default.patch +libdb_is_-ldb +suhosin.patch +fix_broken_upstream_tests.patch +use_embedded_timezonedb.patch +manpage_spelling.patch +force_libmysqlclient_r.patch +119-sybase-alias.patch +libedit_is_editline.patch +bad_whatis_entries.patch +fix-autoconf-ftbfs.patch +curl_streams_sleep.patch +gentoo/006_ext-curl-set_opt-crash.patch +gentoo/009_ob-memory-leaks.patch +mssql-null-exception.patch +exif_read_data-segfault.patch +fix-zlib-compression.patch +CVE-2009-3291.patch +CVE-2009-3292.patch +CVE-2009-3557.patch +CVE-2009-3558.patch +CVE-2009-4017.patch +CVE-2009-4018.patch +CVE-2009-2626.patch +CVE-2009-4142.patch +CVE-2009-4143.patch +CVE-2010-0397.patch +CVE-2010-1128.patch +CVE-2010-1129.patch +CVE-2010-1130.patch +CVE-2010-1868.patch +CVE-2010-1917.patch +CVE-2010-2225.patch +CVE-2010-2531.patch +CVE-2010-3065.patch +php5-CVE-2009-5016.patch +php5-CVE-2010-3436.patch +php5-CVE-2010-3709.patch +php5-CVE-2010-3710.patch +php5-CVE-2010-3870.patch +php5-CVE-2010-4645.patch +php5-CVE-2010-3436-regression.patch +php5-CVE-2010-4697.patch -p0 +php5-CVE-2010-4698.patch -p0 +php5-CVE-2011-0421.patch -p0 +php5-CVE-2011-0708.patch -p0 +php5-CVE-2011-1092.patch -p0 +php5-CVE-2011-1148.patch -p0 +php5-CVE-2011-1464.patch -p0 +php5-CVE-2011-1466.patch -p0 +php5-CVE-2011-1469.patch -p0 +php5-CVE-2011-1470.patch -p0 +php5-CVE-2011-1471.patch -p0 --- php5-5.2.10.dfsg.1.orig/debian/patches/CVE-2009-2626.patch +++ php5-5.2.10.dfsg.1/debian/patches/CVE-2009-2626.patch @@ -0,0 +1,44 @@ +Description: fix information disclosure and denial of service via + zend_restore_ini_entry_cb function. +Origin: upstream, http://svn.php.net/viewvc?view=revision&revision=284157 +Origin: upstream, http://svn.php.net/viewvc?view=revision&revision=283946 +Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=540605 + +diff -Nur php5-5.2.10.dfsg.1/main/main.c php5-5.2.10.dfsg.1.new/main/main.c +--- php5-5.2.10.dfsg.1/main/main.c 2010-01-05 13:11:56.000000000 -0500 ++++ php5-5.2.10.dfsg.1.new/main/main.c 2010-01-05 13:12:15.000000000 -0500 +@@ -312,8 +312,7 @@ + static PHP_INI_MH(OnUpdateErrorLog) + { + /* Only do the safemode/open_basedir check at runtime */ +- if ((stage == PHP_INI_STAGE_RUNTIME || stage == PHP_INI_STAGE_HTACCESS) && +- strcmp(new_value, "syslog")) { ++ if ((stage == PHP_INI_STAGE_RUNTIME || stage == PHP_INI_STAGE_HTACCESS) && new_value && strcmp(new_value, "syslog")) { + if (PG(safe_mode) && (!php_checkuid(new_value, NULL, CHECKUID_CHECK_FILE_AND_DIR))) { + return FAILURE; + } +diff -Nur php5-5.2.10.dfsg.1/Zend/zend_ini.c php5-5.2.10.dfsg.1.new/Zend/zend_ini.c +--- php5-5.2.10.dfsg.1/Zend/zend_ini.c 2008-12-31 06:17:33.000000000 -0500 ++++ php5-5.2.10.dfsg.1.new/Zend/zend_ini.c 2010-01-05 13:12:15.000000000 -0500 +@@ -46,15 +46,20 @@ + + static int zend_restore_ini_entry_cb(zend_ini_entry *ini_entry, int stage TSRMLS_DC) /* {{{ */ + { ++ int result = FAILURE; + if (ini_entry->modified) { + if (ini_entry->on_modify) { + zend_try { + /* even if on_modify bails out, we have to continue on with restoring, + since there can be allocated variables that would be freed on MM shutdown + and would lead to memory corruption later ini entry is modified again */ +- ini_entry->on_modify(ini_entry, ini_entry->orig_value, ini_entry->orig_value_length, ini_entry->mh_arg1, ini_entry->mh_arg2, ini_entry->mh_arg3, stage TSRMLS_CC); ++ result = ini_entry->on_modify(ini_entry, ini_entry->orig_value, ini_entry->orig_value_length, ini_entry->mh_arg1, ini_entry->mh_arg2, ini_entry->mh_arg3, stage TSRMLS_CC); + } zend_end_try(); + } ++ if(stage == ZEND_INI_STAGE_RUNTIME && result == FAILURE) { ++ /* runtime failure is OK */ ++ return 1; ++ } + if (ini_entry->value != ini_entry->orig_value) { + efree(ini_entry->value); + } --- php5-5.2.10.dfsg.1.orig/debian/patches/CVE-2010-1129.patch +++ php5-5.2.10.dfsg.1/debian/patches/CVE-2010-1129.patch @@ -0,0 +1,15 @@ +Description: fix safe_mode bypass via trailing slash in dir pathnames +Origin: upstream, http://svn.php.net/viewvc?view=revision&revision=294882 + +diff -Nur php5-5.2.10.dfsg.1/ext/standard/file.c php5-5.2.10.dfsg.1.new/ext/standard/file.c +--- php5-5.2.10.dfsg.1/ext/standard/file.c 2010-09-14 14:37:08.000000000 -0400 ++++ php5-5.2.10.dfsg.1.new/ext/standard/file.c 2010-09-14 14:37:12.000000000 -0400 +@@ -838,7 +838,7 @@ + convert_to_string_ex(arg1); + convert_to_string_ex(arg2); + +- if (PG(safe_mode) &&(!php_checkuid(Z_STRVAL_PP(arg1), NULL, CHECKUID_ALLOW_ONLY_DIR))) { ++ if (PG(safe_mode) &&(!php_checkuid(Z_STRVAL_PP(arg1), NULL, CHECKUID_CHECK_FILE_AND_DIR))) { + RETURN_FALSE; + } + --- php5-5.2.10.dfsg.1.orig/debian/patches/029-php.ini_paranoid.patch +++ php5-5.2.10.dfsg.1/debian/patches/029-php.ini_paranoid.patch @@ -0,0 +1,1507 @@ +--- /dev/null ++++ php/php.ini-paranoid +@@ -0,0 +1,1504 @@ ++[PHP] ++ ++;;;;;;;;;;; ++; WARNING ; ++;;;;;;;;;;; ++; This file enables many features in the PHP configuration that will ++; break applications that rely on this. Make sure you test applications ++; with this configuration file before enabling it on production. ++ ++;;;;;;;;;;;;;;;;;;; ++; About php.ini ; ++;;;;;;;;;;;;;;;;;;; ++; This file controls many aspects of PHP's behavior. In order for PHP to ++; read it, it must be named 'php.ini'. PHP looks for it in the current ++; working directory, in the path designated by the environment variable ++; PHPRC, and in the path that was defined in compile time (in that order). ++; Under Windows, the compile-time path is the Windows directory. The ++; path in which the php.ini file is looked for can be overridden using ++; the -c argument in command line mode. ++; ++; The syntax of the file is extremely simple. Whitespace and Lines ++; beginning with a semicolon are silently ignored (as you probably guessed). ++; Section headers (e.g. [Foo]) are also silently ignored, even though ++; they might mean something in the future. ++; ++; Directives are specified using the following syntax: ++; directive = value ++; Directive names are *case sensitive* - foo=bar is different from FOO=bar. ++; ++; The value can be a string, a number, a PHP constant (e.g. E_ALL or M_PI), one ++; of the INI constants (On, Off, True, False, Yes, No and None) or an expression ++; (e.g. E_ALL & ~E_NOTICE), or a quoted string ("foo"). ++; ++; Expressions in the INI file are limited to bitwise operators and parentheses: ++; | bitwise OR ++; & bitwise AND ++; ~ bitwise NOT ++; ! boolean NOT ++; ++; Boolean flags can be turned on using the values 1, On, True or Yes. ++; They can be turned off using the values 0, Off, False or No. ++; ++; An empty string can be denoted by simply not writing anything after the equal ++; sign, or by using the None keyword: ++; ++; foo = ; sets foo to an empty string ++; foo = none ; sets foo to an empty string ++; foo = "none" ; sets foo to the string 'none' ++; ++; If you use constants in your value, and these constants belong to a ++; dynamically loaded extension (either a PHP extension or a Zend extension), ++; you may only use these constants *after* the line that loads the extension. ++; ++; ++;;;;;;;;;;;;;;;;;;; ++; About this file ; ++;;;;;;;;;;;;;;;;;;; ++; ++; This is the paranoid, PHP version of the php.ini-dist file. It ++; sets some non standard settings, that make PHP more efficient, more secure ++; in a very paranoid way. Note that these security settings will make some ++; applications not work properly. ++; ++; The price is that with these settings, PHP may be incompatible with some ++; applications, and sometimes, more difficult to develop with. Using this ++; file is recommended for production sites which want a high degree of ++; security. As all of the changes from the standard settings are thoroughly ++; documented, you can go over each one, ++; and decide whether you want to use it or not. ++; ++; For general information about the php.ini file, please consult the ++; php.ini-dist file, included in your PHP distribution. ++; ++; For further information see ++; http://www.php.net/features.safe-mode ++; http://www.phpsecure.info/ ++; ++; This file is different from the php.ini-dist file in the fact that it features ++; different values for several directives, in order to improve performance, while ++; possibly breaking compatibility with the standard out-of-the-box behavior of ++; PHP 3. Please make sure you read what's different, and modify your scripts ++; accordingly, if you decide to use this file instead. ++; ++; Notice that the paranoid configuration file might not be fully up-to-date ++; with the latest variables available so the diff will catch both the changes ++; to the default variable values as well as the variables that are missing in ++; the paranoid configuration file) ++; ++; This version was generated using the version 5.2.4-2 as a basis. ++; ++; Debian users can find the differences between both configurations might ++; be found by running: ++; ++; $ diff -u /usr/share/doc/php5-common/examples/php.ini-dist \ ++ /usr/share/doc/php5-common/examples/php.ini-paranoid |less ++; ++; ++; This is a (not complete) list of some of the changes introduced in this file: ++; ++; - safe_mode = On [Security, Performance loss] ++; Do UID checks when opening files. Enabling safe_mode also enables ++; other functions related to this mode. For more information read: ++; http://www.php.net/features.safe-mode ++; ++; However, this feature by itself cannot be relied on to protect all applications. ++; It is worthwhile reading also: ++; http://ilia.ws/archives/18_PHPs_safe_mode_or_how_not_to_implement_security.html ++; Bottomline: Do not trust that safe_mode will drive all your security vulnerabilities ++; away. ++; ++; - safe_mode_protected_env_vars = LD_LIBRARY_PATH, PATH [Security] ++; Environment variables that users will not be able to modify through ++; putenv(). PATH is added so that scripts cannot overwrite it ++; ++; - open_basedir = /var/www/:/usr/lib/php4/ [Security, Performance loss] ++; Limits the files that PHP can access to the directories specified. ++; This includes the webroot and the usual location of PHP libraries ++; (e.g. PEAR). Since all file locations are checked against this list ++; before any access is allowed, this impacts in the performance of all ++; file operations. ++; ++; - disable_functions = dl, phpinfo, system, .... [Security] ++; Some functions can be used by attackers and can be malversed by ++; applications, the list (not complete) of functions disabled includes ++; functions which might have a severe impact to the system if wrongly used ++; in scripts or subverted remotely by attackers. ++; ++; - expose_php = Off [?Security?] ++; Not exposing that PHP is used in the site (nor its version) can affect ++; how some dumb worms attempt to attack the site. Many might ++; not check this and attempt to compromise the server nevertheless, ++; however. This setting is just 'security by obscurity' so no real ++; security at all (save vs. the dumbest attackers) ++; ++; - error_log = syslog [Security, Performance log] ++; All errors are reported to syslog so that the errors can be easily ++; sent outsite the site to a syslog server. This prevents an intruder ++; from tampering with them in an attempt to hide his tracks since the ++; logs are stored in a different location. It also helps in forensic ++; investigation or when using automatic tools to produce reports or ++; generate alarms based on the syslog information. ++; ++; - error_reporting = E_ALL [Code Cleanliness, Security(?)] ++; By default, PHP surpresses errors of type E_NOTICE. These error messages ++; are emitted for non-critical errors, but that could be a symptom of a bigger ++; problem. Most notably, this will cause error messages about the use ++; of uninitialized variables to be displayed. ++; ++; - display_errors = Off [Security] ++; With this directive set to off, errors that occur during the execution of ++; scripts will no longer be displayed as a part of the script output, and thus, ++; will no longer be exposed to remote users. With some errors, the error message ++; content may expose information about your script, web server, or database ++; server that may be exploitable for hacking. Production sites should have this ++; directive set to off. ++; - log_errors = On [Security] ++; This directive complements the above one. Any errors that occur during the ++; execution of your script will be logged (typically, to your server's error log, ++; but can be configured in several ways). Along with setting display_errors to off, ++; this setup gives you the ability to fully understand what may have gone wrong, ++; without exposing any sensitive information to remote users. ++; - output_buffering = 4096 [Performance] ++; Set a 4KB output buffer. Enabling output buffering typically results in less ++; writes, and sometimes less packets sent on the wire, which can often lead to ++; better performance. The gain this directive actually yields greatly depends ++; on which Web server you're working with, and what kind of scripts you're using. ++; - register_globals = Off [Security, Performance] ++; Global variables are no longer registered for input data (POST, GET, cookies, ++; environment and other server variables). Instead of using $foo, you must use ++; you can use $_REQUEST["foo"] (includes any variable that arrives through the ++; request, namely, POST, GET and cookie variables), or use one of the specific ++; $_GET["foo"], $_POST["foo"], $_COOKIE["foo"] or $_FILES["foo"], depending ++; on where the input originates. Also, you can look at the ++; import_request_variables() function. ++; Note that register_globals is deprecated in PHP 6.0, because it often ++; leads to security bugs. ++; Read http://php.net/manual/en/security.registerglobals.php for further ++; information. ++; Also notice that applications should not rely on this feature being turned Off ++; to remain secure. ++; - register_long_arrays = Off [Performance] ++; Disables registration of HTTP_GET_VARS ++; - register_argc_argv = Off [Performance] ++; Disables registration of the somewhat redundant $argv and $argc global ++; variables. ++; - include_path = "/usr/share/php" [Security] ++; Only files under /usr can be included, this prevents applications from ++; including files from the same directory they are running in. ++; - magic_quotes_gpc = On [Security] ++; Input data is escaped with slashes so that applications that do ++; not use addslashes() are not so easily subjected to SQL injection ++; when talking to SQL databases. ++; This features is deprecated in PHP 6.0, applications should be fixed to ++; prevent SQL injection attacks through input data and not rely on this feature. ++; - magic_quotes_runtime = On [Security] ++; Quotes in data returned from functions that access external data sources (such as ++; databases) are escapted with a backslash. ++; This features is deprecated in PHP 6.0, applications should be fixed to ++; prevent SQL injection attacks through input data and not rely on this feature. ++; ++; - variables_order = "GPCS" [Performance] ++; The environment variables are not hashed into the $HTTP_ENV_VARS[]. To access ++; environment variables, you can use getenv() instead. ++; - allow_call_time_pass_reference = Off [Code cleanliness] ++; It's not possible to decide to force a variable to be passed by reference ++; when calling a function. The PHP 4 style to do this is by making the ++; function require the relevant argument by reference. ++; ++; - enable_dl = Off [Security] ++; The dl() function is not needed in most environments and does introduce ++; a number of security issues. ++; - file_uploads = Off [Security] ++; File uploads should not be allowed to the server. ++; - allow_url_fopen = Off [Security] ++; File calls should not transparently retrieve files from the network ++; since this could be subverted by attackers in poorly coded scripts ++; by forcing them to download (and execute) malicious remote content ++; from compromised hosts. This behaviour has been observed in automatic ++; worms/tools that use it to scan and propagate through badly written ++; applications (in conjuntion with other unsafe features) ++; http://myhost/myapplication.php?include=http://roguesever/rogueapp.php ++; ++; - session.save_path = /var/lib/php5 [Security] ++; This is defined to a non-world readable directory so users cannot ++; hihack sessions of other users by getting a list of the files. ++; ++; Notice that on on shared servers on a per application basis, otherwise ++; other users would be able to get access to other applications' data by ++; setting a proper session id in a different application. If session paths ++; are not shared sessions of one application will be invalid on another. ++; For more information see: ++; http://php.net/manual/en/ref.session.php#ini.session.save-path ++; and ++; http://php.net/manual/en/function.session-save-path.php ++; - session.cookie_secure = 1 [Security] ++; Cookies will only be sent through secure (SSL) connections. ++; - session.use_only_cookies = 1 [Security] ++; Session ids are not allowed in URLs which make it more difficult for ++; cross site scripting (XSS) attacks to be succesfull and also has the ++; advantaged that session ids will not be stored in the server's logs making ++; them vulnerable to reuse by people with access to the server logs. ++; - session.cookie_httponly = 1 [Security] ++; Cookies can only be set through the HTTP protocol, JavaScript can not ++; modify them, making applications less vulnerable to XSS attacks. This is ++; not supported, however, by all browsers. ++; - session.hash_function = 1 [Security, Performance loss] ++; Use SHA-1 instead of MD5 which is not (yet) broken but there are some known ++; attacks. Slight performance loss as it takes more time to compute. ++; ++; ++; This file is maintained by Javier Fernandez-Sanguino ++; please forward him any suggestions or changes you believe might be appropiate ++ ++ ++;;;;;;;;;;;;;;;;;;;; ++; Language Options ; ++;;;;;;;;;;;;;;;;;;;; ++ ++; Enable the PHP scripting language engine under Apache. ++engine = On ++ ++; Enable compatibility mode with Zend Engine 1 (PHP 4.x) ++zend.ze1_compatibility_mode = Off ++ ++; Allow the tags are recognized. ++; NOTE: Using short tags should be avoided when developing applications or ++; libraries that are meant for redistribution, or deployment on PHP ++; servers which are not under your control, because short tags may not ++; be supported on the target server. For portable, redistributable code, ++; be sure not to use short tags. ++short_open_tag = On ++ ++; Allow ASP-style <% %> tags. ++asp_tags = Off ++ ++; The number of significant digits displayed in floating point numbers. ++precision = 12 ++ ++; Enforce year 2000 compliance (will cause problems with non-compliant browsers) ++y2k_compliance = On ++ ++; Output buffering allows you to send header lines (including cookies) even ++; after you send body content, at the price of slowing PHP's output layer a ++; bit. You can enable output buffering during runtime by calling the output ++; buffering functions. You can also enable output buffering for all files by ++; setting this directive to On. If you wish to limit the size of the buffer ++; to a certain size - you can use a maximum number of bytes instead of 'On', as ++; a value for this directive (e.g., output_buffering=4096). ++output_buffering = 4096 ++ ++; You can redirect all of the output of your scripts to a function. For ++; example, if you set output_handler to "mb_output_handler", character ++; encoding will be transparently converted to the specified encoding. ++; Setting any output handler automatically turns on output buffering. ++; Note: People who wrote portable scripts should not depend on this ini ++; directive. Instead, explicitly set the output handler using ob_start(). ++; Using this ini directive may cause problems unless you know what script ++; is doing. ++; Note: You cannot use both "mb_output_handler" with "ob_iconv_handler" ++; and you cannot use both "ob_gzhandler" and "zlib.output_compression". ++; Note: output_handler must be empty if this is set 'On' !!!! ++; Instead you must use zlib.output_handler. ++;output_handler = ++ ++; Transparent output compression using the zlib library ++; Valid values for this option are 'off', 'on', or a specific buffer size ++; to be used for compression (default is 4KB) ++; Note: Resulting chunk size may vary due to nature of compression. PHP ++; outputs chunks that are few hundreds bytes each as a result of ++; compression. If you prefer a larger chunk size for better ++; performance, enable output_buffering in addition. ++; Note: You need to use zlib.output_handler instead of the standard ++; output_handler, or otherwise the output will be corrupted. ++zlib.output_compression = Off ++ ++; You cannot specify additional output handlers if zlib.output_compression ++; is activated here. This setting does the same as output_handler but in ++; a different order. ++;zlib.output_handler = ++ ++; Implicit flush tells PHP to tell the output layer to flush itself ++; automatically after every output block. This is equivalent to calling the ++; PHP function flush() after each and every call to print() or echo() and each ++; and every HTML block. Turning this option on has serious performance ++; implications and is generally recommended for debugging purposes only. ++implicit_flush = Off ++ ++; The unserialize callback function will be called (with the undefined class' ++; name as parameter), if the unserializer finds an undefined class ++; which should be instantiated. ++; A warning appears if the specified function is not defined, or if the ++; function doesn't include/implement the missing class. ++; So only set this entry, if you really want to implement such a ++; callback-function. ++unserialize_callback_func= ++ ++; When floats & doubles are serialized store serialize_precision significant ++; digits after the floating point. The default value ensures that when floats ++; are decoded with unserialize, the data will remain the same. ++serialize_precision = 100 ++ ++; Whether to enable the ability to force arguments to be passed by reference ++; at function call time. This method is deprecated and is likely to be ++; unsupported in future versions of PHP/Zend. The encouraged method of ++; specifying which arguments should be passed by reference is in the function ++; declaration. You're encouraged to try and turn this option Off and make ++; sure your scripts work properly with it in order to ensure they will work ++; with future versions of the language (you will receive a warning each time ++; you use this feature, and the argument will be passed by value instead of by ++; reference). ++allow_call_time_pass_reference = Off ++ ++; ++; Safe Mode ++; ++; Notice that with this mode on PHP will not create new files in ++; directories which have different owner than the owner of the script. This ++; typically applies to /tmp, so contrary to Unix intuition, you will not be able ++; to create new files there (even if the /tmp rights are set correctly). ++; ++; NOTE: this is considered a "broken" security measure. ++; Applications relying on this feature will not recieve full ++; support by the security team. For more information please ++; see /usr/share/doc/php5-common/README.Debian.security ++; ++safe_mode = On ++ ++; By default, Safe Mode does a UID compare check when ++; opening files. If you want to relax this to a GID compare, ++; then turn on safe_mode_gid. ++safe_mode_gid = Off ++ ++; When safe_mode is on, UID/GID checks are bypassed when ++; including files from this directory and its subdirectories. ++; (directory must also be in include_path or full path must ++; be used when including) ++safe_mode_include_dir = ++ ++; When safe_mode is on, only executables located in the safe_mode_exec_dir ++; will be allowed to be executed via the exec family of functions. ++; ++; Note: This should be customised per site (if exec is permitted) ++safe_mode_exec_dir = ++ ++; Setting certain environment variables may be a potential security breach. ++; This directive contains a comma-delimited list of prefixes. In Safe Mode, ++; the user may only alter environment variables whose names begin with the ++; prefixes supplied here. By default, users will only be able to set ++; environment variables that begin with PHP_ (e.g. PHP_FOO=BAR). ++; ++; Note: If this directive is empty, PHP will let the user modify ANY ++; environment variable! ++safe_mode_allowed_env_vars = PHP_ ++ ++; This directive contains a comma-delimited list of environment variables that ++; the end user won't be able to change using putenv(). These variables will be ++; protected even if safe_mode_allowed_env_vars is set to allow to change them. ++safe_mode_protected_env_vars = LD_LIBRARY_PATH,PATH ++ ++; open_basedir, if set, limits all file operations to the defined directory ++; and below. This directive makes most sense if used in a per-directory ++; or per-virtualhost web server configuration file. This directive is ++; *NOT* affected by whether Safe Mode is turned On or Off. ++; ++; In Debian, the WebRoot is /var/www/ so we limit file operations to it. ++; ++; NOTE: this is considered a "broken" security measure. ++; Applications relying on this feature will not recieve full ++; support by the security team. For more information please ++; see /usr/share/doc/php5-common/README.Debian.security ++open_basedir = /var/www/:/usr/lib/php4/ ++ ++; This directive allows you to disable certain functions for security reasons. ++; It receives a comma-delimited list of function names. This directive is ++; *NOT* affected by whether Safe Mode is turned On or Off. ++; ++; Notes: ++; - The list of functions disabled here might break some applications ++; however, they are considered dangerous and often subverted by attackers ++; remotely. ++; - 'include' is not in the list, if your applications do not depend on it ++; make sure you add it here too. ++disable_functions = dl, phpinfo, system, mail, shell_exec, exec, escapeshellarg, escapeshellcmd, passthru, proc_close, proc_open, proc_get_status, proc_nice, proc_open, proc_terminate, popen, pclose, chown, disk_free_space, disk_total_space, diskfreespace, fileinode, max_execution_time, set_time_limit, highlight_file, show_source ++ ++; This directive allows you to disable certain classes for security reasons. ++; It receives a comma-delimited list of class names. This directive is ++; *NOT* affected by whether Safe Mode is turned On or Off. ++disable_classes = ++ ++; Colors for Syntax Highlighting mode. Anything that's acceptable in ++; would work. ++;highlight.string = #DD0000 ++;highlight.comment = #FF9900 ++;highlight.keyword = #007700 ++;highlight.bg = #FFFFFF ++;highlight.default = #0000BB ++;highlight.html = #000000 ++ ++; If enabled, the request will be allowed to complete even if the user aborts ++; the request. Consider enabling it if executing long request, which may end up ++; being interrupted by the user or a browser timing out. ++; ignore_user_abort = On ++ ++; Determines the size of the realpath cache to be used by PHP. This value should ++; be increased on systems where PHP opens many files to reflect the quantity of ++; the file operations performed. ++; realpath_cache_size=16k ++ ++; Duration of time, in seconds for which to cache realpath information for a given ++; file or directory. For systems with rarely changing files, consider increasing this ++; value. ++; realpath_cache_ttl=120 ++ ++; ++; Misc ++; ++; Decides whether PHP may expose the fact that it is installed on the server ++; (e.g. by adding its signature to the Web server header). It is no security ++; threat in any way, but it makes it possible to determine whether you use PHP ++; on your server or not. ++expose_php = Off ++ ++ ++;;;;;;;;;;;;;;;;;;; ++; Resource Limits ; ++;;;;;;;;;;;;;;;;;;; ++ ++max_execution_time = 30 ; Maximum execution time of each script, in seconds ++max_input_time = 60 ; Maximum amount of time each script may spend parsing request data ++max_input_nesting_level = 64 ; Maximum input variable nesting level ++memory_limit = 8M ; Maximum amount of memory a script may consume (8MB) ++ ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Error handling and logging ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; error_reporting is a bit-field. Or each number up to get desired error ++; reporting level ++; E_ALL - All errors and warnings (doesn't include E_STRICT) ++; E_ERROR - fatal run-time errors ++; E_RECOVERABLE_ERROR - almost fatal run-time errors ++; E_WARNING - run-time warnings (non-fatal errors) ++; E_PARSE - compile-time parse errors ++; E_NOTICE - run-time notices (these are warnings which often result ++; from a bug in your code, but it's possible that it was ++; intentional (e.g., using an uninitialized variable and ++; relying on the fact it's automatically initialized to an ++; empty string) ++; E_STRICT - run-time notices, enable to have PHP suggest changes ++; to your code which will ensure the best interoperability ++; and forward compatibility of your code ++; E_CORE_ERROR - fatal errors that occur during PHP's initial startup ++; E_CORE_WARNING - warnings (non-fatal errors) that occur during PHP's ++; initial startup ++; E_COMPILE_ERROR - fatal compile-time errors ++; E_COMPILE_WARNING - compile-time warnings (non-fatal errors) ++; E_USER_ERROR - user-generated error message ++; E_USER_WARNING - user-generated warning message ++; E_USER_NOTICE - user-generated notice message ++; ++; Examples: ++; ++; - Show all errors, except for notices and coding standards warnings ++; ++;error_reporting = E_ALL & ~E_NOTICE ++; ++; - Show all errors, except for notices ++; ++;error_reporting = E_ALL & ~E_NOTICE | E_STRICT ++; ++; - Show only errors ++; ++;error_reporting = E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE_ERROR ++; ++; - Show all errors ++; ++error_reporting = E_ALL ++ ++; Print out errors (as a part of the output). For production web sites, ++; you're strongly encouraged to turn this feature off, and use error logging ++; instead (see below). Keeping display_errors enabled on a production web site ++; may reveal security information to end users, such as file paths on your Web ++; server, your database schema or other information. ++; ++; possible values for display_errors: ++; ++; Off - Do not display any errors ++; stderr - Display errors to STDERR (affects only CGI/CLI binaries!) ++; stdout (On) - Display errors to STDOUT ++; ++display_errors = Off ++ ++; Even when display_errors is on, errors that occur during PHP's startup ++; sequence are not displayed. It's strongly recommended to keep ++; display_startup_errors off, except for when debugging. ++display_startup_errors = Off ++ ++; Log errors into a log file (server-specific log, stderr, or error_log (below)) ++; As stated above, you're strongly advised to use error logging in place of ++; error displaying on production web sites. ++log_errors = On ++ ++; Set maximum length of log_errors. In error_log information about the source is ++; added. The default is 1024 and 0 allows to not apply any maximum length at all. ++log_errors_max_len = 1024 ++ ++; Do not log repeated messages. Repeated errors must occur in same file on same ++; line until ignore_repeated_source is set true. ++ignore_repeated_errors = Off ++ ++; Ignore source of message when ignoring repeated messages. When this setting ++; is On you will not log errors with repeated messages from different files or ++; source lines. ++ignore_repeated_source = Off ++ ++; If this parameter is set to Off, then memory leaks will not be shown (on ++; stdout or in the log). This has only effect in a debug compile, and if ++; error reporting includes E_WARNING in the allowed list ++report_memleaks = On ++ ++;report_zend_debug = 0 ++ ++; Store the last error/warning message in $php_errormsg (boolean). ++track_errors = Off ++ ++; Disable the inclusion of HTML tags in error messages. ++; Note: Never use this feature for production boxes. ++html_errors = Off ++ ++; If html_errors is set On PHP produces clickable error messages that direct ++; to a page describing the error or function causing the error in detail. ++; You can download a copy of the PHP manual from http://www.php.net/docs.php ++; and change docref_root to the base URL of your local copy including the ++; leading '/'. You must also specify the file extension being used including ++; the dot. ++; Note: Never use this feature for production boxes. ++;docref_root = "/phpmanual/" ++;docref_ext = .html ++ ++; String to output before an error message. ++;error_prepend_string = "" ++ ++; String to output after an error message. ++;error_append_string = "" ++ ++; Log errors to specified file. ++;error_log = filename ++ ++; Log errors to syslog (Event Log on NT, not valid in Windows 95). ++error_log = syslog ++ ++ ++;;;;;;;;;;;;;;;;; ++; Data Handling ; ++;;;;;;;;;;;;;;;;; ++; ++; Note - track_vars is ALWAYS enabled as of PHP 4.0.3 ++ ++; The separator used in PHP generated URLs to separate arguments. ++; Default is "&". ++;arg_separator.output = "&" ++ ++; List of separator(s) used by PHP to parse input URLs into variables. ++; Default is "&". ++; NOTE: Every character in this directive is considered as separator! ++;arg_separator.input = ";&" ++ ++; This directive describes the order in which PHP registers GET, POST, Cookie, ++; Environment and Built-in variables (G, P, C, E & S respectively, often ++; referred to as EGPCS or GPC). Registration is done from left to right, newer ++; values override older values. ++variables_order = "GPCS" ++ ++; Whether or not to register the EGPCS variables as global variables. You may ++; want to turn this off if you don't want to clutter your scripts' global scope ++; with user data. This makes most sense when coupled with track_vars - in which ++; case you can access all of the GPC variables through the $HTTP_*_VARS[], ++; variables. ++; ++; You should do your best to write your scripts so that they do not require ++; register_globals to be on; Using form variables as globals can easily lead ++; to possible security problems, if the code is not very well thought of. ++ ++; NOTE: applications relying on this feature will not recieve full ++; support by the security team. For more information please ++; see /usr/share/doc/php5-common/README.Debian.security ++; ++register_globals = Off ++ ++; Whether or not to register the old-style input arrays, HTTP_GET_VARS ++; and friends. If you're not using them, it's recommended to turn them off, ++; for performance reasons. ++register_long_arrays = Off ++ ++; This directive tells PHP whether to declare the argv&argc variables (that ++; would contain the GET information). If you don't use these variables, you ++; should turn it off for increased performance. ++register_argc_argv = Off ++ ++; When enabled, the SERVER and ENV variables are created when they're first ++; used (Just In Time) instead of when the script starts. If these variables ++; are not used within a script, having this directive on will result in a ++; performance gain. The PHP directives register_globals, register_long_arrays, ++; and register_argc_argv must be disabled for this directive to have any affect. ++auto_globals_jit = On ++ ++; Maximum size of POST data that PHP will accept. ++post_max_size = 8M ++ ++; Magic quotes ++; ++ ++; Magic quotes for incoming GET/POST/Cookie data. ++; Note: This feature is deprecated in PHP 6.0. Applications should not rely ++; on this feature to prevent security attacks. ++magic_quotes_gpc = On ++ ++; Magic quotes for runtime-generated data, e.g. data from SQL, from exec(), etc. ++; Note: This feature is deprecated in PHP 6.0. Applications should not rely ++; on this feature to prevent security attacks. ++magic_quotes_runtime = On ++ ++; Use Sybase-style magic quotes (escape ' with '' instead of \'). ++magic_quotes_sybase = Off ++ ++; Automatically add files before or after any PHP document. ++auto_prepend_file = ++auto_append_file = ++ ++; As of 4.0b4, PHP always outputs a character encoding by default in ++; the Content-type: header. To disable sending of the charset, simply ++; set it to be empty. ++; ++; PHP's built-in default is text/html ++default_mimetype = "text/html" ++;default_charset = "iso-8859-1" ++ ++; Always populate the $HTTP_RAW_POST_DATA variable. ++;always_populate_raw_post_data = On ++ ++ ++;;;;;;;;;;;;;;;;;;;;;;;;; ++; Paths and Directories ; ++;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; UNIX: "/path1:/path2" ++; Note (paranoid): ++; - '.' (the default) is not allowed here, applications that rely on it ++; need to be modified ++; - /usr is allowed, but files there should be protected against being ++; overwritten by mounting the filesystem read-only and should be ++; monitored with a system integrity check tool. ++include_path = "/usr/share/php" ++ ++; Windows: "\path1;\path2" ++;include_path = ".;c:\php\includes" ++ ++; The root of the PHP pages, used only if nonempty. ++; if PHP was not compiled with FORCE_REDIRECT, you SHOULD set doc_root ++; if you are running php as a CGI under any web server (other than IIS) ++; see documentation for security issues. The alternate is to use the ++; cgi.force_redirect configuration below ++doc_root = ++ ++; The directory under which PHP opens the script using /~username used only ++; if nonempty. ++user_dir = ++ ++; Directory in which the loadable extensions (modules) reside. ++; extension_dir = "./" ++ ++; Whether or not to enable the dl() function. The dl() function does NOT work ++; properly in multithreaded servers, such as IIS or Zeus, and is automatically ++; disabled on them. ++; ++; NOTE: this is a potential security hole and is disabled by default in debian ++enable_dl = Off ++ ++; cgi.force_redirect is necessary to provide security running PHP as a CGI under ++; most web servers. Left undefined, PHP turns this on by default. You can ++; turn it off here AT YOUR OWN RISK ++; **You CAN safely turn this off for IIS, in fact, you MUST.** ++; cgi.force_redirect = 1 ++ ++; if cgi.nph is enabled it will force cgi to always sent Status: 200 with ++; every request. ++; cgi.nph = 1 ++ ++; if cgi.force_redirect is turned on, and you are not running under Apache or Netscape ++; (iPlanet) web servers, you MAY need to set an environment variable name that PHP ++; will look for to know it is OK to continue execution. Setting this variable MAY ++; cause security issues, KNOW WHAT YOU ARE DOING FIRST. ++; cgi.redirect_status_env = ; ++ ++; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI. PHP's ++; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok ++; what PATH_INFO is. For more information on PATH_INFO, see the cgi specs. Setting ++; this to 1 will cause PHP CGI to fix it's paths to conform to the spec. A setting ++; of zero causes PHP to behave as before. Default is 1. You should fix your scripts ++; to use SCRIPT_FILENAME rather than PATH_TRANSLATED. ++cgi.fix_pathinfo=1 ++ ++; FastCGI under IIS (on WINNT based OS) supports the ability to impersonate ++; security tokens of the calling client. This allows IIS to define the ++; security context that the request runs under. mod_fastcgi under Apache ++; does not currently support this feature (03/17/2002) ++; Set to 1 if running under IIS. Default is zero. ++; fastcgi.impersonate = 1; ++ ++; Disable logging through FastCGI connection ++; fastcgi.logging = 0 ++ ++; cgi.rfc2616_headers configuration option tells PHP what type of headers to ++; use when sending HTTP response code. If it's set 0 PHP sends Status: header that ++; is supported by Apache. When this option is set to 1 PHP will send ++; RFC2616 compliant header. ++; Default is zero. ++;cgi.rfc2616_headers = 0 ++ ++ ++;;;;;;;;;;;;;;;; ++; File Uploads ; ++;;;;;;;;;;;;;;;; ++ ++; Whether to allow HTTP file uploads. ++file_uploads = Off ++ ++; Temporary directory for HTTP uploaded files (will use system default if not ++; specified). ++; ++; Note: If enabled above you have to create this directory and set appropiate ++; permissions. The default (/tmp) is insecure since other users might be able ++; to access upload files or make symlink tricks. ++upload_tmp_dir = /var/lib/php5/uploads ++ ++; Maximum allowed size for uploaded files. ++upload_max_filesize = 2M ++ ++ ++;;;;;;;;;;;;;;;;;; ++; Fopen wrappers ; ++;;;;;;;;;;;;;;;;;; ++ ++; Whether to allow the treatment of URLs (like http:// or ftp://) as files. ++; ++; This is turned off to avoid variable redefinition by remote attacker ++; that attempts to have the server download (and execute) a remote file ++; from a compromised host. This behaviour has been observed in automatic ++; scanning against badly written applications: ++; http://myhost/myapplication.php?include=http://roguesever/rogueapp.php ++allow_url_fopen = Off ++ ++; Whether to allow include/require to open URLs (like http:// or ftp://) as files. ++allow_url_include = Off ++ ++; Define the anonymous ftp password (your email address) ++;from="john@doe.com" ++ ++; Define the User-Agent string ++; user_agent="PHP" ++ ++; Default timeout for socket based streams (seconds) ++default_socket_timeout = 60 ++ ++; If your scripts have to deal with files from Macintosh systems, ++; or you are running on a Mac and need to deal with files from ++; unix or win32 systems, setting this flag will cause PHP to ++; automatically detect the EOL character in those files so that ++; fgets() and file() will work regardless of the source of the file. ++; auto_detect_line_endings = Off ++ ++ ++;;;;;;;;;;;;;;;;;;;;;; ++; Dynamic Extensions ; ++;;;;;;;;;;;;;;;;;;;;;; ++; ++; If you wish to have an extension loaded automatically, use the following ++; syntax: ++; ++; extension=modulename.extension ++; ++; For example, on Windows: ++; ++; extension=msql.dll ++; ++; ... or under UNIX: ++; ++; extension=msql.so ++; ++; Note that it should be the name of the module only; no directory information ++; needs to go here. Specify the location of the extension with the ++; extension_dir directive above. ++ ++ ++;;;;;;;;;;;;;;;;;;; ++; Module Settings ; ++;;;;;;;;;;;;;;;;;;; ++ ++[Date] ++; Defines the default timezone used by the date functions ++;date.timezone = ++ ++;date.default_latitude = 31.7667 ++;date.default_longitude = 35.2333 ++ ++;date.sunrise_zenith = 90.583333 ++;date.sunset_zenith = 90.583333 ++ ++[filter] ++;filter.default = unsafe_raw ++;filter.default_flags = ++ ++[iconv] ++;iconv.input_encoding = ISO-8859-1 ++;iconv.internal_encoding = ISO-8859-1 ++;iconv.output_encoding = ISO-8859-1 ++ ++[sqlite] ++;sqlite.assoc_case = 0 ++ ++[xmlrpc] ++;xmlrpc_error_number = 0 ++;xmlrpc_errors = 0 ++ ++[Pcre] ++;PCRE library backtracking limit. ++;pcre.backtrack_limit=100000 ++ ++;PCRE library recursion limit. ++;Please note that if you set this value to a high number you may consume all ++;the available process stack and eventually crash PHP (due to reaching the ++;stack size limit imposed by the Operating System). ++;pcre.recursion_limit=100000 ++ ++[Syslog] ++; Whether or not to define the various syslog variables (e.g. $LOG_PID, ++; $LOG_CRON, etc.). Turning it off is a good idea performance-wise. In ++; runtime, you can define these variables by calling define_syslog_variables(). ++define_syslog_variables = Off ++ ++[mail function] ++; For Win32 only. ++SMTP = localhost ++smtp_port = 25 ++ ++; For Win32 only. ++;sendmail_from = me@example.com ++ ++; For Unix only. You may supply arguments as well (default: "sendmail -t -i"). ++;sendmail_path = ++ ++; Force the addition of the specified parameters to be passed as extra parameters ++; to the sendmail binary. These parameters will always replace the value of ++; the 5th parameter to mail(), even in safe mode. ++;mail.force_extra_parameters = ++ ++[SQL] ++; This configuration directive is unrelated to safe_mode. ++; If enabled, connections to databases (like mysql_connect() or mysql_pconnect()) ++; will ignore the arguments provided (which include username and password) and ++; will attempt to connect always using default values. These default values ++; are typically host=localhost, user=the script owner,password=empty password. ++; ++; Note (paranoid): This is disabled as it is not actually a security measure, unless ++; you want script to not have users and passwords hardcoded in them. ++sql.safe_mode = Off ++ ++[ODBC] ++;odbc.default_db = Not yet implemented ++;odbc.default_user = Not yet implemented ++;odbc.default_pw = Not yet implemented ++ ++; Allow or prevent persistent links. ++odbc.allow_persistent = On ++ ++; Check that a connection is still valid before reuse. ++odbc.check_persistent = On ++ ++; Maximum number of persistent links. -1 means no limit. ++odbc.max_persistent = -1 ++ ++; Maximum number of links (persistent + non-persistent). -1 means no limit. ++odbc.max_links = -1 ++ ++; Handling of LONG fields. Returns number of bytes to variables. 0 means ++; passthru. ++odbc.defaultlrl = 4096 ++ ++; Handling of binary data. 0 means passthru, 1 return as is, 2 convert to char. ++; See the documentation on odbc_binmode and odbc_longreadlen for an explanation ++; of uodbc.defaultlrl and uodbc.defaultbinmode ++odbc.defaultbinmode = 1 ++ ++[MySQL] ++; Allow or prevent persistent links. ++mysql.allow_persistent = On ++ ++; Maximum number of persistent links. -1 means no limit. ++mysql.max_persistent = -1 ++ ++; Maximum number of links (persistent + non-persistent). -1 means no limit. ++mysql.max_links = -1 ++ ++; Default port number for mysql_connect(). If unset, mysql_connect() will use ++; the $MYSQL_TCP_PORT or the mysql-tcp entry in /etc/services or the ++; compile-time value defined MYSQL_PORT (in that order). Win32 will only look ++; at MYSQL_PORT. ++mysql.default_port = ++ ++; Default socket name for local MySQL connects. If empty, uses the built-in ++; MySQL defaults. ++mysql.default_socket = ++ ++; Default host for mysql_connect() (doesn't apply in safe mode). ++mysql.default_host = ++ ++; Default user for mysql_connect() (doesn't apply in safe mode). ++mysql.default_user = ++ ++; Default password for mysql_connect() (doesn't apply in safe mode). ++; Note that this is generally a *bad* idea to store passwords in this file. ++; *Any* user with PHP access can run 'echo get_cfg_var("mysql.default_password") ++; and reveal this password! And of course, any users with read access to this ++; file will be able to reveal the password as well. ++mysql.default_password = ++ ++; Maximum time (in seconds) for connect timeout. -1 means no limit ++mysql.connect_timeout = 60 ++ ++; Trace mode. When trace_mode is active (=On), warnings for table/index scans and ++; SQL-Errors will be displayed. ++mysql.trace_mode = Off ++ ++[MySQLi] ++ ++; Maximum number of links. -1 means no limit. ++mysqli.max_links = -1 ++ ++; Default port number for mysqli_connect(). If unset, mysqli_connect() will use ++; the $MYSQL_TCP_PORT or the mysql-tcp entry in /etc/services or the ++; compile-time value defined MYSQL_PORT (in that order). Win32 will only look ++; at MYSQL_PORT. ++mysqli.default_port = 3306 ++ ++; Default socket name for local MySQL connects. If empty, uses the built-in ++; MySQL defaults. ++mysqli.default_socket = ++ ++; Default host for mysql_connect() (doesn't apply in safe mode). ++mysqli.default_host = ++ ++; Default user for mysql_connect() (doesn't apply in safe mode). ++mysqli.default_user = ++ ++; Default password for mysqli_connect() (doesn't apply in safe mode). ++; Note that this is generally a *bad* idea to store passwords in this file. ++; *Any* user with PHP access can run 'echo get_cfg_var("mysqli.default_pw") ++; and reveal this password! And of course, any users with read access to this ++; file will be able to reveal the password as well. ++mysqli.default_pw = ++ ++; Allow or prevent reconnect ++mysqli.reconnect = Off ++ ++[mSQL] ++; Allow or prevent persistent links. ++msql.allow_persistent = On ++ ++; Maximum number of persistent links. -1 means no limit. ++msql.max_persistent = -1 ++ ++; Maximum number of links (persistent+non persistent). -1 means no limit. ++msql.max_links = -1 ++ ++[OCI8] ++; enables privileged connections using external credentials (OCI_SYSOPER, OCI_SYSDBA) ++;oci8.privileged_connect = Off ++ ++; Connection: The maximum number of persistent OCI8 connections per ++; process. Using -1 means no limit. ++;oci8.max_persistent = -1 ++ ++; Connection: The maximum number of seconds a process is allowed to ++; maintain an idle persistent connection. Using -1 means idle ++; persistent connections will be maintained forever. ++;oci8.persistent_timeout = -1 ++ ++; Connection: The number of seconds that must pass before issuing a ++; ping during oci_pconnect() to check the connection validity. When ++; set to 0, each oci_pconnect() will cause a ping. Using -1 disables ++; pings completely. ++;oci8.ping_interval = 60 ++ ++; Tuning: This option enables statement caching, and specifies how ++; many statements to cache. Using 0 disables statement caching. ++;oci8.statement_cache_size = 20 ++ ++; Tuning: Enables statement prefetching and sets the default number of ++; rows that will be fetched automatically after statement execution. ++;oci8.default_prefetch = 10 ++ ++; Compatibility. Using On means oci_close() will not close ++; oci_connect() and oci_new_connect() connections. ++;oci8.old_oci_close_semantics = Off ++ ++[PostgresSQL] ++; Allow or prevent persistent links. ++pgsql.allow_persistent = On ++ ++; Detect broken persistent links always with pg_pconnect(). ++; Auto reset feature requires a little overheads. ++pgsql.auto_reset_persistent = Off ++ ++; Maximum number of persistent links. -1 means no limit. ++pgsql.max_persistent = -1 ++ ++; Maximum number of links (persistent+non persistent). -1 means no limit. ++pgsql.max_links = -1 ++ ++; Ignore PostgreSQL backends Notice message or not. ++; Notice message logging require a little overheads. ++pgsql.ignore_notice = 0 ++ ++; Log PostgreSQL backends Noitce message or not. ++; Unless pgsql.ignore_notice=0, module cannot log notice message. ++pgsql.log_notice = 0 ++ ++[Sybase] ++; Allow or prevent persistent links. ++sybase.allow_persistent = On ++ ++; Maximum number of persistent links. -1 means no limit. ++sybase.max_persistent = -1 ++ ++; Maximum number of links (persistent + non-persistent). -1 means no limit. ++sybase.max_links = -1 ++ ++;sybase.interface_file = "/usr/sybase/interfaces" ++ ++; Minimum error severity to display. ++sybase.min_error_severity = 10 ++ ++; Minimum message severity to display. ++sybase.min_message_severity = 10 ++ ++; Compatibility mode with old versions of PHP 3.0. ++; If on, this will cause PHP to automatically assign types to results according ++; to their Sybase type, instead of treating them all as strings. This ++; compatibility mode will probably not stay around forever, so try applying ++; whatever necessary changes to your code, and turn it off. ++sybase.compatability_mode = Off ++ ++[Sybase-CT] ++; Allow or prevent persistent links. ++sybct.allow_persistent = On ++ ++; Maximum number of persistent links. -1 means no limit. ++sybct.max_persistent = -1 ++ ++; Maximum number of links (persistent + non-persistent). -1 means no limit. ++sybct.max_links = -1 ++ ++; Minimum server message severity to display. ++sybct.min_server_severity = 10 ++ ++; Minimum client message severity to display. ++sybct.min_client_severity = 10 ++ ++[bcmath] ++; Number of decimal digits for all bcmath functions. ++bcmath.scale = 0 ++ ++[browscap] ++;browscap = extra/browscap.ini ++ ++[Informix] ++; Default host for ifx_connect() (doesn't apply in safe mode). ++ifx.default_host = ++ ++; Default user for ifx_connect() (doesn't apply in safe mode). ++ifx.default_user = ++ ++; Default password for ifx_connect() (doesn't apply in safe mode). ++ifx.default_password = ++ ++; Allow or prevent persistent links. ++ifx.allow_persistent = On ++ ++; Maximum number of persistent links. -1 means no limit. ++ifx.max_persistent = -1 ++ ++; Maximum number of links (persistent + non-persistent). -1 means no limit. ++ifx.max_links = -1 ++ ++; If on, select statements return the contents of a text blob instead of its id. ++ifx.textasvarchar = 0 ++ ++; If on, select statements return the contents of a byte blob instead of its id. ++ifx.byteasvarchar = 0 ++ ++; Trailing blanks are stripped from fixed-length char columns. May help the ++; life of Informix SE users. ++ifx.charasvarchar = 0 ++ ++; If on, the contents of text and byte blobs are dumped to a file instead of ++; keeping them in memory. ++ifx.blobinfile = 0 ++ ++; NULL's are returned as empty strings, unless this is set to 1. In that case, ++; NULL's are returned as string 'NULL'. ++ifx.nullformat = 0 ++ ++[Session] ++; Handler used to store/retrieve data. ++session.save_handler = files ++ ++; Argument passed to save_handler. In the case of files, this is the path ++; where data files are stored. Note: Windows users have to change this ++; variable in order to use PHP's session functions. ++; ++; As of PHP 4.0.1, you can define the path as: ++; ++; session.save_path = "N;/path" ++; ++; where N is an integer. Instead of storing all the session files in ++; /path, what this will do is use subdirectories N-levels deep, and ++; store the session data in those directories. This is useful if you ++; or your OS have problems with lots of files in one directory, and is ++; a more efficient layout for servers that handle lots of sessions. ++; ++; NOTE 1: PHP will not create this directory structure automatically. ++; You can use the script in the ext/session dir for that purpose. ++; NOTE 2: See the section on garbage collection below if you choose to ++; use subdirectories for session storage ++; ++; The file storage module creates files using mode 600 by default. ++; You can change that by using ++; ++; session.save_path = "N;MODE;/path" ++; ++; where MODE is the octal representation of the mode. Note that this ++; does not overwrite the process's umask. ++session.save_path = /var/lib/php5 ++ ++; Substring to check each HTTP Referer for. If the Referer was sent by the ++; client and the substring was not found, the embedded session id will be marked ++; as invalid. Defaults to the empty string. ++; Note (paranoid): to prevent some XSS attacks should be defined to the server's URI ++; session.referer_check = ++ ++ ++; Path to an external resource (file) which will be used as an additional ++; entropy source in the session id creation process. ++; Note (paranoid): /dev/urandom is not fully random but if /dev/random is used ++; the entropy pool could be exhaused by constantly asking for session ids and ++; would compromise other applications relying on randomness ++session.entropy_file = "/dev/urandom" ++ ++; Number of bytes which will be read from the file specified above. ++; Defaults to 0 (disabled). ++session.entropy_length = 6 ++ ++; Whether to use cookies. ++session.use_cookies = 1 ++ ++; If this option is enabled cookies are only sent through secure (SSL) ++; connections and, consequently, are more difficult to intercept. ++; (disabled by default) ++session.cookie_secure = 1 ++ ++; This option enables administrators to make their users invulnerable to ++; attacks which involve passing session ids in URLs; defaults to 1 (since PHP 6.0). ++session.use_only_cookies = 1 ++ ++; Name of the session (used as cookie name). ++session.name = PHPSESSID ++ ++; Initialize session on request startup. ++session.auto_start = 0 ++ ++; Lifetime in seconds of cookie or, if 0, until browser is restarted. ++session.cookie_lifetime = 0 ++ ++; The path for which the cookie is valid. ++; Note (paranoid): Applications should restrict the path where the cookie ++; is valid through use of session_set_cookie_params(). ++session.cookie_path = / ++ ++; The domain for which the cookie is valid. ++; Note (paranoid): Make sure you configure this for your site ++session.cookie_domain = ++ ++; Whether or not to add the httpOnly flag to the cookie, which makes it inaccessible to browser scripting languages such as JavaScript. ++session.cookie_httponly = 1 ++ ++; Handler used to serialize data. php is the standard serializer of PHP. ++session.serialize_handler = php ++ ++; Define the probability that the 'garbage collection' process is started ++; on every session initialization. ++; The probability is calculated by using gc_probability/gc_divisor, ++; e.g. 1/100 means there is a 1% chance that the GC process starts ++; on each request. ++ ++; This is disabled in the Debian packages, due to the strict permissions ++; on /var/lib/php5. Instead of setting this here, see the cronjob at ++; /etc/cron.d/php5, which uses the session.gc_maxlifetime setting below ++;session.gc_probability = 0 ++session.gc_divisor = 100 ++ ++; After this number of seconds, stored data will be seen as 'garbage' and ++; cleaned up by the garbage collection process. ++session.gc_maxlifetime = 1440 ++ ++; NOTE: If you are using the subdirectory option for storing session files ++; (see session.save_path above), then garbage collection does *not* ++; happen automatically. You will need to do your own garbage ++; collection through a shell script, cron entry, or some other method. ++; For example, the following script would is the equivalent of ++; setting session.gc_maxlifetime to 1440 (1440 seconds = 24 minutes): ++; cd /path/to/sessions; find -cmin +24 | xargs rm ++ ++; PHP 4.2 and less have an undocumented feature/bug that allows you to ++; to initialize a session variable in the global scope, albeit register_globals ++; is disabled. PHP 4.3 and later will warn you, if this feature is used. ++; You can disable the feature and the warning separately. At this time, ++; the warning is only displayed, if bug_compat_42 is enabled. ++ ++session.bug_compat_42 = 0 ++session.bug_compat_warn = 1 ++ ++; Check HTTP Referer to invalidate externally stored URLs containing ids. ++; HTTP_REFERER has to contain this substring for the session to be ++; considered as valid. ++session.referer_check = ++ ++; How many bytes to read from the file. ++session.entropy_length = 0 ++ ++; Specified here to create the session id. ++session.entropy_file = ++ ++;session.entropy_length = 16 ++ ++;session.entropy_file = /dev/urandom ++ ++; Set to {nocache,private,public,} to determine HTTP caching aspects ++; or leave this empty to avoid sending anti-caching headers. ++session.cache_limiter = nocache ++ ++; Document expires after n minutes. ++session.cache_expire = 180 ++ ++; trans sid support is disabled by default. ++; Use of trans sid may risk your users security. ++; Use this option with caution. ++; - User may send URL contains active session ID ++; to other person via. email/irc/etc. ++; - URL that contains active session ID may be stored ++; in publically accessible computer. ++; - User may access your site with the same session ID ++; always using URL stored in browser's history or bookmarks. ++session.use_trans_sid = 0 ++ ++; Select a hash function ++; 0: MD5 (128 bits) ++; 1: SHA-1 (160 bits) ++; Note (paranoic): Set to SHA-1 since there are known attacks against MD5 ++; although the algorithm is not yet broken) ++session.hash_function = 1 ++ ++; Define how many bits are stored in each character when converting ++; the binary hash data to something readable. ++; ++; 4 bits: 0-9, a-f ++; 5 bits: 0-9, a-v ++; 6 bits: 0-9, a-z, A-Z, "-", "," ++session.hash_bits_per_character = 4 ++ ++; The URL rewriter will look for URLs in a defined set of HTML tags. ++; form/fieldset are special; if you include them here, the rewriter will ++; add a hidden field with the info which is otherwise appended ++; to URLs. If you want XHTML conformity, remove the form entry. ++; Note that all valid entries require a "=", even if no value follows. ++url_rewriter.tags = "a=href,area=href,frame=src,input=src,form=fakeentry,fieldset=" ++ ++[MSSQL] ++; Allow or prevent persistent links. ++mssql.allow_persistent = On ++ ++; Maximum number of persistent links. -1 means no limit. ++mssql.max_persistent = -1 ++ ++; Maximum number of links (persistent+non persistent). -1 means no limit. ++mssql.max_links = -1 ++ ++; Minimum error severity to display. ++mssql.min_error_severity = 10 ++ ++; Minimum message severity to display. ++mssql.min_message_severity = 10 ++ ++; Compatibility mode with old versions of PHP 3.0. ++mssql.compatability_mode = Off ++ ++; Connect timeout ++;mssql.connect_timeout = 5 ++ ++; Query timeout ++;mssql.timeout = 60 ++ ++; Valid range 0 - 2147483647. Default = 4096. ++;mssql.textlimit = 4096 ++ ++; Valid range 0 - 2147483647. Default = 4096. ++;mssql.textsize = 4096 ++ ++; Limits the number of records in each batch. 0 = all records in one batch. ++;mssql.batchsize = 0 ++ ++; Specify how datetime and datetim4 columns are returned ++; On => Returns data converted to SQL server settings ++; Off => Returns values as YYYY-MM-DD hh:mm:ss ++;mssql.datetimeconvert = On ++ ++; Use NT authentication when connecting to the server ++mssql.secure_connection = On ++ ++; Specify max number of processes. -1 = library default ++; msdlib defaults to 25 ++; FreeTDS defaults to 4096 ++;mssql.max_procs = -1 ++ ++; Specify client character set. ++; If empty or not set the client charset from freetds.comf is used ++; This is only used when compiled with FreeTDS ++;mssql.charset = "ISO-8859-1" ++ ++[Assertion] ++; Assert(expr); active by default. ++;assert.active = On ++ ++; Issue a PHP warning for each failed assertion. ++;assert.warning = On ++ ++; Don't bail out by default. ++;assert.bail = Off ++ ++; User-function to be called if an assertion fails. ++;assert.callback = 0 ++ ++; Eval the expression with current error_reporting(). Set to true if you want ++; error_reporting(0) around the eval(). ++;assert.quiet_eval = 0 ++ ++[COM] ++; path to a file containing GUIDs, IIDs or filenames of files with TypeLibs ++;com.typelib_file = ++; allow Distributed-COM calls ++;com.allow_dcom = true ++; autoregister constants of a components typlib on com_load() ++;com.autoregister_typelib = true ++; register constants casesensitive ++;com.autoregister_casesensitive = false ++; show warnings on duplicate constant registrations ++;com.autoregister_verbose = true ++ ++[mbstring] ++; language for internal character representation. ++;mbstring.language = Japanese ++ ++; internal/script encoding. ++; Some encoding cannot work as internal encoding. ++; (e.g. SJIS, BIG5, ISO-2022-*) ++;mbstring.internal_encoding = EUC-JP ++ ++; http input encoding. ++;mbstring.http_input = auto ++ ++; http output encoding. mb_output_handler must be ++; registered as output buffer to function ++;mbstring.http_output = SJIS ++ ++; enable automatic encoding translation according to ++; mbstring.internal_encoding setting. Input chars are ++; converted to internal encoding by setting this to On. ++; Note: Do _not_ use automatic encoding translation for ++; portable libs/applications. ++;mbstring.encoding_translation = Off ++ ++; automatic encoding detection order. ++; auto means ++;mbstring.detect_order = auto ++ ++; substitute_character used when character cannot be converted ++; one from another ++;mbstring.substitute_character = none; ++ ++; overload(replace) single byte functions by mbstring functions. ++; mail(), ereg(), etc are overloaded by mb_send_mail(), mb_ereg(), ++; etc. Possible values are 0,1,2,4 or combination of them. ++; For example, 7 for overload everything. ++; 0: No overload ++; 1: Overload mail() function ++; 2: Overload str*() functions ++; 4: Overload ereg*() functions ++;mbstring.func_overload = 0 ++ ++[FrontBase] ++;fbsql.allow_persistent = On ++;fbsql.autocommit = On ++;fbsql.show_timestamp_decimals = Off ++;fbsql.default_database = ++;fbsql.default_database_password = ++;fbsql.default_host = ++;fbsql.default_password = ++;fbsql.default_user = "_SYSTEM" ++;fbsql.generate_warnings = Off ++;fbsql.max_connections = 128 ++;fbsql.max_links = 128 ++;fbsql.max_persistent = -1 ++;fbsql.max_results = 128 ++ ++[gd] ++; Tell the jpeg decode to libjpeg warnings and try to create ++; a gd image. The warning will then be displayed as notices ++; disabled by default ++;gd.jpeg_ignore_warning = 0 ++ ++[exif] ++; Exif UNICODE user comments are handled as UCS-2BE/UCS-2LE and JIS as JIS. ++; With mbstring support this will automatically be converted into the encoding ++; given by corresponding encode setting. When empty mbstring.internal_encoding ++; is used. For the decode settings you can distinguish between motorola and ++; intel byte order. A decode setting cannot be empty. ++;exif.encode_unicode = ISO-8859-15 ++;exif.decode_unicode_motorola = UCS-2BE ++;exif.decode_unicode_intel = UCS-2LE ++;exif.encode_jis = ++;exif.decode_jis_motorola = JIS ++;exif.decode_jis_intel = JIS ++ ++[Tidy] ++; The path to a default tidy configuration file to use when using tidy ++;tidy.default_config = /usr/local/lib/php/default.tcfg ++ ++; Should tidy clean and repair output automatically? ++; WARNING: Do not use this option if you are generating non-html content ++; such as dynamic images ++tidy.clean_output = Off ++ ++[soap] ++; Enables or disables WSDL caching feature. ++soap.wsdl_cache_enabled=1 ++; Sets the directory name where SOAP extension will put cache files. ++soap.wsdl_cache_dir="/var/lib/php5/soap-cache" ++; (time to live) Sets the number of second while cached file will be used ++; instead of original one. ++soap.wsdl_cache_ttl=86400 ++ ++; Local Variables: ++; tab-width: 4 ++; End: --- php5-5.2.10.dfsg.1.orig/debian/patches/php5-CVE-2010-4697.patch +++ php5-5.2.10.dfsg.1/debian/patches/php5-CVE-2010-4697.patch @@ -0,0 +1,93 @@ +Subject: Fixed bug #52879 (Objects unreferenced in __get, __set, __isset or __unset can be freed too early). +Author: mail_ben_schmidt at yahoo dot com dot au +Origin: http://svn.php.net/viewvc?view=revision&revision=303913 +Bug: http://bugs.php.net/52879 + +CVE-2010-4697 + +Patch is modified from upstream commit to remove edits to the NEWS file, +to reduce conflicts when applying patches and backported to apply to +earlier releases of php. + +Index: Zend/zend_object_handlers.c +=================================================================== +--- Zend/zend_object_handlers.c (revision 303912) ++++ Zend/zend_object_handlers.c (revision 303913) +@@ -329,6 +329,9 @@ + !guard->in_get) { + /* have getter - try with it! */ + ZVAL_ADDREF(object); ++ if (PZVAL_IS_REF(object)) { ++ SEPARATE_ZVAL(&object); ++ } + guard->in_get = 1; /* prevent circular getting */ + rv = zend_std_call_getter(object, member TSRMLS_CC); + guard->in_get = 0; +@@ -418,22 +421,22 @@ + } + } + } else { +- int setter_done = 0; + zend_guard *guard; + + if (zobj->ce->__set && + zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS && + !guard->in_set) { + ZVAL_ADDREF(object); ++ if (PZVAL_IS_REF(object)) { ++ SEPARATE_ZVAL(&object); ++ } + guard->in_set = 1; /* prevent circular setting */ + if (zend_std_call_setter(object, member, value TSRMLS_CC) != SUCCESS) { + /* for now, just ignore it - __set should take care of warnings, etc. */ + } +- setter_done = 1; + guard->in_set = 0; + zval_ptr_dtor(&object); +- } +- if (!setter_done && property_info) { ++ } else if (property_info) { + zval **foo; + + /* if we assign referenced variable, we should separate it */ +@@ -611,6 +614,9 @@ + !guard->in_unset) { + /* have unseter - try with it! */ + ZVAL_ADDREF(object); ++ if (PZVAL_IS_REF(object)) { ++ SEPARATE_ZVAL(&object); ++ } + guard->in_unset = 1; /* prevent circular unsetting */ + zend_std_call_unsetter(object, member TSRMLS_CC); + guard->in_unset = 0; +@@ -1042,6 +1048,9 @@ + + /* have issetter - try with it! */ + ZVAL_ADDREF(object); ++ if (PZVAL_IS_REF(object)) { ++ SEPARATE_ZVAL(&object); ++ } + guard->in_isset = 1; /* prevent circular getting */ + rv = zend_std_call_issetter(object, member TSRMLS_CC); + if (rv) { +Index: Zend/tests/bug52879.phpt +=================================================================== +--- Zend/tests/bug52879.phpt (revision 0) ++++ Zend/tests/bug52879.phpt (revision 303913) +@@ -0,0 +1,16 @@ ++--TEST-- ++Bug #52879 (Objects unreferenced in __get, __set, __isset or __unset can be freed too early) ++--FILE-- ++myRef = $value; ++ } ++} ++$myGlobal=new MyClass($myGlobal); ++$myGlobal->myRef=&$myGlobal; ++$myGlobal->myNonExistentProperty="ok\n"; ++echo $myGlobal; ++--EXPECT-- ++ok --- php5-5.2.10.dfsg.1.orig/debian/patches/php5-CVE-2011-1469.patch +++ php5-5.2.10.dfsg.1/debian/patches/php5-CVE-2011-1469.patch @@ -0,0 +1,123 @@ +Subject: Fixed bug #54092 (Segmentation fault when using HTTP proxy with the FTP wrapper). +Origin: http://svn.php.net/viewvc?view=revision&revision=308734 + +#php_stream->wrapperdata should hold an array zval (like its zval* type +#indicates...), it's not a place where the wrapper can drop an arbitrary +#pointer. For that, .wrapperthis should be used. +#Also, since the ftp dir wrapper defines its own stream type, it's more +#appropriate to use .abstract to store the stream instance specific data. + +CVE-2011-1469 + +Patch differs from upstream commit in that it drops the added NEWS file +entry to reduce patch conflicts, and adjusted for earlier versions of +php. + +Index: ext/standard/ftp_fopen_wrapper.c +=================================================================== +--- ext/standard/ftp_fopen_wrapper.c (revision 308733) ++++ ext/standard/ftp_fopen_wrapper.c (revision 308734) +@@ -72,6 +72,12 @@ + #define FTPS_ENCRYPT_DATA 1 + #define GET_FTP_RESULT(stream) get_ftp_result((stream), tmp_line, sizeof(tmp_line) TSRMLS_CC) + ++typedef struct _php_ftp_dirstream_data { ++ php_stream *datastream; ++ php_stream *controlstream; ++ php_stream *dirstream; ++} php_ftp_dirstream_data; ++ + /* {{{ get_ftp_result + */ + static inline int get_ftp_result(php_stream *stream, char *buffer, size_t buffer_size TSRMLS_DC) +@@ -97,12 +103,12 @@ + */ + static int php_stream_ftp_stream_close(php_stream_wrapper *wrapper, php_stream *stream TSRMLS_DC) + { +- php_stream *controlstream = (php_stream *)stream->wrapperdata; ++ php_stream *controlstream = stream->wrapperthis; + + if (controlstream) { + php_stream_write_string(controlstream, "QUIT\r\n"); + php_stream_close(controlstream); +- stream->wrapperdata = NULL; ++ stream->wrapperthis = NULL; + } + return 0; + } +@@ -584,7 +584,7 @@ + } + + /* remember control stream */ +- datastream->wrapperdata = (zval *)stream; ++ datastream->wrapperthis = stream; + + php_url_free(resource); + return datastream; +@@ -608,11 +608,13 @@ + static size_t php_ftp_dirstream_read(php_stream *stream, char *buf, size_t count TSRMLS_DC) + { + php_stream_dirent *ent = (php_stream_dirent *)buf; +- php_stream *innerstream = (php_stream *)stream->abstract; ++ php_stream *innerstream; + size_t tmp_len; + char *basename; + size_t basename_len; + ++ innerstream = ((php_ftp_dirstream_data *)stream->abstract)->datastream; ++ + if (count != sizeof(php_stream_dirent)) { + return 0; + } +@@ -656,13 +658,18 @@ + */ + static int php_ftp_dirstream_close(php_stream *stream, int close_handle TSRMLS_DC) + { +- php_stream *innerstream = (php_stream *)stream->abstract; ++ php_ftp_dirstream_data *data = stream->abstract; + +- if (innerstream->wrapperdata) { +- php_stream_close((php_stream *)innerstream->wrapperdata); +- innerstream->wrapperdata = NULL; ++ /* close control connection */ ++ if (data->controlstream) { ++ php_stream_close(data->controlstream); ++ data->controlstream = NULL; + } +- php_stream_close((php_stream *)stream->abstract); ++ /* close data connection */ ++ php_stream_close(data->datastream); ++ data->datastream = NULL; ++ ++ efree(data); + stream->abstract = NULL; + + return 0; +@@ -688,6 +695,7 @@ + php_stream * php_stream_ftp_opendir(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context STREAMS_DC TSRMLS_DC) + { + php_stream *stream, *reuseid, *datastream = NULL; ++ php_ftp_dirstream_data *dirsdata; + php_url *resource = NULL; + int result = 0, use_ssl, use_ssl_on_data = 0; + char *hoststart = NULL, tmp_line[512]; +@@ -747,12 +755,15 @@ + goto opendir_errexit; + } + +- /* remember control stream */ +- datastream->wrapperdata = (zval *)stream; +- + php_url_free(resource); +- return php_stream_alloc(&php_ftp_dirstream_ops, datastream, 0, mode); + ++ dirsdata = emalloc(sizeof *dirsdata); ++ dirsdata->datastream = datastream; ++ dirsdata->controlstream = stream; ++ dirsdata->dirstream = php_stream_alloc(&php_ftp_dirstream_ops, dirsdata, 0, mode); ++ ++ return dirsdata->dirstream; ++ + opendir_errexit: + if (resource) { + php_url_free(resource); --- php5-5.2.10.dfsg.1.orig/debian/patches/CVE-2009-3557.patch +++ php5-5.2.10.dfsg.1/debian/patches/CVE-2009-3557.patch @@ -0,0 +1,17 @@ +Description: fix safe_mode bypass via tempam function +upstream, Origin: http://svn.php.net/viewvc?view=revision&revision=288945 + +diff -Nur php5-5.2.10.dfsg.1/ext/standard/file.c php5-5.2.10.dfsg.1.new/ext/standard/file.c +--- php5-5.2.10.dfsg.1/ext/standard/file.c 2009-11-24 15:17:24.000000000 -0500 ++++ php5-5.2.10.dfsg.1.new/ext/standard/file.c 2009-11-24 15:17:29.000000000 -0500 +@@ -838,6 +838,10 @@ + convert_to_string_ex(arg1); + convert_to_string_ex(arg2); + ++ if (PG(safe_mode) &&(!php_checkuid(Z_STRVAL_PP(arg1), NULL, CHECKUID_ALLOW_ONLY_DIR))) { ++ RETURN_FALSE; ++ } ++ + if (php_check_open_basedir(Z_STRVAL_PP(arg1) TSRMLS_CC)) { + RETURN_FALSE; + } --- php5-5.2.10.dfsg.1.orig/debian/patches/php5-CVE-2010-3436.patch +++ php5-5.2.10.dfsg.1/debian/patches/php5-CVE-2010-3436.patch @@ -0,0 +1,29 @@ +Subject: Fixed possible flaw in open_basedir allowing basedir bypass +Origin: http://svn.php.net/viewvc?view=revision&revision=303824 + +CVE-2010-3436 + +--- + main/fopen_wrappers.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +Index: b/main/fopen_wrappers.c +=================================================================== +--- a/main/fopen_wrappers.c ++++ b/main/fopen_wrappers.c +@@ -239,8 +239,13 @@ PHPAPI int php_check_specific_open_based + #else + if (strncmp(resolved_basedir, resolved_name, resolved_basedir_len) == 0) { + #endif +- /* File is in the right directory */ +- return 0; ++ if (resolved_name_len > resolved_basedir_len && ++ resolved_name[resolved_basedir_len] != PHP_DIR_SEPARATOR) { ++ return -1; ++ } else { ++ /* File is in the right directory */ ++ return 0; ++ } + } else { + /* /openbasedir/ and /openbasedir are the same directory */ + if (resolved_basedir_len == (resolved_name_len + 1) && resolved_basedir[resolved_basedir_len - 1] == PHP_DIR_SEPARATOR) { --- php5-5.2.10.dfsg.1.orig/debian/patches/php5-CVE-2010-4645.patch +++ php5-5.2.10.dfsg.1/debian/patches/php5-CVE-2010-4645.patch @@ -0,0 +1,25 @@ +Subject: Fixed Bug #53632 (infinite loop with x87 fpu). (Scott, Rasmus) +Origin: http://svn.php.net/viewvc?view=revision&revision=307095 +Bug: http://bugs.php.net/53632 +Bug-Ubuntu: https://bugs.launchpad.net/bugs/697181 + +[Ubuntu note: removed NEWS file change from commit diff to ease + application of patch. - sbeattie] + +--- + Zend/zend_strtod.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: b/Zend/zend_strtod.c +=================================================================== +--- a/Zend/zend_strtod.c ++++ b/Zend/zend_strtod.c +@@ -2045,7 +2045,7 @@ ZEND_API double zend_strtod (CONST char + int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign, + e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign; + CONST char *s, *s0, *s1; +- double aadj, aadj1, adj; ++ volatile double aadj, aadj1, adj; + volatile _double rv, rv0; + Long L; + ULong y, z; --- php5-5.2.10.dfsg.1.orig/debian/patches/use-specific-libdb-version.patch +++ php5-5.2.10.dfsg.1/debian/patches/use-specific-libdb-version.patch @@ -0,0 +1,13 @@ +Index: php5-5.2.4/ext/dba/config.m4 +=================================================================== +--- php5-5.2.4.orig/ext/dba/config.m4 2007-12-19 04:18:56.000000000 +0100 ++++ php5-5.2.4/ext/dba/config.m4 2007-12-19 04:19:03.000000000 +0100 +@@ -301,7 +301,7 @@ + break + fi + done +- PHP_DBA_DB_CHECK(4, db db-4.6 db-4.5 db-4.4 db-4.3 db-4.2 db-4.1 db-4.0 db-4 db4, [(void)db_create((DB**)0, (DB_ENV*)0, 0)]) ++ PHP_DBA_DB_CHECK(4, db-4.6 db-4.5 db-4.4 db-4.3 db-4.2 db-4.1 db-4.0 db-4 db4 db, [(void)db_create((DB**)0, (DB_ENV*)0, 0)]) + fi + PHP_DBA_STD_RESULT(db4,Berkeley DB4) + --- php5-5.2.10.dfsg.1.orig/debian/patches/019-z_off_t_as_long.patch +++ php5-5.2.10.dfsg.1/debian/patches/019-z_off_t_as_long.patch @@ -0,0 +1,1532 @@ +--- /dev/null ++++ php/ext/zlib/zconf.h +@@ -0,0 +1,326 @@ ++/* zconf.h -- configuration of the zlib compression library ++ * Copyright (C) 1995-2003 Jean-loup Gailly. ++ * For conditions of distribution and use, see copyright notice in zlib.h ++ */ ++ ++/* @(#) $Id: 019-z_off_t_as_long.patch.disabled,v 1.3 2004/08/23 07:48:56 adconrad Exp $ */ ++ ++#ifndef ZCONF_H ++#define ZCONF_H ++ ++#warning Including local zconf.h instead of system zconf.h ++ ++/* ++ * If you *really* need a unique prefix for all types and library functions, ++ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. ++ */ ++#ifdef Z_PREFIX ++# define deflateInit_ z_deflateInit_ ++# define deflate z_deflate ++# define deflateEnd z_deflateEnd ++# define inflateInit_ z_inflateInit_ ++# define inflate z_inflate ++# define inflateEnd z_inflateEnd ++# define deflateInit2_ z_deflateInit2_ ++# define deflateSetDictionary z_deflateSetDictionary ++# define deflateCopy z_deflateCopy ++# define deflateReset z_deflateReset ++# define deflatePrime z_deflatePrime ++# define deflateParams z_deflateParams ++# define deflateBound z_deflateBound ++# define inflateInit2_ z_inflateInit2_ ++# define inflateSetDictionary z_inflateSetDictionary ++# define inflateSync z_inflateSync ++# define inflateSyncPoint z_inflateSyncPoint ++# define inflateCopy z_inflateCopy ++# define inflateReset z_inflateReset ++# define compress z_compress ++# define compress2 z_compress2 ++# define compressBound z_compressBound ++# define uncompress z_uncompress ++# define adler32 z_adler32 ++# define crc32 z_crc32 ++# define get_crc_table z_get_crc_table ++ ++# define Byte z_Byte ++# define uInt z_uInt ++# define uLong z_uLong ++# define Bytef z_Bytef ++# define charf z_charf ++# define intf z_intf ++# define uIntf z_uIntf ++# define uLongf z_uLongf ++# define voidpf z_voidpf ++# define voidp z_voidp ++#endif ++ ++#if defined(__MSDOS__) && !defined(MSDOS) ++# define MSDOS ++#endif ++#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) ++# define OS2 ++#endif ++#if defined(_WINDOWS) && !defined(WINDOWS) ++# define WINDOWS ++#endif ++#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) ++# define WIN32 ++#endif ++#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) ++# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) ++# ifndef SYS16BIT ++# define SYS16BIT ++# endif ++# endif ++#endif ++ ++/* ++ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more ++ * than 64k bytes at a time (needed on systems with 16-bit int). ++ */ ++#ifdef SYS16BIT ++# define MAXSEG_64K ++#endif ++#ifdef MSDOS ++# define UNALIGNED_OK ++#endif ++ ++#ifdef __STDC_VERSION__ ++# ifndef STDC ++# define STDC ++# endif ++# if __STDC_VERSION__ >= 199901L ++# ifndef STDC99 ++# define STDC99 ++# endif ++# endif ++#endif ++#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) ++# define STDC ++#endif ++#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) ++# define STDC ++#endif ++#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) ++# define STDC ++#endif ++#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) ++# define STDC ++#endif ++ ++#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ ++# define STDC ++#endif ++ ++#ifndef STDC ++# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ ++# define const /* note: need a more gentle solution here */ ++# endif ++#endif ++ ++/* Some Mac compilers merge all .h files incorrectly: */ ++#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) ++# define NO_DUMMY_DECL ++#endif ++ ++/* Maximum value for memLevel in deflateInit2 */ ++#ifndef MAX_MEM_LEVEL ++# ifdef MAXSEG_64K ++# define MAX_MEM_LEVEL 8 ++# else ++# define MAX_MEM_LEVEL 9 ++# endif ++#endif ++ ++/* Maximum value for windowBits in deflateInit2 and inflateInit2. ++ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files ++ * created by gzip. (Files created by minigzip can still be extracted by ++ * gzip.) ++ */ ++#ifndef MAX_WBITS ++# define MAX_WBITS 15 /* 32K LZ77 window */ ++#endif ++ ++/* The memory requirements for deflate are (in bytes): ++ (1 << (windowBits+2)) + (1 << (memLevel+9)) ++ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) ++ plus a few kilobytes for small objects. For example, if you want to reduce ++ the default memory requirements from 256K to 128K, compile with ++ make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" ++ Of course this will generally degrade compression (there's no free lunch). ++ ++ The memory requirements for inflate are (in bytes) 1 << windowBits ++ that is, 32K for windowBits=15 (default value) plus a few kilobytes ++ for small objects. ++*/ ++ ++ /* Type declarations */ ++ ++#ifndef OF /* function prototypes */ ++# ifdef STDC ++# define OF(args) args ++# else ++# define OF(args) () ++# endif ++#endif ++ ++/* The following definitions for FAR are needed only for MSDOS mixed ++ * model programming (small or medium model with some far allocations). ++ * This was tested only with MSC; for other MSDOS compilers you may have ++ * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, ++ * just define FAR to be empty. ++ */ ++#ifdef SYS16BIT ++# if defined(M_I86SM) || defined(M_I86MM) ++ /* MSC small or medium model */ ++# define SMALL_MEDIUM ++# ifdef _MSC_VER ++# define FAR _far ++# else ++# define FAR far ++# endif ++# endif ++# if (defined(__SMALL__) || defined(__MEDIUM__)) ++ /* Turbo C small or medium model */ ++# define SMALL_MEDIUM ++# ifdef __BORLANDC__ ++# define FAR _far ++# else ++# define FAR far ++# endif ++# endif ++#endif ++ ++#if defined(WINDOWS) || defined(WIN32) ++ /* If building or using zlib as a DLL, define ZLIB_DLL. ++ * This is not mandatory, but it offers a little performance increase. ++ */ ++# ifdef ZLIB_DLL ++# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) ++# ifdef ZLIB_INTERNAL ++# define ZEXTERN extern __declspec(dllexport) ++# else ++# define ZEXTERN extern __declspec(dllimport) ++# endif ++# endif ++# endif /* ZLIB_DLL */ ++ /* If building or using zlib with the WINAPI/WINAPIV calling convention, ++ * define ZLIB_WINAPI. ++ * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. ++ */ ++# ifdef ZLIB_WINAPI ++# ifdef FAR ++# undef FAR ++# endif ++# include ++ /* No need for _export, use ZLIB.DEF instead. */ ++ /* For complete Windows compatibility, use WINAPI, not __stdcall. */ ++# define ZEXPORT WINAPI ++# ifdef WIN32 ++# define ZEXPORTVA WINAPIV ++# else ++# define ZEXPORTVA FAR CDECL ++# endif ++# endif ++#endif ++ ++#if defined (__BEOS__) ++# ifdef ZLIB_DLL ++# ifdef ZLIB_INTERNAL ++# define ZEXPORT __declspec(dllexport) ++# define ZEXPORTVA __declspec(dllexport) ++# else ++# define ZEXPORT __declspec(dllimport) ++# define ZEXPORTVA __declspec(dllimport) ++# endif ++# endif ++#endif ++ ++#ifndef ZEXTERN ++# define ZEXTERN extern ++#endif ++#ifndef ZEXPORT ++# define ZEXPORT ++#endif ++#ifndef ZEXPORTVA ++# define ZEXPORTVA ++#endif ++ ++#ifndef FAR ++# define FAR ++#endif ++ ++#if !defined(__MACTYPES__) ++typedef unsigned char Byte; /* 8 bits */ ++#endif ++typedef unsigned int uInt; /* 16 bits or more */ ++typedef unsigned long uLong; /* 32 bits or more */ ++ ++#ifdef SMALL_MEDIUM ++ /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ ++# define Bytef Byte FAR ++#else ++ typedef Byte FAR Bytef; ++#endif ++typedef char FAR charf; ++typedef int FAR intf; ++typedef uInt FAR uIntf; ++typedef uLong FAR uLongf; ++ ++#ifdef STDC ++ typedef void const *voidpc; ++ typedef void FAR *voidpf; ++ typedef void *voidp; ++#else ++ typedef Byte const *voidpc; ++ typedef Byte FAR *voidpf; ++ typedef Byte *voidp; ++#endif ++ ++#if 1 /* HAVE_UNISTD_H -- this line is updated by ./configure */ ++# include /* for off_t */ ++# include /* for SEEK_* and off_t */ ++# ifdef VMS ++# include /* for off_t */ ++# endif ++/* # define z_off_t off_t */ ++#endif ++#ifndef SEEK_SET ++# define SEEK_SET 0 /* Seek from beginning of file. */ ++# define SEEK_CUR 1 /* Seek from current position. */ ++# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ ++#endif ++#ifndef z_off_t ++# warning Defining z_off_t as 'long' rather than 'off_t' ++# define z_off_t long ++#endif ++ ++#if defined(__OS400__) ++#define NO_vsnprintf ++#endif ++ ++#if defined(__MVS__) ++# define NO_vsnprintf ++# ifdef FAR ++# undef FAR ++# endif ++#endif ++ ++/* MVS linker does not support external names larger than 8 bytes */ ++#if defined(__MVS__) ++# pragma map(deflateInit_,"DEIN") ++# pragma map(deflateInit2_,"DEIN2") ++# pragma map(deflateEnd,"DEEND") ++# pragma map(deflateBound,"DEBND") ++# pragma map(inflateInit_,"ININ") ++# pragma map(inflateInit2_,"ININ2") ++# pragma map(inflateEnd,"INEND") ++# pragma map(inflateSync,"INSY") ++# pragma map(inflateSetDictionary,"INSEDI") ++# pragma map(compressBound,"CMBND") ++# pragma map(inflate_table,"INTABL") ++# pragma map(inflate_fast,"INFA") ++# pragma map(inflate_copyright,"INCOPY") ++#endif ++ ++#endif /* ZCONF_H */ +--- /dev/null ++++ php/ext/zlib/zlib.h +@@ -0,0 +1,1200 @@ ++/* zlib.h -- interface of the 'zlib' general purpose compression library ++ version 1.2.1.1, January 9th, 2004 ++ ++ Copyright (C) 1995-2004 Jean-loup Gailly and Mark Adler ++ ++ This software is provided 'as-is', without any express or implied ++ warranty. In no event will the authors be held liable for any damages ++ arising from the use of this software. ++ ++ Permission is granted to anyone to use this software for any purpose, ++ including commercial applications, and to alter it and redistribute it ++ freely, subject to the following restrictions: ++ ++ 1. The origin of this software must not be misrepresented; you must not ++ claim that you wrote the original software. If you use this software ++ in a product, an acknowledgment in the product documentation would be ++ appreciated but is not required. ++ 2. Altered source versions must be plainly marked as such, and must not be ++ misrepresented as being the original software. ++ 3. This notice may not be removed or altered from any source distribution. ++ ++ Jean-loup Gailly Mark Adler ++ jloup@gzip.org madler@alumni.caltech.edu ++ ++ ++ The data format used by the zlib library is described by RFCs (Request for ++ Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt ++ (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). ++*/ ++ ++#ifndef ZLIB_H ++#define ZLIB_H ++ ++#include "zconf.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#define ZLIB_VERSION "1.2.1.1" ++#define ZLIB_VERNUM 0x1211 ++ ++/* ++ The 'zlib' compression library provides in-memory compression and ++ decompression functions, including integrity checks of the uncompressed ++ data. This version of the library supports only one compression method ++ (deflation) but other algorithms will be added later and will have the same ++ stream interface. ++ ++ Compression can be done in a single step if the buffers are large ++ enough (for example if an input file is mmap'ed), or can be done by ++ repeated calls of the compression function. In the latter case, the ++ application must provide more input and/or consume the output ++ (providing more output space) before each call. ++ ++ The compressed data format used by the in-memory functions is the zlib ++ format, which is a zlib wrapper documented in RFC 1950, wrapped around a ++ deflate stream, which is itself documented in RFC 1951. ++ ++ The library also supports reading and writing files in gzip (.gz) format ++ with an interface similar to that of stdio using the functions that start ++ with "gz". The gzip format is different from the zlib format. gzip is a ++ gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. ++ ++ The zlib format was designed to be compact and fast for use in memory ++ and on communications channels. The gzip format was designed for single- ++ file compression on file systems, has a larger header than zlib to maintain ++ directory information, and uses a different, slower check method than zlib. ++ ++ This library does not provide any functions to write gzip files in memory. ++ However such functions could be easily written using zlib's deflate function, ++ the documentation in the gzip RFC, and the examples in gzio.c. ++ ++ The library does not install any signal handler. The decoder checks ++ the consistency of the compressed data, so the library should never ++ crash even in case of corrupted input. ++*/ ++ ++typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); ++typedef void (*free_func) OF((voidpf opaque, voidpf address)); ++ ++struct internal_state; ++ ++typedef struct z_stream_s { ++ Bytef *next_in; /* next input byte */ ++ uInt avail_in; /* number of bytes available at next_in */ ++ uLong total_in; /* total nb of input bytes read so far */ ++ ++ Bytef *next_out; /* next output byte should be put there */ ++ uInt avail_out; /* remaining free space at next_out */ ++ uLong total_out; /* total nb of bytes output so far */ ++ ++ char *msg; /* last error message, NULL if no error */ ++ struct internal_state FAR *state; /* not visible by applications */ ++ ++ alloc_func zalloc; /* used to allocate the internal state */ ++ free_func zfree; /* used to free the internal state */ ++ voidpf opaque; /* private data object passed to zalloc and zfree */ ++ ++ int data_type; /* best guess about the data type: ascii or binary */ ++ uLong adler; /* adler32 value of the uncompressed data */ ++ uLong reserved; /* reserved for future use */ ++} z_stream; ++ ++typedef z_stream FAR *z_streamp; ++ ++/* ++ The application must update next_in and avail_in when avail_in has ++ dropped to zero. It must update next_out and avail_out when avail_out ++ has dropped to zero. The application must initialize zalloc, zfree and ++ opaque before calling the init function. All other fields are set by the ++ compression library and must not be updated by the application. ++ ++ The opaque value provided by the application will be passed as the first ++ parameter for calls of zalloc and zfree. This can be useful for custom ++ memory management. The compression library attaches no meaning to the ++ opaque value. ++ ++ zalloc must return Z_NULL if there is not enough memory for the object. ++ If zlib is used in a multi-threaded application, zalloc and zfree must be ++ thread safe. ++ ++ On 16-bit systems, the functions zalloc and zfree must be able to allocate ++ exactly 65536 bytes, but will not be required to allocate more than this ++ if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, ++ pointers returned by zalloc for objects of exactly 65536 bytes *must* ++ have their offset normalized to zero. The default allocation function ++ provided by this library ensures this (see zutil.c). To reduce memory ++ requirements and avoid any allocation of 64K objects, at the expense of ++ compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). ++ ++ The fields total_in and total_out can be used for statistics or ++ progress reports. After compression, total_in holds the total size of ++ the uncompressed data and may be saved for use in the decompressor ++ (particularly if the decompressor wants to decompress everything in ++ a single step). ++*/ ++ ++ /* constants */ ++ ++#define Z_NO_FLUSH 0 ++#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ ++#define Z_SYNC_FLUSH 2 ++#define Z_FULL_FLUSH 3 ++#define Z_FINISH 4 ++#define Z_BLOCK 5 ++/* Allowed flush values; see deflate() and inflate() below for details */ ++ ++#define Z_OK 0 ++#define Z_STREAM_END 1 ++#define Z_NEED_DICT 2 ++#define Z_ERRNO (-1) ++#define Z_STREAM_ERROR (-2) ++#define Z_DATA_ERROR (-3) ++#define Z_MEM_ERROR (-4) ++#define Z_BUF_ERROR (-5) ++#define Z_VERSION_ERROR (-6) ++/* Return codes for the compression/decompression functions. Negative ++ * values are errors, positive values are used for special but normal events. ++ */ ++ ++#define Z_NO_COMPRESSION 0 ++#define Z_BEST_SPEED 1 ++#define Z_BEST_COMPRESSION 9 ++#define Z_DEFAULT_COMPRESSION (-1) ++/* compression levels */ ++ ++#define Z_FILTERED 1 ++#define Z_HUFFMAN_ONLY 2 ++#define Z_RLE 3 ++#define Z_DEFAULT_STRATEGY 0 ++/* compression strategy; see deflateInit2() below for details */ ++ ++#define Z_BINARY 0 ++#define Z_ASCII 1 ++#define Z_UNKNOWN 2 ++/* Possible values of the data_type field (though see inflate()) */ ++ ++#define Z_DEFLATED 8 ++/* The deflate compression method (the only one supported in this version) */ ++ ++#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ ++ ++#define zlib_version zlibVersion() ++/* for compatibility with versions < 1.0.2 */ ++ ++ /* basic functions */ ++ ++ZEXTERN const char * ZEXPORT zlibVersion OF((void)); ++/* The application can compare zlibVersion and ZLIB_VERSION for consistency. ++ If the first character differs, the library code actually used is ++ not compatible with the zlib.h header file used by the application. ++ This check is automatically made by deflateInit and inflateInit. ++ */ ++ ++/* ++ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); ++ ++ Initializes the internal stream state for compression. The fields ++ zalloc, zfree and opaque must be initialized before by the caller. ++ If zalloc and zfree are set to Z_NULL, deflateInit updates them to ++ use default allocation functions. ++ ++ The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: ++ 1 gives best speed, 9 gives best compression, 0 gives no compression at ++ all (the input data is simply copied a block at a time). ++ Z_DEFAULT_COMPRESSION requests a default compromise between speed and ++ compression (currently equivalent to level 6). ++ ++ deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not ++ enough memory, Z_STREAM_ERROR if level is not a valid compression level, ++ Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible ++ with the version assumed by the caller (ZLIB_VERSION). ++ msg is set to null if there is no error message. deflateInit does not ++ perform any compression: this will be done by deflate(). ++*/ ++ ++ ++ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); ++/* ++ deflate compresses as much data as possible, and stops when the input ++ buffer becomes empty or the output buffer becomes full. It may introduce some ++ output latency (reading input without producing any output) except when ++ forced to flush. ++ ++ The detailed semantics are as follows. deflate performs one or both of the ++ following actions: ++ ++ - Compress more input starting at next_in and update next_in and avail_in ++ accordingly. If not all input can be processed (because there is not ++ enough room in the output buffer), next_in and avail_in are updated and ++ processing will resume at this point for the next call of deflate(). ++ ++ - Provide more output starting at next_out and update next_out and avail_out ++ accordingly. This action is forced if the parameter flush is non zero. ++ Forcing flush frequently degrades the compression ratio, so this parameter ++ should be set only when necessary (in interactive applications). ++ Some output may be provided even if flush is not set. ++ ++ Before the call of deflate(), the application should ensure that at least ++ one of the actions is possible, by providing more input and/or consuming ++ more output, and updating avail_in or avail_out accordingly; avail_out ++ should never be zero before the call. The application can consume the ++ compressed output when it wants, for example when the output buffer is full ++ (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK ++ and with zero avail_out, it must be called again after making room in the ++ output buffer because there might be more output pending. ++ ++ If the parameter flush is set to Z_SYNC_FLUSH, all pending output is ++ flushed to the output buffer and the output is aligned on a byte boundary, so ++ that the decompressor can get all input data available so far. (In particular ++ avail_in is zero after the call if enough output space has been provided ++ before the call.) Flushing may degrade compression for some compression ++ algorithms and so it should be used only when necessary. ++ ++ If flush is set to Z_FULL_FLUSH, all output is flushed as with ++ Z_SYNC_FLUSH, and the compression state is reset so that decompression can ++ restart from this point if previous compressed data has been damaged or if ++ random access is desired. Using Z_FULL_FLUSH too often can seriously degrade ++ the compression. ++ ++ If deflate returns with avail_out == 0, this function must be called again ++ with the same value of the flush parameter and more output space (updated ++ avail_out), until the flush is complete (deflate returns with non-zero ++ avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that ++ avail_out is greater than six to avoid repeated flush markers due to ++ avail_out == 0 on return. ++ ++ If the parameter flush is set to Z_FINISH, pending input is processed, ++ pending output is flushed and deflate returns with Z_STREAM_END if there ++ was enough output space; if deflate returns with Z_OK, this function must be ++ called again with Z_FINISH and more output space (updated avail_out) but no ++ more input data, until it returns with Z_STREAM_END or an error. After ++ deflate has returned Z_STREAM_END, the only possible operations on the ++ stream are deflateReset or deflateEnd. ++ ++ Z_FINISH can be used immediately after deflateInit if all the compression ++ is to be done in a single step. In this case, avail_out must be at least ++ the value returned by deflateBound (see below). If deflate does not return ++ Z_STREAM_END, then it must be called again as described above. ++ ++ deflate() sets strm->adler to the adler32 checksum of all input read ++ so far (that is, total_in bytes). ++ ++ deflate() may update data_type if it can make a good guess about ++ the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered ++ binary. This field is only for information purposes and does not affect ++ the compression algorithm in any manner. ++ ++ deflate() returns Z_OK if some progress has been made (more input ++ processed or more output produced), Z_STREAM_END if all input has been ++ consumed and all output has been produced (only when flush is set to ++ Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example ++ if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible ++ (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not ++ fatal, and deflate() can be called again with more input and more output ++ space to continue compressing. ++*/ ++ ++ ++ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); ++/* ++ All dynamically allocated data structures for this stream are freed. ++ This function discards any unprocessed input and does not flush any ++ pending output. ++ ++ deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the ++ stream state was inconsistent, Z_DATA_ERROR if the stream was freed ++ prematurely (some input or output was discarded). In the error case, ++ msg may be set but then points to a static string (which must not be ++ deallocated). ++*/ ++ ++ ++/* ++ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); ++ ++ Initializes the internal stream state for decompression. The fields ++ next_in, avail_in, zalloc, zfree and opaque must be initialized before by ++ the caller. If next_in is not Z_NULL and avail_in is large enough (the exact ++ value depends on the compression method), inflateInit determines the ++ compression method from the zlib header and allocates all data structures ++ accordingly; otherwise the allocation will be deferred to the first call of ++ inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to ++ use default allocation functions. ++ ++ inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough ++ memory, Z_VERSION_ERROR if the zlib library version is incompatible with the ++ version assumed by the caller. msg is set to null if there is no error ++ message. inflateInit does not perform any decompression apart from reading ++ the zlib header if present: this will be done by inflate(). (So next_in and ++ avail_in may be modified, but next_out and avail_out are unchanged.) ++*/ ++ ++ ++ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); ++/* ++ inflate decompresses as much data as possible, and stops when the input ++ buffer becomes empty or the output buffer becomes full. It may introduce ++ some output latency (reading input without producing any output) except when ++ forced to flush. ++ ++ The detailed semantics are as follows. inflate performs one or both of the ++ following actions: ++ ++ - Decompress more input starting at next_in and update next_in and avail_in ++ accordingly. If not all input can be processed (because there is not ++ enough room in the output buffer), next_in is updated and processing ++ will resume at this point for the next call of inflate(). ++ ++ - Provide more output starting at next_out and update next_out and avail_out ++ accordingly. inflate() provides as much output as possible, until there ++ is no more input data or no more space in the output buffer (see below ++ about the flush parameter). ++ ++ Before the call of inflate(), the application should ensure that at least ++ one of the actions is possible, by providing more input and/or consuming ++ more output, and updating the next_* and avail_* values accordingly. ++ The application can consume the uncompressed output when it wants, for ++ example when the output buffer is full (avail_out == 0), or after each ++ call of inflate(). If inflate returns Z_OK and with zero avail_out, it ++ must be called again after making room in the output buffer because there ++ might be more output pending. ++ ++ The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, ++ Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much ++ output as possible to the output buffer. Z_BLOCK requests that inflate() stop ++ if and when it get to the next deflate block boundary. When decoding the zlib ++ or gzip format, this will cause inflate() to return immediately after the ++ header and before the first block. When doing a raw inflate, inflate() will ++ go ahead and process the first block, and will return when it gets to the end ++ of that block, or when it runs out of data. ++ ++ The Z_BLOCK option assists in appending to or combining deflate streams. ++ Also to assist in this, on return inflate() will set strm->data_type to the ++ number of unused bits in the last byte taken from strm->next_in, plus 64 ++ if inflate() is currently decoding the last block in the deflate stream, ++ plus 128 if inflate() returned immediately after decoding an end-of-block ++ code or decoding the complete header up to just before the first byte of the ++ deflate stream. The end-of-block will not be indicated until all of the ++ uncompressed data from that block has been written to strm->next_out. The ++ number of unused bits may in general be greater than seven, except when ++ bit 7 of data_type is set, in which case the number of unused bits will be ++ less than eight. ++ ++ inflate() should normally be called until it returns Z_STREAM_END or an ++ error. However if all decompression is to be performed in a single step ++ (a single call of inflate), the parameter flush should be set to ++ Z_FINISH. In this case all pending input is processed and all pending ++ output is flushed; avail_out must be large enough to hold all the ++ uncompressed data. (The size of the uncompressed data may have been saved ++ by the compressor for this purpose.) The next operation on this stream must ++ be inflateEnd to deallocate the decompression state. The use of Z_FINISH ++ is never required, but can be used to inform inflate that a faster approach ++ may be used for the single inflate() call. ++ ++ In this implementation, inflate() always flushes as much output as ++ possible to the output buffer, and always uses the faster approach on the ++ first call. So the only effect of the flush parameter in this implementation ++ is on the return value of inflate(), as noted below, or when it returns early ++ because Z_BLOCK is used. ++ ++ If a preset dictionary is needed after this call (see inflateSetDictionary ++ below), inflate sets strm-adler to the adler32 checksum of the dictionary ++ chosen by the compressor and returns Z_NEED_DICT; otherwise it sets ++ strm->adler to the adler32 checksum of all output produced so far (that is, ++ total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described ++ below. At the end of the stream, inflate() checks that its computed adler32 ++ checksum is equal to that saved by the compressor and returns Z_STREAM_END ++ only if the checksum is correct. ++ ++ inflate() will decompress and check either zlib-wrapped or gzip-wrapped ++ deflate data. The header type is detected automatically. Any information ++ contained in the gzip header is not retained, so applications that need that ++ information should instead use raw inflate, see inflateInit2() below, or ++ inflateBack() and perform their own processing of the gzip header and ++ trailer. ++ ++ inflate() returns Z_OK if some progress has been made (more input processed ++ or more output produced), Z_STREAM_END if the end of the compressed data has ++ been reached and all uncompressed output has been produced, Z_NEED_DICT if a ++ preset dictionary is needed at this point, Z_DATA_ERROR if the input data was ++ corrupted (input stream not conforming to the zlib format or incorrect check ++ value), Z_STREAM_ERROR if the stream structure was inconsistent (for example ++ if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, ++ Z_BUF_ERROR if no progress is possible or if there was not enough room in the ++ output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and ++ inflate() can be called again with more input and more output space to ++ continue decompressing. If Z_DATA_ERROR is returned, the application may then ++ call inflateSync() to look for a good compression block if a partial recovery ++ of the data is desired. ++*/ ++ ++ ++ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); ++/* ++ All dynamically allocated data structures for this stream are freed. ++ This function discards any unprocessed input and does not flush any ++ pending output. ++ ++ inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state ++ was inconsistent. In the error case, msg may be set but then points to a ++ static string (which must not be deallocated). ++*/ ++ ++ /* Advanced functions */ ++ ++/* ++ The following functions are needed only in some special applications. ++*/ ++ ++/* ++ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, ++ int level, ++ int method, ++ int windowBits, ++ int memLevel, ++ int strategy)); ++ ++ This is another version of deflateInit with more compression options. The ++ fields next_in, zalloc, zfree and opaque must be initialized before by ++ the caller. ++ ++ The method parameter is the compression method. It must be Z_DEFLATED in ++ this version of the library. ++ ++ The windowBits parameter is the base two logarithm of the window size ++ (the size of the history buffer). It should be in the range 8..15 for this ++ version of the library. Larger values of this parameter result in better ++ compression at the expense of memory usage. The default value is 15 if ++ deflateInit is used instead. ++ ++ windowBits can also be -8..-15 for raw deflate. In this case, -windowBits ++ determines the window size. deflate() will then generate raw deflate data ++ with no zlib header or trailer, and will not compute an adler32 check value. ++ ++ windowBits can also be greater than 15 for optional gzip encoding. Add ++ 16 to windowBits to write a simple gzip header and trailer around the ++ compressed data instead of a zlib wrapper. The gzip header will have no ++ file name, no extra data, no comment, no modification time (set to zero), ++ no header crc, and the operating system will be set to 255 (unknown). ++ ++ The memLevel parameter specifies how much memory should be allocated ++ for the internal compression state. memLevel=1 uses minimum memory but ++ is slow and reduces compression ratio; memLevel=9 uses maximum memory ++ for optimal speed. The default value is 8. See zconf.h for total memory ++ usage as a function of windowBits and memLevel. ++ ++ The strategy parameter is used to tune the compression algorithm. Use the ++ value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a ++ filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no ++ string match), or Z_RLE to limit match distances to one (run-length ++ encoding). Filtered data consists mostly of small values with a somewhat ++ random distribution. In this case, the compression algorithm is tuned to ++ compress them better. The effect of Z_FILTERED is to force more Huffman ++ coding and less string matching; it is somewhat intermediate between ++ Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as ++ Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy ++ parameter only affects the compression ratio but not the correctness of the ++ compressed output even if it is not set appropriately. ++ ++ deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough ++ memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid ++ method). msg is set to null if there is no error message. deflateInit2 does ++ not perform any compression: this will be done by deflate(). ++*/ ++ ++ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, ++ const Bytef *dictionary, ++ uInt dictLength)); ++/* ++ Initializes the compression dictionary from the given byte sequence ++ without producing any compressed output. This function must be called ++ immediately after deflateInit, deflateInit2 or deflateReset, before any ++ call of deflate. The compressor and decompressor must use exactly the same ++ dictionary (see inflateSetDictionary). ++ ++ The dictionary should consist of strings (byte sequences) that are likely ++ to be encountered later in the data to be compressed, with the most commonly ++ used strings preferably put towards the end of the dictionary. Using a ++ dictionary is most useful when the data to be compressed is short and can be ++ predicted with good accuracy; the data can then be compressed better than ++ with the default empty dictionary. ++ ++ Depending on the size of the compression data structures selected by ++ deflateInit or deflateInit2, a part of the dictionary may in effect be ++ discarded, for example if the dictionary is larger than the window size in ++ deflate or deflate2. Thus the strings most likely to be useful should be ++ put at the end of the dictionary, not at the front. ++ ++ Upon return of this function, strm->adler is set to the adler32 value ++ of the dictionary; the decompressor may later use this value to determine ++ which dictionary has been used by the compressor. (The adler32 value ++ applies to the whole dictionary even if only a subset of the dictionary is ++ actually used by the compressor.) If a raw deflate was requested, then the ++ adler32 value is not computed and strm->adler is not set. ++ ++ deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a ++ parameter is invalid (such as NULL dictionary) or the stream state is ++ inconsistent (for example if deflate has already been called for this stream ++ or if the compression method is bsort). deflateSetDictionary does not ++ perform any compression: this will be done by deflate(). ++*/ ++ ++ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, ++ z_streamp source)); ++/* ++ Sets the destination stream as a complete copy of the source stream. ++ ++ This function can be useful when several compression strategies will be ++ tried, for example when there are several ways of pre-processing the input ++ data with a filter. The streams that will be discarded should then be freed ++ by calling deflateEnd. Note that deflateCopy duplicates the internal ++ compression state which can be quite large, so this strategy is slow and ++ can consume lots of memory. ++ ++ deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not ++ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent ++ (such as zalloc being NULL). msg is left unchanged in both source and ++ destination. ++*/ ++ ++ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); ++/* ++ This function is equivalent to deflateEnd followed by deflateInit, ++ but does not free and reallocate all the internal compression state. ++ The stream will keep the same compression level and any other attributes ++ that may have been set by deflateInit2. ++ ++ deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source ++ stream state was inconsistent (such as zalloc or state being NULL). ++*/ ++ ++ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, ++ int level, ++ int strategy)); ++/* ++ Dynamically update the compression level and compression strategy. The ++ interpretation of level and strategy is as in deflateInit2. This can be ++ used to switch between compression and straight copy of the input data, or ++ to switch to a different kind of input data requiring a different ++ strategy. If the compression level is changed, the input available so far ++ is compressed with the old level (and may be flushed); the new level will ++ take effect only at the next call of deflate(). ++ ++ Before the call of deflateParams, the stream state must be set as for ++ a call of deflate(), since the currently available input may have to ++ be compressed and flushed. In particular, strm->avail_out must be non-zero. ++ ++ deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source ++ stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR ++ if strm->avail_out was zero. ++*/ ++ ++ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, ++ uLong sourceLen)); ++/* ++ deflateBound() returns an upper bound on the compressed size after ++ deflation of sourceLen bytes. It must be called after deflateInit() ++ or deflateInit2(). This would be used to allocate an output buffer ++ for deflation in a single pass, and so would be called before deflate(). ++*/ ++ ++ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, ++ int bits, ++ int value)); ++/* ++ deflatePrime() inserts bits in the deflate output stream. The intent ++ is that this function is used to start off the deflate output with the ++ bits leftover from a previous deflate stream when appending to it. As such, ++ this function can only be used for raw deflate, and must be used before the ++ first deflate() call after a deflateInit2() or deflateReset(). bits must be ++ less than or equal to 16, and that many of the least significant bits of ++ value will be inserted in the output. ++ ++ deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source ++ stream state was inconsistent. ++*/ ++ ++/* ++ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, ++ int windowBits)); ++ ++ This is another version of inflateInit with an extra parameter. The ++ fields next_in, avail_in, zalloc, zfree and opaque must be initialized ++ before by the caller. ++ ++ The windowBits parameter is the base two logarithm of the maximum window ++ size (the size of the history buffer). It should be in the range 8..15 for ++ this version of the library. The default value is 15 if inflateInit is used ++ instead. windowBits must be greater than or equal to the windowBits value ++ provided to deflateInit2() while compressing, or it must be equal to 15 if ++ deflateInit2() was not used. If a compressed stream with a larger window ++ size is given as input, inflate() will return with the error code ++ Z_DATA_ERROR instead of trying to allocate a larger window. ++ ++ windowBits can also be -8..-15 for raw inflate. In this case, -windowBits ++ determines the window size. inflate() will then process raw deflate data, ++ not looking for a zlib or gzip header, not generating a check value, and not ++ looking for any check values for comparison at the end of the stream. This ++ is for use with other formats that use the deflate compressed data format ++ such as zip. Those formats provide their own check values. If a custom ++ format is developed using the raw deflate format for compressed data, it is ++ recommended that a check value such as an adler32 or a crc32 be applied to ++ the uncompressed data as is done in the zlib, gzip, and zip formats. For ++ most applications, the zlib format should be used as is. Note that comments ++ above on the use in deflateInit2() applies to the magnitude of windowBits. ++ ++ windowBits can also be greater than 15 for optional gzip decoding. Add ++ 32 to windowBits to enable zlib and gzip decoding with automatic header ++ detection, or add 16 to decode only the gzip format (the zlib format will ++ return a Z_DATA_ERROR). ++ ++ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough ++ memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative ++ memLevel). msg is set to null if there is no error message. inflateInit2 ++ does not perform any decompression apart from reading the zlib header if ++ present: this will be done by inflate(). (So next_in and avail_in may be ++ modified, but next_out and avail_out are unchanged.) ++*/ ++ ++ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, ++ const Bytef *dictionary, ++ uInt dictLength)); ++/* ++ Initializes the decompression dictionary from the given uncompressed byte ++ sequence. This function must be called immediately after a call of inflate ++ if this call returned Z_NEED_DICT. The dictionary chosen by the compressor ++ can be determined from the adler32 value returned by this call of ++ inflate. The compressor and decompressor must use exactly the same ++ dictionary (see deflateSetDictionary). ++ ++ inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a ++ parameter is invalid (such as NULL dictionary) or the stream state is ++ inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the ++ expected one (incorrect adler32 value). inflateSetDictionary does not ++ perform any decompression: this will be done by subsequent calls of ++ inflate(). ++*/ ++ ++ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); ++/* ++ Skips invalid compressed data until a full flush point (see above the ++ description of deflate with Z_FULL_FLUSH) can be found, or until all ++ available input is skipped. No output is provided. ++ ++ inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR ++ if no more input was provided, Z_DATA_ERROR if no flush point has been found, ++ or Z_STREAM_ERROR if the stream structure was inconsistent. In the success ++ case, the application may save the current current value of total_in which ++ indicates where valid compressed data was found. In the error case, the ++ application may repeatedly call inflateSync, providing more input each time, ++ until success or end of the input data. ++*/ ++ ++ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, ++ z_streamp source)); ++/* ++ Sets the destination stream as a complete copy of the source stream. ++ ++ This function can be useful when randomly accessing a large stream. The ++ first pass through the stream can periodically record the inflate state, ++ allowing restarting inflate at those points when randomly accessing the ++ stream. ++ ++ inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not ++ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent ++ (such as zalloc being NULL). msg is left unchanged in both source and ++ destination. ++*/ ++ ++ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); ++/* ++ This function is equivalent to inflateEnd followed by inflateInit, ++ but does not free and reallocate all the internal decompression state. ++ The stream will keep attributes that may have been set by inflateInit2. ++ ++ inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source ++ stream state was inconsistent (such as zalloc or state being NULL). ++*/ ++ ++/* ++ZEXTERN int ZEXPORT inflateBackInit OF((z_stream FAR *strm, int windowBits, ++ unsigned char FAR *window)); ++ ++ Initialize the internal stream state for decompression using inflateBack() ++ calls. The fields zalloc, zfree and opaque in strm must be initialized ++ before the call. If zalloc and zfree are Z_NULL, then the default library- ++ derived memory allocation routines are used. windowBits is the base two ++ logarithm of the window size, in the range 8..15. window is a caller ++ supplied buffer of that size. Except for special applications where it is ++ assured that deflate was used with small window sizes, windowBits must be 15 ++ and a 32K byte window must be supplied to be able to decompress general ++ deflate streams. ++ ++ See inflateBack() for the usage of these routines. ++ ++ inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of ++ the paramaters are invalid, Z_MEM_ERROR if the internal state could not ++ be allocated, or Z_VERSION_ERROR if the version of the library does not ++ match the version of the header file. ++*/ ++ ++typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); ++typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); ++ ++ZEXTERN int ZEXPORT inflateBack OF((z_stream FAR *strm, ++ in_func in, void FAR *in_desc, ++ out_func out, void FAR *out_desc)); ++/* ++ inflateBack() does a raw inflate with a single call using a call-back ++ interface for input and output. This is more efficient than inflate() for ++ file i/o applications in that it avoids copying between the output and the ++ sliding window by simply making the window itself the output buffer. This ++ function trusts the application to not change the output buffer passed by ++ the output function, at least until inflateBack() returns. ++ ++ inflateBackInit() must be called first to allocate the internal state ++ and to initialize the state with the user-provided window buffer. ++ inflateBack() may then be used multiple times to inflate a complete, raw ++ deflate stream with each call. inflateBackEnd() is then called to free ++ the allocated state. ++ ++ A raw deflate stream is one with no zlib or gzip header or trailer. ++ This routine would normally be used in a utility that reads zip or gzip ++ files and writes out uncompressed files. The utility would decode the ++ header and process the trailer on its own, hence this routine expects ++ only the raw deflate stream to decompress. This is different from the ++ normal behavior of inflate(), which expects either a zlib or gzip header and ++ trailer around the deflate stream. ++ ++ inflateBack() uses two subroutines supplied by the caller that are then ++ called by inflateBack() for input and output. inflateBack() calls those ++ routines until it reads a complete deflate stream and writes out all of the ++ uncompressed data, or until it encounters an error. The function's ++ parameters and return types are defined above in the in_func and out_func ++ typedefs. inflateBack() will call in(in_desc, &buf) which should return the ++ number of bytes of provided input, and a pointer to that input in buf. If ++ there is no input available, in() must return zero--buf is ignored in that ++ case--and inflateBack() will return a buffer error. inflateBack() will call ++ out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() ++ should return zero on success, or non-zero on failure. If out() returns ++ non-zero, inflateBack() will return with an error. Neither in() nor out() ++ are permitted to change the contents of the window provided to ++ inflateBackInit(), which is also the buffer that out() uses to write from. ++ The length written by out() will be at most the window size. Any non-zero ++ amount of input may be provided by in(). ++ ++ For convenience, inflateBack() can be provided input on the first call by ++ setting strm->next_in and strm->avail_in. If that input is exhausted, then ++ in() will be called. Therefore strm->next_in must be initialized before ++ calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called ++ immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in ++ must also be initialized, and then if strm->avail_in is not zero, input will ++ initially be taken from strm->next_in[0 .. strm->avail_in - 1]. ++ ++ The in_desc and out_desc parameters of inflateBack() is passed as the ++ first parameter of in() and out() respectively when they are called. These ++ descriptors can be optionally used to pass any information that the caller- ++ supplied in() and out() functions need to do their job. ++ ++ On return, inflateBack() will set strm->next_in and strm->avail_in to ++ pass back any unused input that was provided by the last in() call. The ++ return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR ++ if in() or out() returned an error, Z_DATA_ERROR if there was a format ++ error in the deflate stream (in which case strm->msg is set to indicate the ++ nature of the error), or Z_STREAM_ERROR if the stream was not properly ++ initialized. In the case of Z_BUF_ERROR, an input or output error can be ++ distinguished using strm->next_in which will be Z_NULL only if in() returned ++ an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to ++ out() returning non-zero. (in() will always be called before out(), so ++ strm->next_in is assured to be defined if out() returns non-zero.) Note ++ that inflateBack() cannot return Z_OK. ++*/ ++ ++ZEXTERN int ZEXPORT inflateBackEnd OF((z_stream FAR *strm)); ++/* ++ All memory allocated by inflateBackInit() is freed. ++ ++ inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream ++ state was inconsistent. ++*/ ++ ++ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); ++/* Return flags indicating compile-time options. ++ ++ Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: ++ 1.0: size of uInt ++ 3.2: size of uLong ++ 5.4: size of voidpf (pointer) ++ 7.6: size of z_off_t ++ ++ Compiler, assembler, and debug options: ++ 8: DEBUG ++ 9: ASMV or ASMINF -- use ASM code ++ 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention ++ 11: 0 (reserved) ++ ++ One-time table building (smaller code, but not thread-safe if true): ++ 12: BUILDFIXED -- build static block decoding tables when needed ++ 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed ++ 14,15: 0 (reserved) ++ ++ Library content (indicates missing functionality): ++ 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking ++ deflate code when not needed) ++ 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect ++ and decode gzip streams (to avoid linking crc code) ++ 18-19: 0 (reserved) ++ ++ Operation variations (changes in library functionality): ++ 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate ++ 21: FASTEST -- deflate algorithm with only one, lowest compression level ++ 22,23: 0 (reserved) ++ ++ The sprintf variant used by gzprintf (zero is best): ++ 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format ++ 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! ++ 26: 0 = returns value, 1 = void -- 1 means inferred string length returned ++ ++ Remainder: ++ 27-31: 0 (reserved) ++ */ ++ ++ ++ /* utility functions */ ++ ++/* ++ The following utility functions are implemented on top of the ++ basic stream-oriented functions. To simplify the interface, some ++ default options are assumed (compression level and memory usage, ++ standard memory allocation functions). The source code of these ++ utility functions can easily be modified if you need special options. ++*/ ++ ++ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, ++ const Bytef *source, uLong sourceLen)); ++/* ++ Compresses the source buffer into the destination buffer. sourceLen is ++ the byte length of the source buffer. Upon entry, destLen is the total ++ size of the destination buffer, which must be at least the value returned ++ by compressBound(sourceLen). Upon exit, destLen is the actual size of the ++ compressed buffer. ++ This function can be used to compress a whole file at once if the ++ input file is mmap'ed. ++ compress returns Z_OK if success, Z_MEM_ERROR if there was not ++ enough memory, Z_BUF_ERROR if there was not enough room in the output ++ buffer. ++*/ ++ ++ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, ++ const Bytef *source, uLong sourceLen, ++ int level)); ++/* ++ Compresses the source buffer into the destination buffer. The level ++ parameter has the same meaning as in deflateInit. sourceLen is the byte ++ length of the source buffer. Upon entry, destLen is the total size of the ++ destination buffer, which must be at least the value returned by ++ compressBound(sourceLen). Upon exit, destLen is the actual size of the ++ compressed buffer. ++ ++ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough ++ memory, Z_BUF_ERROR if there was not enough room in the output buffer, ++ Z_STREAM_ERROR if the level parameter is invalid. ++*/ ++ ++ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); ++/* ++ compressBound() returns an upper bound on the compressed size after ++ compress() or compress2() on sourceLen bytes. It would be used before ++ a compress() or compress2() call to allocate the destination buffer. ++*/ ++ ++ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, ++ const Bytef *source, uLong sourceLen)); ++/* ++ Decompresses the source buffer into the destination buffer. sourceLen is ++ the byte length of the source buffer. Upon entry, destLen is the total ++ size of the destination buffer, which must be large enough to hold the ++ entire uncompressed data. (The size of the uncompressed data must have ++ been saved previously by the compressor and transmitted to the decompressor ++ by some mechanism outside the scope of this compression library.) ++ Upon exit, destLen is the actual size of the compressed buffer. ++ This function can be used to decompress a whole file at once if the ++ input file is mmap'ed. ++ ++ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not ++ enough memory, Z_BUF_ERROR if there was not enough room in the output ++ buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. ++*/ ++ ++ ++typedef voidp gzFile; ++ ++ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); ++/* ++ Opens a gzip (.gz) file for reading or writing. The mode parameter ++ is as in fopen ("rb" or "wb") but can also include a compression level ++ ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for ++ Huffman only compression as in "wb1h", or 'R' for run-length encoding ++ as in "wb1R". (See the description of deflateInit2 for more information ++ about the strategy parameter.) ++ ++ gzopen can be used to read a file which is not in gzip format; in this ++ case gzread will directly read from the file without decompression. ++ ++ gzopen returns NULL if the file could not be opened or if there was ++ insufficient memory to allocate the (de)compression state; errno ++ can be checked to distinguish the two cases (if errno is zero, the ++ zlib error is Z_MEM_ERROR). */ ++ ++ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); ++/* ++ gzdopen() associates a gzFile with the file descriptor fd. File ++ descriptors are obtained from calls like open, dup, creat, pipe or ++ fileno (in the file has been previously opened with fopen). ++ The mode parameter is as in gzopen. ++ The next call of gzclose on the returned gzFile will also close the ++ file descriptor fd, just like fclose(fdopen(fd), mode) closes the file ++ descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). ++ gzdopen returns NULL if there was insufficient memory to allocate ++ the (de)compression state. ++*/ ++ ++ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); ++/* ++ Dynamically update the compression level or strategy. See the description ++ of deflateInit2 for the meaning of these parameters. ++ gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not ++ opened for writing. ++*/ ++ ++ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); ++/* ++ Reads the given number of uncompressed bytes from the compressed file. ++ If the input file was not in gzip format, gzread copies the given number ++ of bytes into the buffer. ++ gzread returns the number of uncompressed bytes actually read (0 for ++ end of file, -1 for error). */ ++ ++ZEXTERN int ZEXPORT gzwrite OF((gzFile file, ++ voidpc buf, unsigned len)); ++/* ++ Writes the given number of uncompressed bytes into the compressed file. ++ gzwrite returns the number of uncompressed bytes actually written ++ (0 in case of error). ++*/ ++ ++ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); ++/* ++ Converts, formats, and writes the args to the compressed file under ++ control of the format string, as in fprintf. gzprintf returns the number of ++ uncompressed bytes actually written (0 in case of error). The number of ++ uncompressed bytes written is limited to 4095. The caller should assure that ++ this limit is not exceeded. If it is exceeded, then gzprintf() will return ++ return an error (0) with nothing written. In this case, there may also be a ++ buffer overflow with unpredictable consequences, which is possible only if ++ zlib was compiled with the insecure functions sprintf() or vsprintf() ++ because the secure snprintf() or vsnprintf() functions were not available. ++*/ ++ ++ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); ++/* ++ Writes the given null-terminated string to the compressed file, excluding ++ the terminating null character. ++ gzputs returns the number of characters written, or -1 in case of error. ++*/ ++ ++ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); ++/* ++ Reads bytes from the compressed file until len-1 characters are read, or ++ a newline character is read and transferred to buf, or an end-of-file ++ condition is encountered. The string is then terminated with a null ++ character. ++ gzgets returns buf, or Z_NULL in case of error. ++*/ ++ ++ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); ++/* ++ Writes c, converted to an unsigned char, into the compressed file. ++ gzputc returns the value that was written, or -1 in case of error. ++*/ ++ ++ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); ++/* ++ Reads one byte from the compressed file. gzgetc returns this byte ++ or -1 in case of end of file or error. ++*/ ++ ++ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); ++/* ++ Push one character back onto the stream to be read again later. ++ Only one character of push-back is allowed. gzungetc() returns the ++ character pushed, or -1 on failure. gzungetc() will fail if a ++ character has been pushed but not read yet, or if c is -1. The pushed ++ character will be discarded if the stream is repositioned with gzseek() ++ or gzrewind(). ++*/ ++ ++ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); ++/* ++ Flushes all pending output into the compressed file. The parameter ++ flush is as in the deflate() function. The return value is the zlib ++ error number (see function gzerror below). gzflush returns Z_OK if ++ the flush parameter is Z_FINISH and all output could be flushed. ++ gzflush should be called only when strictly necessary because it can ++ degrade compression. ++*/ ++ ++ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, ++ z_off_t offset, int whence)); ++/* ++ Sets the starting position for the next gzread or gzwrite on the ++ given compressed file. The offset represents a number of bytes in the ++ uncompressed data stream. The whence parameter is defined as in lseek(2); ++ the value SEEK_END is not supported. ++ If the file is opened for reading, this function is emulated but can be ++ extremely slow. If the file is opened for writing, only forward seeks are ++ supported; gzseek then compresses a sequence of zeroes up to the new ++ starting position. ++ ++ gzseek returns the resulting offset location as measured in bytes from ++ the beginning of the uncompressed stream, or -1 in case of error, in ++ particular if the file is opened for writing and the new starting position ++ would be before the current position. ++*/ ++ ++ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); ++/* ++ Rewinds the given file. This function is supported only for reading. ++ ++ gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) ++*/ ++ ++ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); ++/* ++ Returns the starting position for the next gzread or gzwrite on the ++ given compressed file. This position represents a number of bytes in the ++ uncompressed data stream. ++ ++ gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) ++*/ ++ ++ZEXTERN int ZEXPORT gzeof OF((gzFile file)); ++/* ++ Returns 1 when EOF has previously been detected reading the given ++ input stream, otherwise zero. ++*/ ++ ++ZEXTERN int ZEXPORT gzclose OF((gzFile file)); ++/* ++ Flushes all pending output if necessary, closes the compressed file ++ and deallocates all the (de)compression state. The return value is the zlib ++ error number (see function gzerror below). ++*/ ++ ++ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); ++/* ++ Returns the error message for the last error which occurred on the ++ given compressed file. errnum is set to zlib error number. If an ++ error occurred in the file system and not in the compression library, ++ errnum is set to Z_ERRNO and the application may consult errno ++ to get the exact error code. ++*/ ++ ++ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); ++/* ++ Clears the error and end-of-file flags for file. This is analogous to the ++ clearerr() function in stdio. This is useful for continuing to read a gzip ++ file that is being written concurrently. ++*/ ++ ++ /* checksum functions */ ++ ++/* ++ These functions are not related to compression but are exported ++ anyway because they might be useful in applications using the ++ compression library. ++*/ ++ ++ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); ++ ++/* ++ Update a running Adler-32 checksum with the bytes buf[0..len-1] and ++ return the updated checksum. If buf is NULL, this function returns ++ the required initial value for the checksum. ++ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed ++ much faster. Usage example: ++ ++ uLong adler = adler32(0L, Z_NULL, 0); ++ ++ while (read_buffer(buffer, length) != EOF) { ++ adler = adler32(adler, buffer, length); ++ } ++ if (adler != original_adler) error(); ++*/ ++ ++ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); ++/* ++ Update a running crc with the bytes buf[0..len-1] and return the updated ++ crc. If buf is NULL, this function returns the required initial value ++ for the crc. Pre- and post-conditioning (one's complement) is performed ++ within this function so it shouldn't be done by the application. ++ Usage example: ++ ++ uLong crc = crc32(0L, Z_NULL, 0); ++ ++ while (read_buffer(buffer, length) != EOF) { ++ crc = crc32(crc, buffer, length); ++ } ++ if (crc != original_crc) error(); ++*/ ++ ++ ++ /* various hacks, don't look :) */ ++ ++/* deflateInit and inflateInit are macros to allow checking the zlib version ++ * and the compiler's view of z_stream: ++ */ ++ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, ++ const char *version, int stream_size)); ++ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, ++ const char *version, int stream_size)); ++ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, ++ int windowBits, int memLevel, ++ int strategy, const char *version, ++ int stream_size)); ++ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, ++ const char *version, int stream_size)); ++ZEXTERN int ZEXPORT inflateBackInit_ OF((z_stream FAR *strm, int windowBits, ++ unsigned char FAR *window, ++ const char *version, ++ int stream_size)); ++#define deflateInit(strm, level) \ ++ deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) ++#define inflateInit(strm) \ ++ inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) ++#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ ++ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ ++ (strategy), ZLIB_VERSION, sizeof(z_stream)) ++#define inflateInit2(strm, windowBits) \ ++ inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) ++#define inflateBackInit(strm, windowBits, window) \ ++ inflateBackInit_((strm), (windowBits), (window), \ ++ ZLIB_VERSION, sizeof(z_stream)) ++ ++ ++#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) ++ struct internal_state {int dummy;}; /* hack for buggy compilers */ ++#endif ++ ++ZEXTERN const char * ZEXPORT zError OF((int err)); ++ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); ++ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* ZLIB_H */ --- php5-5.2.10.dfsg.1.orig/debian/patches/php5-pear-CVE-2011-1144-regression.patch +++ php5-5.2.10.dfsg.1/debian/patches/php5-pear-CVE-2011-1144-regression.patch @@ -0,0 +1,45 @@ +Subject: Bug #18340raiseErro typo +Origin: http://svn.php.net/viewvc?view=revision&revision=308983 + +Also includes http://svn.php.net/viewvc?view=revision&revision=309593 + + Fixed Bug #18388: Parenteses error in REST.php line 232 [dufuz] + +--- PEAR/REST.php.old 2011-03-18 16:33:00.000000000 -0300 ++++ PEAR/REST.php 2011-03-22 18:46:25.000000000 -0300 +@@ -102,7 +102,7 @@ + // reset the age of the cache if the server says it was unmodified + $result = $this->saveCache($url, $ret, null, true, $cacheId); + if (PEAR::isError($result)) { +- return PEAR::raiseErro($result->getMessage()); ++ return PEAR::raiseError($result->getMessage()); + } + } + +@@ -122,7 +122,7 @@ + if ($forcestring) { + $result = $this->saveCache($url, $content, $lastmodified, false, $cacheId); + if (PEAR::isError($result)) { +- return PEAR::raiseErro($result->getMessage()); ++ return PEAR::raiseError($result->getMessage()); + } + + return $content; +@@ -162,7 +162,7 @@ + + $result = $this->saveCache($url, $content, $lastmodified, false, $cacheId); + if (PEAR::isError($result)) { +- return PEAR::raiseErro($result->getMessage()); ++ return PEAR::raiseError($result->getMessage()); + } + + return $content; +@@ -229,7 +229,7 @@ + $cachefile = $d . 'rest.cachefile'; + + if (!is_dir($cache_dir)) { +- if (System::mkdir(array('-p', $cache_dir) === false)) { ++ if (System::mkdir(array('-p', $cache_dir)) === false) { + return PEAR::raiseError("The value of config option cache_dir ($cache_dir) is not a directory and attempts to create the directory failed."); + } + } --- php5-5.2.10.dfsg.1.orig/debian/patches/mssql-null-exception.patch +++ php5-5.2.10.dfsg.1/debian/patches/mssql-null-exception.patch @@ -0,0 +1,16 @@ +Index: php/ext/pdo_dblib/dblib_driver.c +=================================================================== +--- php.orig/ext/pdo_dblib/dblib_driver.c ++++ php/ext/pdo_dblib/dblib_driver.c +@@ -230,9 +230,11 @@ static int pdo_dblib_handle_factory(pdo_ + goto cleanup; + } + ++#if PHP_DBLIB_IS_MSSQL + if (DBSETOPT(H->link, DBTEXTLIMIT, "2147483647") == FAIL) { + goto cleanup; + } ++#endif + + if (vars[3].optval && FAIL == dbuse(H->link, vars[3].optval)) { + goto cleanup; --- php5-5.2.10.dfsg.1.orig/debian/patches/004-ldap_fix.patch +++ php5-5.2.10.dfsg.1/debian/patches/004-ldap_fix.patch @@ -0,0 +1,21 @@ +--- php.orig/ext/ldap/ldap.c ++++ php/ext/ldap/ldap.c +@@ -1335,7 +1335,7 @@ PHP_FUNCTION(ldap_explode_dn) + } + + i=0; +- while (ldap_value[i] != NULL) i++; ++ while (ldap_value && ldap_value[i] != NULL) i++; + count = i; + + array_init(return_value); +@@ -1345,7 +1345,8 @@ PHP_FUNCTION(ldap_explode_dn) + add_index_string(return_value, i, ldap_value[i], 1); + } + +- ldap_value_free(ldap_value); ++ if (ldap_value) ++ ldap_value_free(ldap_value); + } + /* }}} */ + --- php5-5.2.10.dfsg.1.orig/debian/patches/disable_dl_by_default.patch +++ php5-5.2.10.dfsg.1/debian/patches/disable_dl_by_default.patch @@ -0,0 +1,25 @@ +--- php.orig/php.ini-dist ++++ php/php.ini-dist +@@ -510,7 +510,8 @@ user_dir = + ; Whether or not to enable the dl() function. The dl() function does NOT work + ; properly in multithreaded servers, such as IIS or Zeus, and is automatically + ; disabled on them. +-enable_dl = On ++; NOTE: this is a potential security hole and is disabled by default in debian ++enable_dl = Off + + ; cgi.force_redirect is necessary to provide security running PHP as a CGI under + ; most web servers. Left undefined, PHP turns this on by default. You can +--- php.orig/php.ini-recommended ++++ php/php.ini-recommended +@@ -544,7 +544,9 @@ user_dir = + ; Whether or not to enable the dl() function. The dl() function does NOT work + ; properly in multithreaded servers, such as IIS or Zeus, and is automatically + ; disabled on them. +-enable_dl = On ++; NOTE: this is a potential security hole and is disabled by default in debian ++enable_dl = Off ++ + + ; cgi.force_redirect is necessary to provide security running PHP as a CGI under + ; most web servers. Left undefined, PHP turns this on by default. You can --- php5-5.2.10.dfsg.1.orig/debian/patches/101-sqlite_is_shared.patch +++ php5-5.2.10.dfsg.1/debian/patches/101-sqlite_is_shared.patch @@ -0,0 +1,11 @@ +--- php.orig/ext/sqlite/config.m4 ++++ php/ext/sqlite/config.m4 +@@ -84,7 +84,7 @@ if test "$PHP_SQLITE" != "no"; then + ]) + SQLITE_MODULE_TYPE=external + PHP_SQLITE_CFLAGS=$pdo_inc_path +- sqlite_extra_sources="libsqlite/src/encode.c" ++ sqlite_extra_sources="" + else + # use bundled library + PHP_PROG_LEMON --- php5-5.2.10.dfsg.1.orig/debian/patches/CVE-2010-1868.patch +++ php5-5.2.10.dfsg.1/debian/patches/CVE-2010-1868.patch @@ -0,0 +1,24 @@ +Description: fix arbitrary code execution via empty SQL query +Origin: upstream, http://svn.php.net/viewvc?view=revision&revision=298697 + +diff -Nur php5-5.2.10.dfsg.1/ext/sqlite/sqlite.c php5-5.2.10.dfsg.1.new/ext/sqlite/sqlite.c +--- php5-5.2.10.dfsg.1/ext/sqlite/sqlite.c 2008-12-31 06:17:44.000000000 -0500 ++++ php5-5.2.10.dfsg.1.new/ext/sqlite/sqlite.c 2010-09-14 14:38:06.000000000 -0400 +@@ -2170,7 +2170,7 @@ + return; + } + +- rres = (struct php_sqlite_result *)emalloc(sizeof(*rres)); ++ rres = (struct php_sqlite_result *)ecalloc(1, sizeof(*rres)); + sqlite_query(NULL, db, sql, sql_len, (int)mode, 0, NULL, &rres, NULL TSRMLS_CC); + if (db->last_err_code != SQLITE_OK) { + if (rres) { +@@ -2286,7 +2286,7 @@ + return; + } + +- rres = (struct php_sqlite_result *)emalloc(sizeof(*rres)); ++ rres = (struct php_sqlite_result *)ecalloc(1, sizeof(*rres)); + sqlite_query(NULL, db, sql, sql_len, PHPSQLITE_NUM, 0, NULL, &rres, NULL TSRMLS_CC); + if (db->last_err_code != SQLITE_OK) { + if (rres) { --- php5-5.2.10.dfsg.1.orig/debian/patches/php5-CVE-2011-1470.patch +++ php5-5.2.10.dfsg.1/debian/patches/php5-CVE-2011-1470.patch @@ -0,0 +1,70 @@ +Subject: Fixed bug#53579 (stream_get_contents() segfaults on ziparchive streams) + Also added the filename being access to the stream_get_meta_data() array +Origin: http://svn.php.net/viewvc?view=revision&revision=306493 + +CVE-2011-1470 + +Patch differs from upstream commit in that it drops the added entry to +the NEWS file to reduce patch conflicts. + +Index: ext/zip/tests/bug53579.phpt +=================================================================== +--- ext/zip/tests/bug53579.phpt (revision 0) ++++ ext/zip/tests/bug53579.phpt (revision 306493) +@@ -0,0 +1,44 @@ ++--TEST-- ++Bug #53579 (stream_get_contents() segfaults on ziparchive streams) ++--SKIPIF-- ++ ++--FILE-- ++open($file)) { ++ exit('failed'); ++} ++$fp = $zip->getStream('foo'); ++ ++var_dump($fp); ++if(!$fp) exit("\n"); ++$contents = stream_get_contents($fp); ++ ++fclose($fp); ++$zip->close(); ++var_dump($contents); ++ ++ ++$fp = fopen('zip://' . dirname(__FILE__) . '/test_with_comment.zip#foo', 'rb'); ++if (!$fp) { ++ exit("cannot open\n"); ++} ++$contents = stream_get_contents($fp); ++var_dump($contents); ++fclose($fp); ++ ++?> ++--EXPECTF-- ++resource(%d) of type (stream) ++string(5) "foo ++ ++" ++string(5) "foo ++ ++" +Index: ext/zip/zip_stream.c +=================================================================== +--- ext/zip/zip_stream.c (revision 306492) ++++ ext/zip/zip_stream.c (revision 306493) +@@ -216,6 +216,7 @@ + self->stream = NULL; + self->cursor = 0; + stream = php_stream_alloc(&php_stream_zipio_ops, self, NULL, mode); ++ stream->orig_path = estrdup(path); + } else { + zip_close(stream_za); + } --- php5-5.2.10.dfsg.1.orig/debian/patches/php5-CVE-2009-5016.patch +++ php5-5.2.10.dfsg.1/debian/patches/php5-CVE-2009-5016.patch @@ -0,0 +1,22 @@ +Subject: This needs to be larger to avoid an overflow on the bit-shifting in this function +Origin: http://svn.php.net/viewvc/?view=revision&revision=287790 +Bug: http://bugs.php.net/bug.php?id=49687 +CVE-2009-5016 + +--- + ext/xml/xml.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +Index: b/ext/xml/xml.c +=================================================================== +--- a/ext/xml/xml.c ++++ b/ext/xml/xml.c +@@ -559,7 +559,7 @@ PHPAPI char *xml_utf8_decode(const XML_C + { + int pos = len; + char *newbuf = emalloc(len + 1); +- unsigned short c; ++ unsigned int c; + char (*decoder)(unsigned short) = NULL; + xml_encoding *enc = xml_get_encoding(encoding); + --- php5-5.2.10.dfsg.1.orig/debian/patches/php5-CVE-2010-3870.patch +++ php5-5.2.10.dfsg.1/debian/patches/php5-CVE-2010-3870.patch @@ -0,0 +1,204 @@ +Subject: utf8_decode vulnerabilities and deficiencies in the number + of reported malformed sequences. (Gustavo) +Origin: http://svn.php.net/viewvc/?view=revision&revision=304959 +Bug: http://bugs.php.net/bug.php?id=49687 + +[Ubuntu note: patch differs from above commit in that the NEWS entry has + been removed to reduce conflicts when applying - sbeattie] + +--- + ext/xml/tests/bug49687.phpt | 24 +++++++ + ext/xml/xml.c | 140 ++++++++++++++++++++++++++++++++++---------- + 2 files changed, 134 insertions(+), 30 deletions(-) + +Index: b/ext/xml/xml.c +=================================================================== +--- a/ext/xml/xml.c ++++ b/ext/xml/xml.c +@@ -659,10 +659,111 @@ PHPAPI char *xml_utf8_encode(const char + } + /* }}} */ + ++/* copied from trunk's implementation of get_next_char in ext/standard/html.c */ ++#define MB_FAILURE(pos, advance) do { \ ++ *cursor = pos + (advance); \ ++ *status = FAILURE; \ ++ return 0; \ ++} while (0) ++ ++#define CHECK_LEN(pos, chars_need) ((str_len - (pos)) >= (chars_need)) ++#define utf8_lead(c) ((c) < 0x80 || ((c) >= 0xC2 && (c) <= 0xF4)) ++#define utf8_trail(c) ((c) >= 0x80 && (c) <= 0xBF) ++ ++/* {{{ php_next_utf8_char ++ */ ++static inline unsigned int php_next_utf8_char( ++ const unsigned char *str, ++ size_t str_len, ++ size_t *cursor, ++ int *status) ++{ ++ size_t pos = *cursor; ++ unsigned int this_char = 0; ++ unsigned char c; ++ ++ *status = SUCCESS; ++ ++ if (!CHECK_LEN(pos, 1)) ++ MB_FAILURE(pos, 1); ++ ++ /* We'll follow strategy 2. from section 3.6.1 of UTR #36: ++ * "In a reported illegal byte sequence, do not include any ++ * non-initial byte that encodes a valid character or is a leading ++ * byte for a valid sequence. */ ++ c = str[pos]; ++ if (c < 0x80) { ++ this_char = c; ++ pos++; ++ } else if (c < 0xc2) { ++ MB_FAILURE(pos, 1); ++ } else if (c < 0xe0) { ++ if (!CHECK_LEN(pos, 2)) ++ MB_FAILURE(pos, 1); ++ ++ if (!utf8_trail(str[pos + 1])) { ++ MB_FAILURE(pos, utf8_lead(str[pos + 1]) ? 1 : 2); ++ } ++ this_char = ((c & 0x1f) << 6) | (str[pos + 1] & 0x3f); ++ if (this_char < 0x80) { /* non-shortest form */ ++ MB_FAILURE(pos, 2); ++ } ++ pos += 2; ++ } else if (c < 0xf0) { ++ size_t avail = str_len - pos; ++ ++ if (avail < 3 || ++ !utf8_trail(str[pos + 1]) || !utf8_trail(str[pos + 2])) { ++ if (avail < 2 || utf8_lead(str[pos + 1])) ++ MB_FAILURE(pos, 1); ++ else if (avail < 3 || utf8_lead(str[pos + 2])) ++ MB_FAILURE(pos, 2); ++ else ++ MB_FAILURE(pos, 3); ++ } ++ ++ this_char = ((c & 0x0f) << 12) | ((str[pos + 1] & 0x3f) << 6) | (str[pos + 2] & 0x3f); ++ if (this_char < 0x800) { /* non-shortest form */ ++ MB_FAILURE(pos, 3); ++ } else if (this_char >= 0xd800 && this_char <= 0xdfff) { /* surrogate */ ++ MB_FAILURE(pos, 3); ++ } ++ pos += 3; ++ } else if (c < 0xf5) { ++ size_t avail = str_len - pos; ++ ++ if (avail < 4 || ++ !utf8_trail(str[pos + 1]) || !utf8_trail(str[pos + 2]) || ++ !utf8_trail(str[pos + 3])) { ++ if (avail < 2 || utf8_lead(str[pos + 1])) ++ MB_FAILURE(pos, 1); ++ else if (avail < 3 || utf8_lead(str[pos + 2])) ++ MB_FAILURE(pos, 2); ++ else if (avail < 4 || utf8_lead(str[pos + 3])) ++ MB_FAILURE(pos, 3); ++ else ++ MB_FAILURE(pos, 4); ++ } ++ ++ this_char = ((c & 0x07) << 18) | ((str[pos + 1] & 0x3f) << 12) | ((str[pos + 2] & 0x3f) << 6) | (str[pos + 3] & 0x3f); ++ if (this_char < 0x10000 || this_char > 0x10FFFF) { /* non-shortest form or outside range */ ++ MB_FAILURE(pos, 4); ++ } ++ pos += 4; ++ } else { ++ MB_FAILURE(pos, 1); ++ } ++ ++ *cursor = pos; ++ return this_char; ++} ++/* }}} */ ++ ++ + /* {{{ xml_utf8_decode */ + PHPAPI char *xml_utf8_decode(const XML_Char *s, int len, int *newlen, const XML_Char *encoding) + { +- int pos = len; ++ size_t pos = 0; + char *newbuf = emalloc(len + 1); + unsigned int c; + char (*decoder)(unsigned short) = NULL; +@@ -681,36 +782,15 @@ PHPAPI char *xml_utf8_decode(const XML_C + newbuf[*newlen] = '\0'; + return newbuf; + } +- while (pos > 0) { +- c = (unsigned char)(*s); +- if (c >= 0xf0) { /* four bytes encoded, 21 bits */ +- if(pos-4 >= 0) { +- c = ((s[0]&7)<<18) | ((s[1]&63)<<12) | ((s[2]&63)<<6) | (s[3]&63); +- } else { +- c = '?'; +- } +- s += 4; +- pos -= 4; +- } else if (c >= 0xe0) { /* three bytes encoded, 16 bits */ +- if(pos-3 >= 0) { +- c = ((s[0]&63)<<12) | ((s[1]&63)<<6) | (s[2]&63); +- } else { +- c = '?'; +- } +- s += 3; +- pos -= 3; +- } else if (c >= 0xc0) { /* two bytes encoded, 11 bits */ +- if(pos-2 >= 0) { +- c = ((s[0]&63)<<6) | (s[1]&63); +- } else { +- c = '?'; +- } +- s += 2; +- pos -= 2; +- } else { +- s++; +- pos--; ++ ++ while (pos < (size_t)len) { ++ int status = FAILURE; ++ c = php_next_utf8_char((const unsigned char*)s, (size_t) len, &pos, &status); ++ ++ if (status == FAILURE || c > 0xFFU) { ++ c = '?'; + } ++ + newbuf[*newlen] = decoder ? decoder(c) : c; + ++*newlen; + } +Index: b/ext/xml/tests/bug49687.phpt +=================================================================== +--- /dev/null ++++ b/ext/xml/tests/bug49687.phpt +@@ -0,0 +1,24 @@ ++--TEST-- ++Bug #49687 Several utf8_decode deficiencies and vulnerabilities ++--SKIPIF-- ++ ++--FILE-- ++maxfd + 1, &curlstream->readfds, &curlstream->writefds, &curlstream->excfds, &tv)) { ++ switch ((curlstream->maxfd < 0) ? 1 : ++ select(curlstream->maxfd + 1, &curlstream->readfds, &curlstream->writefds, &curlstream->excfds, &tv)) { + case -1: + /* error */ + return 0; +@@ -180,7 +181,8 @@ static size_t php_curl_stream_read(php_s + curlstream->mcode = curl_multi_perform(curlstream->multi, &curlstream->pending); + } while (curlstream->mcode == CURLM_CALL_MULTI_PERFORM); + } +- } while (curlstream->readbuffer.readpos >= curlstream->readbuffer.writepos && curlstream->pending > 0); ++ } while (curlstream->maxfd >= 0 && ++ curlstream->readbuffer.readpos >= curlstream->readbuffer.writepos && curlstream->pending > 0); + + } + --- php5-5.2.10.dfsg.1.orig/debian/patches/013-force_getaddrinfo.patch +++ php5-5.2.10.dfsg.1/debian/patches/013-force_getaddrinfo.patch @@ -0,0 +1,96 @@ +--- php.orig/configure.in ++++ php/configure.in +@@ -601,50 +601,50 @@ vsnprintf \ + + dnl Check for getaddrinfo, should be a better way, but... + dnl Also check for working getaddrinfo +-AC_CACHE_CHECK([for getaddrinfo], ac_cv_func_getaddrinfo, +-[AC_TRY_LINK([#include ], +- [struct addrinfo *g,h;g=&h;getaddrinfo("","",g,&g);], +- AC_TRY_RUN([ +-#include +-#include +-#ifndef AF_INET +-# include +-#endif +-int main(void) { +- struct addrinfo *ai, *pai, hints; +- +- memset(&hints, 0, sizeof(hints)); +- hints.ai_flags = AI_NUMERICHOST; +- +- if (getaddrinfo("127.0.0.1", 0, &hints, &ai) < 0) { +- exit(1); +- } +- +- if (ai == 0) { +- exit(1); +- } +- +- pai = ai; +- +- while (pai) { +- if (pai->ai_family != AF_INET) { +- /* 127.0.0.1/NUMERICHOST should only resolve ONE way */ +- exit(1); +- } +- if (pai->ai_addr->sa_family != AF_INET) { +- /* 127.0.0.1/NUMERICHOST should only resolve ONE way */ +- exit(1); +- } +- pai = pai->ai_next; +- } +- freeaddrinfo(ai); +- exit(0); +-} +- ],ac_cv_func_getaddrinfo=yes, ac_cv_func_getaddrinfo=no, ac_cv_func_getaddrinfo=no), +-ac_cv_func_getaddrinfo=no)]) +-if test "$ac_cv_func_getaddrinfo" = yes; then ++dnl AC_CACHE_CHECK([for getaddrinfo], ac_cv_func_getaddrinfo, ++dnl [AC_TRY_LINK([#include ], ++dnl [struct addrinfo *g,h;g=&h;getaddrinfo("","",g,&g);], ++dnl AC_TRY_RUN([ ++dnl #include ++dnl #include ++dnl #ifndef AF_INET ++dnl # include ++dnl #endif ++dnl int main(void) { ++dnl struct addrinfo *ai, *pai, hints; ++dnl ++dnl memset(&hints, 0, sizeof(hints)); ++dnl hints.ai_flags = AI_NUMERICHOST; ++dnl ++dnl if (getaddrinfo("127.0.0.1", 0, &hints, &ai) < 0) { ++dnl exit(1); ++dnl } ++dnl ++dnl if (ai == 0) { ++dnl exit(1); ++dnl } ++dnl ++dnl pai = ai; ++dnl ++dnl while (pai) { ++dnl if (pai->ai_family != AF_INET) { ++dnl /* 127.0.0.1/NUMERICHOST should only resolve ONE way */ ++dnl exit(1); ++dnl } ++dnl if (pai->ai_addr->sa_family != AF_INET) { ++dnl /* 127.0.0.1/NUMERICHOST should only resolve ONE way */ ++dnl exit(1); ++dnl } ++dnl pai = pai->ai_next; ++dnl } ++dnl freeaddrinfo(ai); ++dnl exit(0); ++dnl } ++dnl ],ac_cv_func_getaddrinfo=yes, ac_cv_func_getaddrinfo=no, ac_cv_func_getaddrinfo=no), ++dnl ac_cv_func_getaddrinfo=no)]) ++dnl if test "$ac_cv_func_getaddrinfo" = yes; then + AC_DEFINE(HAVE_GETADDRINFO,1,[Define if you have the getaddrinfo function]) +-fi ++dnl fi + + AC_REPLACE_FUNCS(strlcat strlcpy getopt) + AC_FUNC_UTIME_NULL --- php5-5.2.10.dfsg.1.orig/debian/patches/php5-CVE-2010-3436-regression.patch +++ php5-5.2.10.dfsg.1/debian/patches/php5-CVE-2010-3436-regression.patch @@ -0,0 +1,32 @@ +Subject: fix regression introduced by fix for CVE-2010-3436 +Origin: http://svn.php.net/viewvc?view=revision&revision=305698 +Bug: http://bugs.php.net/bug.php?id=53352 +Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/ntp/+bug/701896 + +--- + main/fopen_wrappers.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +Index: b/main/fopen_wrappers.c +=================================================================== +--- a/main/fopen_wrappers.c ++++ b/main/fopen_wrappers.c +@@ -223,6 +223,9 @@ PHPAPI int php_check_specific_open_based + resolved_basedir[resolved_basedir_len] = PHP_DIR_SEPARATOR; + resolved_basedir[++resolved_basedir_len] = '\0'; + } ++ } else { ++ resolved_basedir[resolved_basedir_len++] = PHP_DIR_SEPARATOR; ++ resolved_basedir[resolved_basedir_len] = '\0'; + } + + resolved_name_len = strlen(resolved_name); +@@ -240,7 +243,7 @@ PHPAPI int php_check_specific_open_based + if (strncmp(resolved_basedir, resolved_name, resolved_basedir_len) == 0) { + #endif + if (resolved_name_len > resolved_basedir_len && +- resolved_name[resolved_basedir_len] != PHP_DIR_SEPARATOR) { ++ resolved_name[resolved_basedir_len - 1] != PHP_DIR_SEPARATOR) { + return -1; + } else { + /* File is in the right directory */ --- php5-5.2.10.dfsg.1.orig/debian/patches/CVE-2010-1917.patch +++ php5-5.2.10.dfsg.1/debian/patches/CVE-2010-1917.patch @@ -0,0 +1,17 @@ +Description: fix denial of service via fnmatch stack consumption +Origin: upstream, http://svn.php.net/viewvc?view=revision&revision=298881 + +diff -Nur php5-5.2.10.dfsg.1/ext/standard/file.c php5-5.2.10.dfsg.1.new/ext/standard/file.c +--- php5-5.2.10.dfsg.1/ext/standard/file.c 2010-09-14 14:38:31.000000000 -0400 ++++ php5-5.2.10.dfsg.1.new/ext/standard/file.c 2010-09-14 14:38:36.000000000 -0400 +@@ -2568,6 +2568,10 @@ + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Filename exceeds the maximum allowed length of %d characters", MAXPATHLEN); + RETURN_FALSE; + } ++ if (pattern_len >= MAXPATHLEN) { ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Pattern exceeds the maximum allowed length of %d characters", MAXPATHLEN); ++ RETURN_FALSE; ++ } + + RETURN_BOOL( ! fnmatch( pattern, filename, flags )); + } --- php5-5.2.10.dfsg.1.orig/debian/patches/044-strtod_arm_fix.patch +++ php5-5.2.10.dfsg.1/debian/patches/044-strtod_arm_fix.patch @@ -0,0 +1,54 @@ +--- php.orig/Zend/zend_strtod.c ++++ php/Zend/zend_strtod.c +@@ -152,14 +152,25 @@ typedef unsigned long int uint32_t; + #define IEEE_LITTLE_ENDIAN + #endif + +-#if defined(__arm__) && !defined(__VFP_FP__) +-/* +- * * Although the CPU is little endian the FP has different +- * * byte and word endianness. The byte order is still little endian +- * * but the word order is big endian. +- * */ +-#define IEEE_BIG_ENDIAN ++#if defined(__arm__) || defined(__thumb__) ++/* ARM traditionally used big-endian words; and within those words the ++ byte ordering was big or little endian depending upon the target. ++ Modern floating-point formats are naturally ordered; in this case ++ __VFP_FP__ will be defined, even if soft-float. */ + #undef IEEE_LITTLE_ENDIAN ++#undef IEEE_BIG_ENDIAN ++#if defined(__VFP_FP__) || defined(__MAVERICK__) ++# ifdef __ARMEL__ ++# define IEEE_LITTLE_ENDIAN ++# else ++# define IEEE_BIG_ENDIAN ++# endif ++#else ++# define IEEE_BIG_ENDIAN ++# ifdef __ARMEL__ ++# define IEEE_BYTES_LITTLE_ENDIAN ++# endif ++#endif + #endif + + #ifdef __vax__ +@@ -266,8 +277,7 @@ BEGIN_EXTERN_C() + + #if defined(IEEE_LITTLE_ENDIAN) + defined(IEEE_BIG_ENDIAN) + defined(VAX) + \ + defined(IBM) != 1 +- Exactly one of IEEE_LITTLE_ENDIAN IEEE_BIG_ENDIAN, VAX, or +- IBM should be defined. ++#error "Exactly one of IEEE_LITTLE_ENDIAN IEEE_BIG_ENDIAN, VAX, or IBM should be defined." + #endif + + typedef union { +@@ -287,7 +297,7 @@ BEGIN_EXTERN_C() + * An alternative that might be better on some machines is + * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff) + */ +-#if defined(IEEE_LITTLE_ENDIAN) + defined(VAX) + defined(__arm__) ++#if defined(IEEE_LITTLE_ENDIAN) + defined(VAX) + defined(IEEE_BYTES_LITTLE_ENDIAN) + #define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \ + ((unsigned short *)a)[0] = (unsigned short)c, a++) + #else --- php5-5.2.10.dfsg.1.orig/debian/patches/CVE-2009-4018.patch +++ php5-5.2.10.dfsg.1/debian/patches/CVE-2009-4018.patch @@ -0,0 +1,50 @@ +Description: fix safe_mode_protected_env_vars bypass via proc_open() +upstream, Origin: http://svn.php.net/viewvc/?view=revision&revision=286360 +Bug: http://bugs.php.net/bug.php?id=49026 + +diff -Nur php5-5.2.10.dfsg.1/ext/standard/proc_open.c php5-5.2.10.dfsg.1.new/ext/standard/proc_open.c +--- php5-5.2.10.dfsg.1/ext/standard/proc_open.c 2009-11-24 15:18:22.000000000 -0500 ++++ php5-5.2.10.dfsg.1.new/ext/standard/proc_open.c 2009-11-24 15:18:30.000000000 -0500 +@@ -30,6 +30,7 @@ + #include "php_string.h" + #include "safe_mode.h" + #include "ext/standard/head.h" ++#include "ext/standard/basic_functions.h" + #include "ext/standard/file.h" + #include "exec.h" + #include "php_globals.h" +@@ -152,6 +153,34 @@ + if (string_length == 0) { + continue; + } ++ if (PG(safe_mode)) { ++ /* Check the protected list */ ++ if (zend_hash_exists(&BG(sm_protected_env_vars), string_key, string_length - 1)) { ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Safe Mode warning: Cannot override protected environment variable '%s'", string_key); ++ return env; ++ } ++ /* Check the allowed list */ ++ if (BG(sm_allowed_env_vars) && *BG(sm_allowed_env_vars)) { ++ char *allowed_env_vars = estrdup(BG(sm_allowed_env_vars)); ++ char *strtok_buf = NULL; ++ char *allowed_prefix = php_strtok_r(allowed_env_vars, ", ", &strtok_buf); ++ zend_bool allowed = 0; ++ ++ while (allowed_prefix) { ++ if (!strncmp(allowed_prefix, string_key, strlen(allowed_prefix))) { ++ allowed = 1; ++ break; ++ } ++ allowed_prefix = php_strtok_r(NULL, ", ", &strtok_buf); ++ } ++ efree(allowed_env_vars); ++ if (!allowed) { ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Safe Mode warning: Cannot set environment variable '%s' - it's not in the allowed list", string_key); ++ return env; ++ } ++ } ++ } ++ + l = string_length + el_len + 1; + memcpy(p, string_key, string_length); + strcat(p, "="); --- php5-5.2.10.dfsg.1.orig/debian/patches/php5-pear-CVE-2011-1072.patch +++ php5-5.2.10.dfsg.1/debian/patches/php5-pear-CVE-2011-1072.patch @@ -0,0 +1,713 @@ +Subject: Fixed Bug #18056 [SECURITY]: Symlink attack in PEAR install [dufuz] +Origin: http://svn.php.net/viewvc?view=revision&revision=308687 + +This feature is implemented as a result of the above fix +* Implemented Request #16648: Use TMPDIR for builds instead of /var/tmp [dufuz] + +CVE-2011-1072 + +This patch differs from the upstream commit in that the packages.xml +and packages2.xml edits containing only information about the commits +were removed to reduce conflicts. + +Index: PEAR/PackageFile.php +=================================================================== +--- PEAR/PackageFile.php (revision 308686) ++++ PEAR/PackageFile.php (revision 308687) +@@ -46,11 +46,7 @@ + */ + var $_config; + var $_debug; +- /** +- * Temp directory for uncompressing tgz files. +- * @var string|false +- */ +- var $_tmpdir; ++ + var $_logger = false; + /** + * @var boolean +@@ -58,17 +54,23 @@ + var $_rawReturn = false; + + /** ++ * helper for extracting Archive_Tar errors ++ * @var array ++ * @access private ++ */ ++ var $_extractErrors = array(); ++ ++ /** + * + * @param PEAR_Config $config + * @param ? $debug + * @param string @tmpdir Optional temporary directory for uncompressing + * files + */ +- function PEAR_PackageFile(&$config, $debug = false, $tmpdir = false) ++ function PEAR_PackageFile(&$config, $debug = false) + { + $this->_config = $config; + $this->_debug = $debug; +- $this->_tmpdir = $tmpdir; + } + + /** +@@ -349,20 +351,17 @@ + } + } + +- if ($this->_tmpdir) { +- $tmpdir = $this->_tmpdir; +- } else { +- $tmpdir = System::mkTemp(array('-t', $this->_config->get('temp_dir'), '-d', 'pear')); +- if ($tmpdir === false) { +- $ret = PEAR::raiseError("there was a problem with getting the configured temp directory"); +- return $ret; +- } +- +- PEAR_PackageFile::addTempFile($tmpdir); ++ $tmpdir = System::mktemp('-t ' . $this->_config->get('temp_dir') . ' -d pear'); ++ if ($tmpdir === false) { ++ $ret = PEAR::raiseError("there was a problem with getting the configured temp directory"); ++ return $ret; + } + ++ PEAR_PackageFile::addTempFile($tmpdir); ++ + $this->_extractErrors(); + PEAR::staticPushErrorHandling(PEAR_ERROR_CALLBACK, array($this, '_extractErrors')); ++ + if (!$xml || !$tar->extractList(array($xml), $tmpdir)) { + $extra = implode("\n", $this->_extractErrors()); + if ($extra) { +@@ -381,13 +380,6 @@ + } + + /** +- * helper for extracting Archive_Tar errors +- * @var array +- * @access private +- */ +- var $_extractErrors = array(); +- +- /** + * helper callback for extracting Archive_Tar errors + * + * @param PEAR_Error|null $err +Index: PEAR/Installer.php +=================================================================== +--- PEAR/Installer.php (revision 308686) ++++ PEAR/Installer.php (revision 308687) +@@ -1036,25 +1036,10 @@ + // }}} + // {{{ _parsePackageXml() + +- function _parsePackageXml(&$descfile, &$tmpdir) ++ function _parsePackageXml(&$descfile) + { +- 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); ++ $pkg = new PEAR_PackageFile($this->config, $this->debug); + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $p = &$pkg->fromAnyFile($descfile, PEAR_VALIDATE_INSTALLING); + PEAR::staticPopErrorHandling(); +@@ -1135,17 +1120,20 @@ + $pkg = $pkgfile->getPackageFile(); + $pkgfile = $pkg->getArchiveFile(); + $descfile = $pkg->getPackageFile(); +- $tmpdir = dirname($descfile); + } else { + $descfile = $pkgfile; +- $tmpdir = ''; +- $pkg = $this->_parsePackageXml($descfile, $tmpdir); ++ $pkg = $this->_parsePackageXml($descfile); + if (PEAR::isError($pkg)) { + return $pkg; + } + } + ++ $tmpdir = dirname($descfile); + if (realpath($descfile) != realpath($pkgfile)) { ++ // Use the temp_dir since $descfile can contain the download dir path ++ $tmpdir = $this->config->get('temp_dir', null, 'pear.php.net'); ++ $tmpdir = System::mktemp("-d -t $tmpdir"); ++ + $tar = new Archive_Tar($pkgfile); + if (!$tar->extract($tmpdir)) { + return $this->raiseError("unable to unpack $pkgfile"); +@@ -1373,9 +1361,8 @@ + } + } + +- $tmp_path = dirname($descfile); + if (substr($pkgfile, -4) != '.xml') { +- $tmp_path .= DIRECTORY_SEPARATOR . $pkgname . '-' . $pkg->getVersion(); ++ $tmpdir .= DIRECTORY_SEPARATOR . $pkgname . '-' . $pkg->getVersion(); + } + + $this->configSet('default_channel', $channel); +@@ -1401,9 +1388,9 @@ + foreach ($filelist as $file => $atts) { + $this->expectError(PEAR_INSTALLER_FAILED); + if ($pkg->getPackagexmlVersion() == '1.0') { +- $res = $this->_installFile($file, $atts, $tmp_path, $options); ++ $res = $this->_installFile($file, $atts, $tmpdir, $options); + } else { +- $res = $this->_installFile2($pkg, $file, $atts, $tmp_path, $options); ++ $res = $this->_installFile2($pkg, $file, $atts, $tmpdir, $options); + } + $this->popExpect(); + +Index: PEAR/Downloader.php +=================================================================== +--- PEAR/Downloader.php (revision 308686) ++++ PEAR/Downloader.php (revision 308687) +@@ -189,7 +189,8 @@ + require_once 'System.php'; + } + +- $tmp = System::mktemp(array('-d')); ++ $tmpdir = $this->config->get('temp_dir'); ++ $tmp = System::mktemp("-d -t $tmpdir"); + $a = $this->downloadHttp('http://' . $channel . '/channel.xml', $this->ui, $tmp, $callback, false); + PEAR::popErrorHandling(); + if (PEAR::isError($a)) { +@@ -493,14 +494,13 @@ + */ + function analyzeDependencies(&$params, $force = false) + { +- $hasfailed = $failed = false; + if (isset($this->_options['downloadonly'])) { + return; + } + + PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); + $redo = true; +- $reset = false; ++ $reset = $hasfailed = $failed = false; + while ($redo) { + $redo = false; + foreach ($params as $i => $param) { +@@ -698,6 +698,7 @@ + } + } + } ++ + PEAR::staticPopErrorHandling(); + if ($hasfailed && (isset($this->_options['ignore-errors']) || + isset($this->_options['nodeps']))) { +@@ -718,6 +719,7 @@ + if (isset($this->_downloadDir)) { + return $this->_downloadDir; + } ++ + $downloaddir = $this->config->get('download_dir'); + if (empty($downloaddir) || (is_dir($downloaddir) && !is_writable($downloaddir))) { + if (is_dir($downloaddir) && !is_writable($downloaddir)) { +@@ -725,14 +727,17 @@ + '" is not writeable. Change download_dir config variable to ' . + 'a writeable dir to avoid this warning'); + } ++ + if (!class_exists('System')) { + require_once 'System.php'; + } ++ + if (PEAR::isError($downloaddir = System::mktemp('-d'))) { + return $downloaddir; + } + $this->log(3, '+ tmp dir created at ' . $downloaddir); + } ++ + if (!is_writable($downloaddir)) { + if (PEAR::isError(System::mkdir(array('-p', $downloaddir))) || + !is_writable($downloaddir)) { +@@ -741,6 +746,7 @@ + 'a writeable dir'); + } + } ++ + return $this->_downloadDir = $downloaddir; + } + +@@ -771,27 +777,11 @@ + $this->_options = $options; + } + +- // }}} +- // {{{ setOptions() + function getOptions() + { + return $this->_options; + } + +- /** +- * For simpler unit-testing +- * @param PEAR_Config +- * @param int +- * @param string +- */ +- function &getPackagefileObject(&$c, $d, $t = false) +- { +- if (!class_exists('PEAR_PackageFile')) { +- require_once 'PEAR/PackageFile.php'; +- } +- $a = &new PEAR_PackageFile($c, $d, $t); +- return $a; +- } + + /** + * @param array output of {@link parsePackageName()} +@@ -1000,9 +990,20 @@ + } + return $info; + } elseif ($chan->supportsREST($this->config->get('preferred_mirror')) +- && $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror')) ++ && ++ ( ++ ($base2 = $chan->getBaseURL('REST1.3', $this->config->get('preferred_mirror'))) ++ || ++ ($base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) ++ ) + ) { +- $rest = &$this->config->getREST('1.0', $this->_options); ++ if ($base2) { ++ $base = $base2; ++ $rest = &$this->config->getREST('1.3', $this->_options); ++ } else { ++ $rest = &$this->config->getREST('1.0', $this->_options); ++ } ++ + $url = $rest->getDepDownloadURL($base, $xsdversion, $dep, $parr, + $state, $version, $chan->getName()); + if (PEAR::isError($url)) { +@@ -1707,6 +1708,10 @@ + } + + $dest_file = $save_dir . DIRECTORY_SEPARATOR . $save_as; ++ if (is_link($dest_file)) { ++ return PEAR::raiseError('SECURITY ERROR: Will not write to ' . $dest_file . ' as it is symlinked to ' . readlink($dest_file) . ' - Possible symlink attack'); ++ } ++ + if (!$wp = @fopen($dest_file, 'wb')) { + fclose($fp); + if ($callback) { +@@ -1758,5 +1763,4 @@ + } + return $dest_file; + } +-} +-// }}} +\ No newline at end of file ++} +\ No newline at end of file +Index: PEAR/Downloader/Package.php +=================================================================== +--- PEAR/Downloader/Package.php (revision 308686) ++++ PEAR/Downloader/Package.php (revision 308687) +@@ -1376,6 +1376,8 @@ + continue; + } + ++ // FIXME do symlink check ++ + fwrite($fp, $filecontents, strlen($filecontents)); + fclose($fp); + if ($s = $params[$i]->explicitState()) { +@@ -1497,13 +1499,12 @@ + * @param int + * @param string + */ +- function &getPackagefileObject(&$c, $d, $t = false) ++ function &getPackagefileObject(&$c, $d) + { +- $a = &new PEAR_PackageFile($c, $d, $t); ++ $a = &new PEAR_PackageFile($c, $d); + return $a; + } + +- + /** + * This will retrieve from a local file if possible, and parse out + * a group name as well. The original parameter will be modified to reflect this. +@@ -1527,16 +1528,7 @@ + if (@is_file($param)) { + $this->_type = 'local'; + $options = $this->_downloader->getOptions(); +- if (isset($options['downloadonly'])) { +- $pkg = &$this->getPackagefileObject($this->_config, +- $this->_downloader->_debug); +- } else { +- if (PEAR::isError($dir = $this->_downloader->getDownloadDir())) { +- return $dir; +- } +- $pkg = &$this->getPackagefileObject($this->_config, +- $this->_downloader->_debug, $dir); +- } ++ $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->_debug); + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $pf = &$pkg->fromAnyFile($param, PEAR_VALIDATE_INSTALLING); + PEAR::popErrorHandling(); +@@ -1608,15 +1600,7 @@ + } + + // whew, download worked! +- if (isset($options['downloadonly'])) { +- $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->debug); +- } else { +- $dir = $this->_downloader->getDownloadDir(); +- if (PEAR::isError($dir)) { +- return $dir; +- } +- $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->debug, $dir); +- } ++ $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->debug); + + PEAR::pushErrorHandling(PEAR_ERROR_RETURN); + $pf = &$pkg->fromAnyFile($file, PEAR_VALIDATE_INSTALLING); +Index: PEAR/REST.php +=================================================================== +--- PEAR/REST.php (revision 308686) ++++ PEAR/REST.php (revision 308687) +@@ -100,7 +100,10 @@ + $ret = $this->getCache($url); + if (!PEAR::isError($ret) && $trieddownload) { + // reset the age of the cache if the server says it was unmodified +- $this->saveCache($url, $ret, null, true, $cacheId); ++ $result = $this->saveCache($url, $ret, null, true, $cacheId); ++ if (PEAR::isError($result)) { ++ return PEAR::raiseErro($result->getMessage()); ++ } + } + + return $ret; +@@ -117,7 +120,11 @@ + } + + if ($forcestring) { +- $this->saveCache($url, $content, $lastmodified, false, $cacheId); ++ $result = $this->saveCache($url, $content, $lastmodified, false, $cacheId); ++ if (PEAR::isError($result)) { ++ return PEAR::raiseErro($result->getMessage()); ++ } ++ + return $content; + } + +@@ -153,7 +160,11 @@ + $content = $parser->getData(); + } + +- $this->saveCache($url, $content, $lastmodified, false, $cacheId); ++ $result = $this->saveCache($url, $content, $lastmodified, false, $cacheId); ++ if (PEAR::isError($result)) { ++ return PEAR::raiseErro($result->getMessage()); ++ } ++ + return $content; + } + +@@ -212,57 +223,65 @@ + */ + function saveCache($url, $contents, $lastmodified, $nochange = false, $cacheid = null) + { +- $cachedir = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR . md5($url); +- $cacheidfile = $cachedir . 'rest.cacheid'; +- $cachefile = $cachedir . 'rest.cachefile'; ++ $cache_dir = $this->config->get('cache_dir'); ++ $d = $cache_dir . DIRECTORY_SEPARATOR . md5($url); ++ $cacheidfile = $d . 'rest.cacheid'; ++ $cachefile = $d . 'rest.cachefile'; + + if ($cacheid === null && $nochange) { + $cacheid = unserialize(implode('', file($cacheidfile))); + } + +- $fp = @fopen($cacheidfile, 'wb'); +- if (!$fp) { +- $cache_dir = $this->config->get('cache_dir'); ++ if (is_link($cacheidfile)) { ++ return PEAR::raiseError('SECURITY ERROR: Will not write to ' . $cacheidfile . ' as it is symlinked to ' . readlink($cacheidfile) . ' - Possible symlink attack'); ++ } ++ ++ if (is_link($cachefile)) { ++ return PEAR::raiseError('SECURITY ERROR: Will not write to ' . $cacheidfile . ' as it is symlinked to ' . readlink($cacheidfile) . ' - Possible symlink attack'); ++ } ++ ++ $cacheidfile_fp = @fopen($cacheidfile, 'wb'); ++ if (!$cacheidfile_fp) { + if (is_dir($cache_dir)) { +- return false; ++ return PEAR::raiseError("The value of config option cache_dir ($cache_dir) is not a directory. "); + } + + System::mkdir(array('-p', $cache_dir)); +- $fp = @fopen($cacheidfile, 'wb'); +- if (!$fp) { +- return false; ++ $cacheidfile_fp = @fopen($cacheidfile, 'wb'); ++ if (!$cacheidfile_fp) { ++ return PEAR::raiseError("Could not open $cacheidfile for writing."); + } + } + + if ($nochange) { +- fwrite($fp, serialize(array( ++ fwrite($cacheidfile_fp, serialize(array( + 'age' => time(), + 'lastChange' => $cacheid['lastChange'], + )) + ); + +- fclose($fp); ++ fclose($cacheidfile_fp); + return true; + } + +- fwrite($fp, serialize(array( ++ fwrite($cacheidfile_fp, serialize(array( + 'age' => time(), + 'lastChange' => $lastmodified, + )) + ); ++ fclose($cacheidfile_fp); + +- fclose($fp); +- $fp = @fopen($cachefile, 'wb'); +- if (!$fp) { ++ $cachefile_fp = @fopen($cachefile, 'wb'); ++ if (!$cachefile_fp) { + if (file_exists($cacheidfile)) { + @unlink($cacheidfile); + } + +- return false; ++ return PEAR::raiseError("Could not open $cacheidfile for writing."); + } + +- fwrite($fp, serialize($contents)); +- fclose($fp); ++ fwrite($cachefile_fp, serialize($contents)); ++ fclose($cachefile_fp); + return true; + } + +Index: PEAR/Builder.php +=================================================================== +--- PEAR/Builder.php (revision 308686) ++++ PEAR/Builder.php (revision 308687) +@@ -220,7 +220,7 @@ + /** + * Build an extension from source. Runs "phpize" in the source + * directory, but compiles in a temporary directory +- * (/var/tmp/pear-build-USER/PACKAGE-VERSION). ++ * (TMPDIR/pear-build-USER/PACKAGE-VERSION). + * + * @param string|PEAR_PackageFile_v* $descfile path to XML package description file, or + * a PEAR_PackageFile object +@@ -250,6 +250,7 @@ + ' appears to have a prefix ' . $matches[2] . ', but' . + ' config variable php_prefix does not match'); + } ++ + if (isset($matches[3]) && strlen($matches[3]) && + trim($matches[3]) != trim($this->config->get('php_suffix'))) { + $this->log(0, 'WARNING: php_bin ' . $this->config->get('php_bin') . +@@ -258,14 +259,15 @@ + } + } + +- + $this->current_callback = $callback; + if (PEAR_OS == "Windows") { + return $this->_build_win32($descfile, $callback); + } ++ + if (PEAR_OS != 'Unix') { + return $this->raiseError("building extensions not supported on this platform"); + } ++ + if (is_object($descfile)) { + $pkg = $descfile; + $descfile = $pkg->getPackageFile(); +@@ -284,14 +286,17 @@ + } + $dir = dirname($descfile); + } ++ + $old_cwd = getcwd(); + if (!file_exists($dir) || !is_dir($dir) || !chdir($dir)) { + return $this->raiseError("could not chdir to $dir"); + } ++ + $vdir = $pkg->getPackage() . '-' . $pkg->getVersion(); + if (is_dir($vdir)) { + chdir($vdir); + } ++ + $dir = getcwd(); + $this->log(2, "building in $dir"); + putenv('PATH=' . $this->config->get('bin_dir') . ':' . getenv('PATH')); +@@ -302,6 +307,7 @@ + if (PEAR::isError($err)) { + return $err; + } ++ + if (!$err) { + return $this->raiseError("`phpize' failed"); + } +@@ -327,30 +333,31 @@ + // }}} end of interactive part + + // FIXME make configurable +- if(!$user=getenv('USER')){ ++ if (!$user=getenv('USER')) { + $user='defaultuser'; + } +- $build_basedir = "/var/tmp/pear-build-$user"; ++ ++ $tmpdir = $this->config->get('temp_dir'); ++ $build_basedir = System::mktemp(" -t $tmpdir -d pear-build-$user"); + $build_dir = "$build_basedir/$vdir"; + $inst_dir = "$build_basedir/install-$vdir"; + $this->log(1, "building in $build_dir"); + if (is_dir($build_dir)) { + System::rm(array('-rf', $build_dir)); + } ++ + if (!System::mkDir(array('-p', $build_dir))) { + return $this->raiseError("could not create build dir: $build_dir"); + } ++ + $this->addTempFile($build_dir); + if (!System::mkDir(array('-p', $inst_dir))) { + return $this->raiseError("could not create temporary install dir: $inst_dir"); + } + $this->addTempFile($inst_dir); + +- if (getenv('MAKE')) { +- $make_command = getenv('MAKE'); +- } else { +- $make_command = 'make'; +- } ++ $make_command = getenv('MAKE') ? getenv('MAKE') : 'make'; ++ + $to_run = array( + $configure_command, + $make_command, +Index: PEAR/Command/Remote.php +=================================================================== +--- PEAR/Command/Remote.php (revision 308686) ++++ PEAR/Command/Remote.php (revision 308687) +@@ -144,7 +144,7 @@ + 'shortcut' => 'cc', + 'options' => array(), + 'doc' => ' +-Clear the XML-RPC/REST cache. See also the cache_ttl configuration ++Clear the REST cache. See also the cache_ttl configuration + parameter. + ', + ), +@@ -776,6 +776,7 @@ + if ($verbose >= 1) { + $output .= "reading directory $cache_dir\n"; + } ++ + $num = 0; + while ($ent = readdir($dp)) { + if (preg_match('/rest.cache(file|id)\\z/', $ent)) { +Index: PEAR/Command/Package.php +=================================================================== +--- PEAR/Command/Package.php (revision 308686) ++++ PEAR/Command/Package.php (revision 308687) +@@ -314,7 +314,7 @@ + return $a; + } + +- function &getPackageFile($config, $debug = false, $tmpdir = null) ++ function &getPackageFile($config, $debug = false) + { + if (!class_exists('PEAR_Common')) { + require_once 'PEAR/Common.php'; +@@ -322,7 +322,7 @@ + if (!class_exists('PEAR_PackageFile')) { + require_once 'PEAR/PackageFile.php'; + } +- $a = &new PEAR_PackageFile($config, $debug, $tmpdir); ++ $a = &new PEAR_PackageFile($config, $debug); + $common = new PEAR_Common; + $common->ui = $this->ui; + $a->setLogger($common); +@@ -969,7 +969,9 @@ + } + + $tar = new Archive_Tar($params[0]); +- $tmpdir = System::mktemp('-d pearsign'); ++ ++ $tmpdir = $this->config->get('temp_dir'); ++ $tmpdir = System::mktemp(" -t $tmpdir -d pearsign"); + if (!$tar->extractList('package2.xml package.xml package.sig', $tmpdir)) { + return $this->raiseError("failed to extract tar file"); + } +Index: PEAR/Command/Install.php +=================================================================== +--- PEAR/Command/Install.php (revision 308686) ++++ PEAR/Command/Install.php (revision 308687) +@@ -730,7 +730,8 @@ + if ($param->getPackageType() == 'extsrc' || + $param->getPackageType() == 'extbin' || + $param->getPackageType() == 'zendextsrc' || +- $param->getPackageType() == 'zendextbin') { ++ $param->getPackageType() == 'zendextbin' ++ ) { + $pkg = &$param->getPackageFile(); + if ($instbin = $pkg->getInstalledBinary()) { + $instpkg = &$instreg->getPackage($instbin, $pkg->getChannel()); +@@ -741,7 +742,8 @@ + foreach ($instpkg->getFilelist() as $name => $atts) { + $pinfo = pathinfo($atts['installed_as']); + if (!isset($pinfo['extension']) || +- in_array($pinfo['extension'], array('c', 'h'))) { ++ in_array($pinfo['extension'], array('c', 'h')) ++ ) { + continue; // make sure we don't match php_blah.h + } + +Index: PEAR/Command/Pickle.php +=================================================================== +--- PEAR/Command/Pickle.php (revision 308686) ++++ PEAR/Command/Pickle.php (revision 308687) +@@ -104,7 +104,7 @@ + * @param string|null $tmpdir + * @return PEAR_PackageFile + */ +- function &getPackageFile($config, $debug = false, $tmpdir = null) ++ function &getPackageFile($config, $debug = false) + { + if (!class_exists('PEAR_Common')) { + require_once 'PEAR/Common.php'; +@@ -114,7 +114,7 @@ + require_once 'PEAR/PackageFile.php'; + } + +- $a = &new PEAR_PackageFile($config, $debug, $tmpdir); ++ $a = &new PEAR_PackageFile($config, $debug); + $common = new PEAR_Common; + $common->ui = $this->ui; + $a->setLogger($common); --- php5-5.2.10.dfsg.1.orig/debian/patches/CVE-2010-0397.patch +++ php5-5.2.10.dfsg.1/debian/patches/CVE-2010-0397.patch @@ -0,0 +1,56 @@ +Description: fix denial of service via xmlrpc crafted argument +Origin: upstream, http://svn.php.net/viewvc?view=revision&revision=296152 +Origin: upstream, http://svn.php.net/viewvc?view=revision&revision=296153 +Bug: http://bugs.php.net/bug.php?id=51288 +Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=573573 + +diff -Nur php5-5.2.10.dfsg.1/ext/xmlrpc/tests/bug51288.phpt php5-5.2.10.dfsg.1.new/ext/xmlrpc/tests/bug51288.phpt +--- php5-5.2.10.dfsg.1/ext/xmlrpc/tests/bug51288.phpt 1969-12-31 19:00:00.000000000 -0500 ++++ php5-5.2.10.dfsg.1.new/ext/xmlrpc/tests/bug51288.phpt 2010-09-14 14:36:18.000000000 -0400 +@@ -0,0 +1,14 @@ ++--TEST-- ++Bug #51288 (CVE-2010-0397, NULL pointer deref when no in request) ++--FILE-- ++'; ++var_dump(xmlrpc_decode_request($req, $method)); ++var_dump($method); ++echo "Done\n"; ++?> ++--EXPECT-- ++NULL ++NULL ++Done +diff -Nur php5-5.2.10.dfsg.1/ext/xmlrpc/xmlrpc-epi-php.c php5-5.2.10.dfsg.1.new/ext/xmlrpc/xmlrpc-epi-php.c +--- php5-5.2.10.dfsg.1/ext/xmlrpc/xmlrpc-epi-php.c 2009-05-22 08:50:44.000000000 -0400 ++++ php5-5.2.10.dfsg.1.new/ext/xmlrpc/xmlrpc-epi-php.c 2010-09-14 14:36:03.000000000 -0400 +@@ -702,6 +702,7 @@ + zval* retval = NULL; + XMLRPC_REQUEST response; + STRUCT_XMLRPC_REQUEST_INPUT_OPTIONS opts = {{0}}; ++ const char *method_name; + opts.xml_elem_opts.encoding = encoding_in ? utf8_get_encoding_id_from_string(Z_STRVAL_P(encoding_in)) : ENCODING_DEFAULT; + + /* generate XMLRPC_REQUEST from raw xml */ +@@ -712,10 +713,16 @@ + + if(XMLRPC_RequestGetRequestType(response) == xmlrpc_request_call) { + if(method_name_out) { +- zval_dtor(method_name_out); +- Z_TYPE_P(method_name_out) = IS_STRING; +- Z_STRVAL_P(method_name_out) = estrdup(XMLRPC_RequestGetMethodName(response)); +- Z_STRLEN_P(method_name_out) = strlen(Z_STRVAL_P(method_name_out)); ++ method_name = XMLRPC_RequestGetMethodName(response); ++ if (method_name) { ++ zval_dtor(method_name_out); ++ Z_TYPE_P(method_name_out) = IS_STRING; ++ Z_STRVAL_P(method_name_out) = estrdup(method_name); ++ Z_STRLEN_P(method_name_out) = strlen(Z_STRVAL_P(method_name_out)); ++ } else if (retval) { ++ zval_ptr_dtor(&retval); ++ retval = NULL; ++ } + } + } + --- php5-5.2.10.dfsg.1.orig/debian/patches/CVE-2009-4143.patch +++ php5-5.2.10.dfsg.1/debian/patches/CVE-2009-4143.patch @@ -0,0 +1,30 @@ +Description: fix restrictions bypass via incorrect session data handling +Origin: upstream, http://svn.php.net/viewvc?view=revision&revision=291681 + +diff -Nur php5-5.2.10.dfsg.1/ext/session/session.c php5-5.2.10.dfsg.1.new/ext/session/session.c +--- php5-5.2.10.dfsg.1/ext/session/session.c 2010-01-05 13:13:33.000000000 -0500 ++++ php5-5.2.10.dfsg.1.new/ext/session/session.c 2010-01-05 13:13:40.000000000 -0500 +@@ -1823,7 +1823,10 @@ + } + + IF_SESSION_VARS() { +- HashTable *ht = Z_ARRVAL_P(PS(http_session_vars)); ++ HashTable *ht; ++ ++ SEPARATE_ZVAL_IF_NOT_REF(&PS(http_session_vars)); ++ ht = Z_ARRVAL_P(PS(http_session_vars)); + + if (PG(register_globals)) { + uint str_len; +@@ -1905,7 +1908,10 @@ + } + convert_to_string_ex(p_name); + +- PS_DEL_VARL(Z_STRVAL_PP(p_name), Z_STRLEN_PP(p_name)); ++ IF_SESSION_VARS() { ++ SEPARATE_ZVAL_IF_NOT_REF(&PS(http_session_vars)); ++ PS_DEL_VARL(Z_STRVAL_PP(p_name), Z_STRLEN_PP(p_name)); ++ } + + RETURN_TRUE; + } --- php5-5.2.10.dfsg.1.orig/debian/patches/php5-CVE-2010-4698.patch +++ php5-5.2.10.dfsg.1/debian/patches/php5-CVE-2010-4698.patch @@ -0,0 +1,45 @@ +Subject: Fix #53492, fix crash if aa steps are invalid +Origin: http://svn.php.net/viewvc?view=revision&revision=306097 +Bug: http://bugs.php.net/53492 + +Patch also includes +http://svn.php.net/viewvc?view=revision&revision=306236 + + Merge from trunk: + * Fixed parameter check introduced with the recent fix for bug #53492. + * Improved the error message along the way. + +Patch is modified from upstream commits to remove edits to the NEWS +file, to reduce conflicts when patching. + +Index: ext/gd/gd.c +=================================================================== +--- ext/gd/gd.c (revision 306096) ++++ ext/gd/gd.c (revision 306097) +@@ -4593,6 +4593,11 @@ + return; + } + ++ if (aa_steps != 4 || aa_steps != 16) { ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "AA steps must be 4 or 16"); ++ RETURN_FALSE; ++ } ++ + ZEND_FETCH_RESOURCE(bg_img, gdImagePtr, &img, -1, "Image", le_gd); + ZEND_FETCH_RESOURCE(f_ind, int *, &fnt, -1, "Type 1 font", le_ps_font); + +Index: ext/gd/gd.c +=================================================================== +--- ext/gd/gd.c (revision 306235) ++++ ext/gd/gd.c (revision 306236) +@@ -4228,8 +4228,8 @@ + return; + } + +- if (aa_steps != 4 || aa_steps != 16) { +- php_error_docref(NULL TSRMLS_CC, E_WARNING, "AA steps must be 4 or 16"); ++ if (aa_steps != 4 && aa_steps != 16) { ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Antialias steps must be 4 or 16"); + RETURN_FALSE; + } + --- php5-5.2.10.dfsg.1.orig/debian/patches/027-readline_is_editline.patch +++ php5-5.2.10.dfsg.1/debian/patches/027-readline_is_editline.patch @@ -0,0 +1,61 @@ +Index: php5-5.2.4/ext/readline/config.m4 +=================================================================== +--- php5-5.2.4.orig/ext/readline/config.m4 2005-11-29 00:04:01.000000000 +0100 ++++ php5-5.2.4/ext/readline/config.m4 2007-12-21 12:21:51.623149790 +0100 +@@ -12,7 +12,7 @@ + + if test "$PHP_READLINE" && test "$PHP_READLINE" != "no"; then + for i in $PHP_READLINE /usr/local /usr; do +- test -f $i/include/readline/readline.h && READLINE_DIR=$i && break ++ test -f $i/include/editline/readline.h && READLINE_DIR=$i && break + done + + if test -z "$READLINE_DIR"; then +@@ -64,7 +64,7 @@ + elif test "$PHP_LIBEDIT" != "no"; then + + for i in $PHP_LIBEDIT /usr/local /usr; do +- test -f $i/include/readline/readline.h && LIBEDIT_DIR=$i && break ++ test -f $i/include/editline/readline.h && LIBEDIT_DIR=$i && break + done + + if test -z "$LIBEDIT_DIR"; then +Index: php5-5.2.4/ext/readline/readline.c +=================================================================== +--- php5-5.2.4.orig/ext/readline/readline.c 2007-02-12 02:23:17.000000000 +0100 ++++ php5-5.2.4/ext/readline/readline.c 2007-12-21 12:23:25.336380666 +0100 +@@ -33,7 +33,7 @@ + #define rl_completion_matches completion_matches + #endif + +-#include ++#include + #ifndef HAVE_LIBEDIT + #include + #endif +Index: php5-5.2.4/sapi/cli/php_cli.c +=================================================================== +--- php5-5.2.4.orig/sapi/cli/php_cli.c 2007-08-09 01:51:24.000000000 +0200 ++++ php5-5.2.4/sapi/cli/php_cli.c 2007-12-21 12:21:51.627149842 +0100 +@@ -76,7 +76,7 @@ + #endif + + #if (HAVE_LIBREADLINE || HAVE_LIBEDIT) && !defined(COMPILE_DL_READLINE) +-#include ++#include + #if !HAVE_LIBEDIT + #include + #endif +Index: php5-5.2.4/sapi/cli/php_cli_readline.c +=================================================================== +--- php5-5.2.4.orig/sapi/cli/php_cli_readline.c 2007-06-04 11:47:54.000000000 +0200 ++++ php5-5.2.4/sapi/cli/php_cli_readline.c 2007-12-21 12:21:51.627149842 +0100 +@@ -49,7 +49,7 @@ + #include + #endif + +-#include ++#include + #if !HAVE_LIBEDIT + #include + #endif --- php5-5.2.10.dfsg.1.orig/debian/patches/CVE-2010-1130.patch +++ php5-5.2.10.dfsg.1/debian/patches/CVE-2010-1130.patch @@ -0,0 +1,21 @@ +Description: fix safe_mode bypass via semicolon in session_save_path +Origin: upstream, http://svn.php.net/viewvc?view=revision&revision=294272 + +diff -Nur php5-5.2.10.dfsg.1/ext/session/session.c php5-5.2.10.dfsg.1.new/ext/session/session.c +--- php5-5.2.10.dfsg.1/ext/session/session.c 2010-09-14 14:37:24.000000000 -0400 ++++ php5-5.2.10.dfsg.1.new/ext/session/session.c 2010-09-14 14:37:28.000000000 -0400 +@@ -659,8 +659,13 @@ + return FAILURE; + } + +- if ((p = zend_memrchr(new_value, ';', new_value_length))) { ++ /* we do not use zend_memrchr() since path can contain ; itself */ ++ if ((p = strchr(new_value, ';'))) { ++ char *p2; + p++; ++ if ((p2 = strchr(p, ';'))) { ++ p = p2 + 1; ++ } + } else { + p = new_value; + } --- php5-5.2.10.dfsg.1.orig/debian/patches/034-apache2_umask_fix.patch +++ php5-5.2.10.dfsg.1/debian/patches/034-apache2_umask_fix.patch @@ -0,0 +1,44 @@ + +Save and restore umask across requests correctly. + +--- php.orig/sapi/apache2handler/sapi_apache2.c ++++ php/sapi/apache2handler/sapi_apache2.c +@@ -432,6 +432,19 @@ static apr_status_t php_server_context_c + return APR_SUCCESS; + } + ++static int saved_umask; ++ ++static void php_save_umask(void) ++{ ++ saved_umask = umask(077); ++ umask(saved_umask); ++} ++ ++static void php_restore_umask(void) ++{ ++ umask(saved_umask); ++} ++ + static int php_apache_request_ctor(request_rec *r, php_struct *ctx TSRMLS_DC) + { + char *content_length; +@@ -623,6 +636,8 @@ zend_first_try { + } else { + zend_file_handle zfd; + ++ php_save_umask(); ++ + zfd.type = ZEND_HANDLE_FILENAME; + zfd.filename = (char *) r->filename; + zfd.free_filename = 0; +@@ -634,6 +649,9 @@ zend_first_try { + zend_execute_scripts(ZEND_INCLUDE TSRMLS_CC, NULL, 1, &zfd); + } + ++ php_restore_umask(); ++ ++ + apr_table_set(r->notes, "mod_php_memory_usage", + apr_psprintf(ctx->r->pool, "%u", zend_memory_peak_usage(1 TSRMLS_CC))); + } --- php5-5.2.10.dfsg.1.orig/debian/patches/053-extension_api.patch +++ php5-5.2.10.dfsg.1/debian/patches/053-extension_api.patch @@ -0,0 +1,52 @@ +--- php.orig/configure.in ++++ php/configure.in +@@ -1104,8 +1104,13 @@ dnl Build extension directory path + + ZEND_MODULE_API_NO=`$EGREP '#define ZEND_MODULE_API_NO ' $srcdir/Zend/zend_modules.h|$SED 's/#define ZEND_MODULE_API_NO //'` + ++DEBIAN_PHP_API=`egrep -h '^#define ZEND_EXTENSION_API_NO|^#define ZEND_MODULE_API_NO|#define PHP_API_VERSION' $srcdir/Zend/zend_extensions.h $srcdir/Zend/zend_modules.h $srcdir/main/php.h | awk '{print $3}' | sed -e 's/^2200/200/' | sort -n | tail -n 1` ++if echo "$CPPFLAGS $CFLAGS" | grep -q -- -D_FILE_OFFSET_BITS=64; then ++ DEBIAN_PHP_API="${DEBIAN_PHP_API}+lfs" ++fi ++ + if test -z "$EXTENSION_DIR"; then +- extbasedir=$ZEND_MODULE_API_NO ++ extbasedir=$DEBIAN_PHP_API + if test "$oldstyleextdir" = "yes"; then + if test "$PHP_DEBUG" = "1"; then + part1=debug +@@ -1250,6 +1255,7 @@ PHP_SUBST(CXX) + PHP_SUBST(CXXFLAGS) + PHP_SUBST(CXXFLAGS_CLEAN) + PHP_SUBST_OLD(DEBUG_CFLAGS) ++PHP_SUBST_OLD(DEBIAN_PHP_API) + PHP_SUBST_OLD(EXTENSION_DIR) + PHP_SUBST_OLD(EXTRA_LDFLAGS) + PHP_SUBST_OLD(EXTRA_LDFLAGS_PROGRAM) +--- php.orig/scripts/php-config.in ++++ php/scripts/php-config.in +@@ -17,6 +17,7 @@ php_cli_binary=NONE + php_cgi_binary=NONE + configure_options="@CONFIGURE_OPTIONS@" + php_sapis="@PHP_INSTALLED_SAPIS@" ++phpapi="@DEBIAN_PHP_API@" + + # Set php_cli_binary and php_cgi_binary if available + for sapi in $php_sapis; do +@@ -55,6 +56,8 @@ case "$1" in + echo $include_dir;; + --php-binary) + echo $php_binary;; ++--phpapi) ++ echo $phpapi;; + --php-sapis) + echo $php_sapis;; + --configure-options) +@@ -75,6 +78,7 @@ Options: + --include-dir [$include_dir] + --php-binary [$php_binary] + --php-sapis [$php_sapis] ++ --phpapi [$phpapi] + --configure-options [$configure_options] + --version [$version] + --vernum [$vernum] --- php5-5.2.10.dfsg.1.orig/debian/patches/CVE-2010-3065.patch +++ php5-5.2.10.dfsg.1/debian/patches/CVE-2010-3065.patch @@ -0,0 +1,16 @@ +Description: fix arbitrary session variable modification via crafted + session variable name +Origin: upstream, http://svn.php.net/viewvc?view=revision&revision=298608 + +diff -Nur php5-5.2.10.dfsg.1/ext/session/session.c php5-5.2.10.dfsg.1.new/ext/session/session.c +--- php5-5.2.10.dfsg.1/ext/session/session.c 2010-09-14 14:41:04.000000000 -0400 ++++ php5-5.2.10.dfsg.1.new/ext/session/session.c 2010-09-14 14:41:09.000000000 -0400 +@@ -819,7 +819,7 @@ + + PS_ENCODE_LOOP( + smart_str_appendl(&buf, key, key_length); +- if (memchr(key, PS_DELIMITER, key_length)) { ++ if (memchr(key, PS_DELIMITER, key_length) || memchr(key, PS_UNDEF_MARKER, key_length)) { + PHP_VAR_SERIALIZE_DESTROY(var_hash); + smart_str_free(&buf); + return FAILURE; --- php5-5.2.10.dfsg.1.orig/debian/patches/047-zts_with_dl.patch +++ php5-5.2.10.dfsg.1/debian/patches/047-zts_with_dl.patch @@ -0,0 +1,15 @@ +--- php.orig/ext/standard/dl.c ++++ php/ext/standard/dl.c +@@ -81,12 +81,7 @@ PHP_FUNCTION(dl) + if ((strncmp(sapi_module.name, "cgi", 3)!=0) && + (strcmp(sapi_module.name, "cli")!=0) && + (strncmp(sapi_module.name, "embed", 5)!=0)) { +-#ifdef ZTS +- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not supported in multithreaded Web servers - use extension=%s in your php.ini", Z_STRVAL_PP(file)); +- RETURN_FALSE; +-#else + php_error_docref(NULL TSRMLS_CC, E_STRICT, "dl() is deprecated - use extension=%s in your php.ini", Z_STRVAL_PP(file)); +-#endif + } + + php_dl(*file, MODULE_TEMPORARY, return_value, 0 TSRMLS_CC); --- php5-5.2.10.dfsg.1.orig/debian/patches/CVE-2009-4017.patch +++ php5-5.2.10.dfsg.1/debian/patches/CVE-2009-4017.patch @@ -0,0 +1,59 @@ +Description: fix denial of service via large number of files in + form-data POST request. +upstream, Origin: http://svn.php.net/viewvc?view=revision&revision=289990 +upstream, Origin: http://svn.php.net/viewvc?view=revision&revision=290029 +upstream, Origin: http://svn.php.net/viewvc?view=revision&revision=290306 + +diff -Nur php5-5.2.10.dfsg.1/main/main.c php5-5.2.10.dfsg.1.new/main/main.c +--- php5-5.2.10.dfsg.1/main/main.c 2009-11-24 15:17:52.000000000 -0500 ++++ php5-5.2.10.dfsg.1.new/main/main.c 2009-11-24 15:18:08.000000000 -0500 +@@ -456,6 +456,7 @@ + PHP_INI_ENTRY("mail.force_extra_parameters",NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnChangeMailForceExtra) + PHP_INI_ENTRY("disable_functions", "", PHP_INI_SYSTEM, NULL) + PHP_INI_ENTRY("disable_classes", "", PHP_INI_SYSTEM, NULL) ++ PHP_INI_ENTRY("max_file_uploads", "50", PHP_INI_SYSTEM, NULL) + + STD_PHP_INI_BOOLEAN("allow_url_fopen", "1", PHP_INI_SYSTEM, OnUpdateBool, allow_url_fopen, php_core_globals, core_globals) + STD_PHP_INI_BOOLEAN("allow_url_include", "0", PHP_INI_SYSTEM, OnUpdateBool, allow_url_include, php_core_globals, core_globals) +diff -Nur php5-5.2.10.dfsg.1/main/rfc1867.c php5-5.2.10.dfsg.1.new/main/rfc1867.c +--- php5-5.2.10.dfsg.1/main/rfc1867.c 2008-12-31 06:17:47.000000000 -0500 ++++ php5-5.2.10.dfsg.1.new/main/rfc1867.c 2009-11-24 15:18:01.000000000 -0500 +@@ -32,6 +32,7 @@ + #include "php_globals.h" + #include "php_variables.h" + #include "rfc1867.h" ++#include "php_ini.h" + + #define DEBUG_FILE_UPLOAD ZEND_DEBUG + +@@ -794,6 +795,12 @@ + zend_llist header; + void *event_extra_data = NULL; + int llen = 0; ++ char *max_uploads = INI_STR("max_file_uploads"); ++ int upload_cnt = 0; ++ ++ if (max_uploads && *max_uploads) { ++ upload_cnt = atoi(max_uploads); ++ } + + if (SG(request_info).content_length > SG(post_max_size)) { + sapi_module.sapi_error(E_WARNING, "POST Content-Length of %ld bytes exceeds the limit of %ld bytes", SG(request_info).content_length, SG(post_max_size)); +@@ -972,6 +979,9 @@ + /* If file_uploads=off, skip the file part */ + if (!PG(file_uploads)) { + skip_upload = 1; ++ } else if (upload_cnt <= 0) { ++ skip_upload = 1; ++ sapi_module.sapi_error(E_WARNING, "Maximum number of allowable file uploads has been exceeded"); + } + + /* Return with an error if the posted data is garbled */ +@@ -1016,6 +1026,7 @@ + if (!skip_upload) { + /* Handle file */ + fd = php_open_temporary_fd_ex(PG(upload_tmp_dir), "php", &temp_filename, 1 TSRMLS_CC); ++ upload_cnt--; + if (fd==-1) { + sapi_module.sapi_error(E_WARNING, "File upload error - unable to create a temporary file"); + cancel_upload = UPLOAD_ERROR_E; --- php5-5.2.10.dfsg.1.orig/debian/patches/libedit_is_editline.patch +++ php5-5.2.10.dfsg.1/debian/patches/libedit_is_editline.patch @@ -0,0 +1,55 @@ +--- php.orig/ext/readline/config.m4 ++++ php/ext/readline/config.m4 +@@ -55,7 +55,7 @@ if test "$PHP_READLINE" && test "$PHP_RE + elif test "$PHP_LIBEDIT" != "no"; then + + for i in $PHP_LIBEDIT /usr/local /usr; do +- test -f $i/include/readline/readline.h && LIBEDIT_DIR=$i && break ++ test -f $i/include/editline/readline.h && LIBEDIT_DIR=$i && break + done + + if test -z "$LIBEDIT_DIR"; then +--- php.orig/ext/readline/readline.c ++++ php/ext/readline/readline.c +@@ -33,8 +33,10 @@ + #define rl_completion_matches completion_matches + #endif + ++#ifdef HAVE_LIBEDIT ++#include ++#else + #include +-#ifndef HAVE_LIBEDIT + #include + #endif + +--- php5-5.2.6.orig/sapi/cli/php_cli.c 2008-01-29 13:01:14.000000000 -0700 ++++ php5-5.2.6/sapi/cli/php_cli.c 2008-08-12 14:07:13.000000000 -0600 +@@ -76,9 +76,11 @@ + #endif + + #if (HAVE_LIBREADLINE || HAVE_LIBEDIT) && !defined(COMPILE_DL_READLINE) +-#include + #if !HAVE_LIBEDIT ++#include + #include ++#else ++#include + #endif + #include "php_cli_readline.h" + #endif /* HAVE_LIBREADLINE || HAVE_LIBEDIT */ +--- php5-5.2.6.orig/sapi/cli/php_cli_readline.c 2007-12-31 00:20:16.000000000 -0700 ++++ php5-5.2.6.orig/sapi/cli/php_cli_readline.c 2008-08-12 14:44:36.000000000 -0600 +@@ -49,9 +49,11 @@ + #include + #endif + +-#include + #if !HAVE_LIBEDIT ++#include + #include ++#else ++#include + #endif + + #include "zend_compile.h" --- php5-5.2.10.dfsg.1.orig/debian/patches/libtool2.2.patch +++ php5-5.2.10.dfsg.1/debian/patches/libtool2.2.patch @@ -0,0 +1,31 @@ +--- php.orig/scripts/phpize.in ++++ php/scripts/phpize.in +@@ -5,10 +5,16 @@ prefix='@prefix@' + exec_prefix="`eval echo @exec_prefix@`" + phpdir="$prefix/lib/php5/build" + includedir="$prefix/include/php5" ++aclocaldir="$prefix/share/aclocal" + builddir="`pwd`" + SED="@SED@" + +-FILES_BUILD="mkdep.awk scan_makefile_in.awk shtool libtool.m4" ++FILES_BUILD="mkdep.awk scan_makefile_in.awk shtool" ++if [ -f "$aclocaldir/ltsugar.m4" ]; then ++ LIBTOOL_FILES="libtool.m4 ltoptions.m4 ltsugar.m4 ltversion.m4 lt~obsolete.m4" ++else ++ LIBTOOL_FILES="libtool.m4" ++fi + FILES="acinclude.m4 Makefile.global config.sub config.guess ltmain.sh run-tests*.php" + CLEAN_FILES="$FILES *.o *.lo *.la .deps .libs/ build/ include/ modules/ install-sh \ + mkinstalldirs missing config.nice config.sub config.guess configure configure.in \ +@@ -144,8 +150,9 @@ phpize_copy_files() + test -d build || mkdir build + + (cd "$phpdir" && cp $FILES_BUILD "$builddir"/build) ++ (cd "$aclocaldir" && cp $LIBTOOL_FILES "$builddir"/build) + (cd "$phpdir" && cp $FILES "$builddir") +- (cd "$builddir" && cat acinclude.m4 ./build/libtool.m4 > aclocal.m4) ++ (cd "$builddir/build" && cat ../acinclude.m4 $LIBTOOL_FILES > ../aclocal.m4) + } + + phpize_replace_prefix() --- php5-5.2.10.dfsg.1.orig/debian/patches/manpage_spelling.patch +++ php5-5.2.10.dfsg.1/debian/patches/manpage_spelling.patch @@ -0,0 +1,29 @@ +--- php.orig/sapi/cli/php.1.in ++++ php/sapi/cli/php.1.in +@@ -69,7 +69,7 @@ specified by \-F to be executed. + You can access the input line by \fB$argn\fP. While processing the input lines + .B $argi + contains the number of the actual line being processed. Further more +-the paramters \-B and \-E can be used to execute ++the parameters \-B and \-E can be used to execute + .IR code + (see \-r) before and + after all input lines have been processed respectively. Notice that the +@@ -316,7 +316,7 @@ The configuration file for the CGI versi + The configuration file for the version of PHP that apache2 uses. + .SH EXAMPLES + .TP 5 +-\fIphp -r 'echo "Hello World\\n";'\fP ++\fIphp \-r 'echo "Hello World\\n";'\fP + This command simply writes the text "Hello World" to standard out. + .TP + \fIphp \-r 'print_r(gd_info());'\fP +@@ -340,7 +340,7 @@ configuration information. If you then c + Using this PHP command you can count the lines being input. + .TP + \fIphp \-R '@$l+=count(file($argn));' \-E 'echo "Lines:$l\\n";'\fP +-In this example PHP expects each input line beeing a file. It counts all lines ++In this example PHP expects each input line being a file. It counts all lines + of the files specified by each input line and shows the summarized result. + You may combine this with tools like find and change the php scriptlet. + .TP --- php5-5.2.10.dfsg.1.orig/debian/patches/php5-CVE-2011-0708.patch +++ php5-5.2.10.dfsg.1/debian/patches/php5-CVE-2011-0708.patch @@ -0,0 +1,132 @@ +Subject: fix bug #54002, exif_read_data crashes on crafted tags +Origin: http://svn.php.net/viewvc?view=revision&revision=308316 +Bug: http://bugs.php.net/bug.php?id=54002 + +Patch also includes +http://svn.php.net/viewvc?view=revision&revision=308317 + + Bug #54002, fix windows build, use the relevant values in the + warnings + +and http://svn.php.net/viewvc?view=revision&revision=308362 + + fix the fix (Dmitry) and ensure that it builds everywhere, can + someone test on solaris&co pls? + +Patch is also modified to drop the added testcases as they contained +jpegs and not-representable in diffs. They have been added to the +lp:qa-regression-testing tree instead. + +Index: ext/exif/exif.c +=================================================================== +--- ext/exif/exif.c (revision 308315) ++++ ext/exif/exif.c (revision 308316) +@@ -40,6 +40,10 @@ + #include "php.h" + #include "ext/standard/file.h" + ++#ifdef PHP_WIN32 ++include "win32/php_stdint.h" ++#endif ++ + #if HAVE_EXIF + + /* When EXIF_DEBUG is defined the module generates a lot of debug messages +@@ -2821,6 +2825,7 @@ + int tag, format, components; + char *value_ptr, tagname[64], cbuf[32], *outside=NULL; + size_t byte_count, offset_val, fpos, fgot; ++ int64_t byte_count_signed; + xp_field_type *tmp_xp; + #ifdef EXIF_DEBUG + char *dump_data; +@@ -2845,13 +2850,20 @@ + /*return TRUE;*/ + } + +- byte_count = components * php_tiff_bytes_per_format[format]; ++ if (components < 0) { ++ exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "Process tag(x%04X=%s): Illegal byte_count(%ld)", tag, exif_get_tagname(tag, tagname, -12, tag_table TSRMLS_CC), byte_count); ++ return FALSE; ++ } + +- if ((ssize_t)byte_count < 0) { ++ byte_count_signed = (int64_t)components * php_tiff_bytes_per_format[format]; ++ ++ if (byte_count_signed < 0 || (byte_count_signed > 2147483648)) { + exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "Process tag(x%04X=%s): Illegal byte_count(%ld)", tag, exif_get_tagname(tag, tagname, -12, tag_table TSRMLS_CC), byte_count); + return FALSE; + } + ++ byte_count = (size_t)byte_count_signed; ++ + if (byte_count > 4) { + offset_val = php_ifd_get32u(dir_entry+8, ImageInfo->motorola_intel); + /* If its bigger than 4 bytes, the dir entry contains an offset. */ +@@ -2916,6 +2928,7 @@ + efree(dump_data); + } + #endif ++ + if (section_index==SECTION_THUMBNAIL) { + if (!ImageInfo->Thumbnail.data) { + switch(tag) { +Index: ext/exif/exif.c +=================================================================== +--- ext/exif/exif.c (revision 308316) ++++ ext/exif/exif.c (revision 308317) +@@ -41,7 +41,7 @@ + #include "ext/standard/file.h" + + #ifdef PHP_WIN32 +-include "win32/php_stdint.h" ++#include "win32/php_stdint.h" + #endif + + #if HAVE_EXIF +@@ -2851,14 +2851,14 @@ + } + + if (components < 0) { +- exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "Process tag(x%04X=%s): Illegal byte_count(%ld)", tag, exif_get_tagname(tag, tagname, -12, tag_table TSRMLS_CC), byte_count); ++ exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "Process tag(x%04X=%s): Illegal components(%ld)", tag, exif_get_tagname(tag, tagname, -12, tag_table TSRMLS_CC), components); + return FALSE; + } + + byte_count_signed = (int64_t)components * php_tiff_bytes_per_format[format]; + + if (byte_count_signed < 0 || (byte_count_signed > 2147483648)) { +- exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "Process tag(x%04X=%s): Illegal byte_count(%ld)", tag, exif_get_tagname(tag, tagname, -12, tag_table TSRMLS_CC), byte_count); ++ exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "Process tag(x%04X=%s): Illegal byte_count", tag, exif_get_tagname(tag, tagname, -12, tag_table TSRMLS_CC)); + return FALSE; + } + +Index: ext/exif/exif.c +=================================================================== +--- ext/exif/exif.c (revision 308361) ++++ ext/exif/exif.c (revision 308362) +@@ -40,8 +40,14 @@ + #include "php.h" + #include "ext/standard/file.h" + ++#ifdef HAVE_STDINT_H ++# include ++#endif ++#ifdef HAVE_INTTYPES_H ++# include ++#endif + #ifdef PHP_WIN32 +-#include "win32/php_stdint.h" ++# include "win32/php_stdint.h" + #endif + + #if HAVE_EXIF +@@ -2857,7 +2863,7 @@ + + byte_count_signed = (int64_t)components * php_tiff_bytes_per_format[format]; + +- if (byte_count_signed < 0 || (byte_count_signed > 2147483648)) { ++ if (byte_count_signed < 0 || (byte_count_signed > INT32_MAX)) { + exif_error_docref("exif_read_data#error_ifd" EXIFERR_CC, ImageInfo, E_WARNING, "Process tag(x%04X=%s): Illegal byte_count", tag, exif_get_tagname(tag, tagname, -12, tag_table TSRMLS_CC)); + return FALSE; + } --- php5-5.2.10.dfsg.1.orig/debian/patches/036-fd_setsize_fix.patch +++ php5-5.2.10.dfsg.1/debian/patches/036-fd_setsize_fix.patch @@ -0,0 +1,22 @@ +--- php.orig/ext/sockets/sockets.c ++++ php/ext/sockets/sockets.c +@@ -572,6 +572,7 @@ static int php_sock_array_to_fd_set(zval + + php_sock = (php_socket*) zend_fetch_resource(element TSRMLS_CC, -1, le_socket_name, NULL, 1, le_socket); + if (!php_sock) continue; /* If element is not a resource, skip it */ ++ if (php_sock->bsd_socket > FD_SETSIZE) continue; /* must ignore it */ + + PHP_SAFE_FD_SET(php_sock->bsd_socket, fds); + if (php_sock->bsd_socket > *max_fd) { +--- php.orig/ext/standard/streamsfuncs.c ++++ php/ext/standard/streamsfuncs.c +@@ -603,6 +603,9 @@ static int stream_array_to_fd_set(zval * + * is not displayed. + * */ + if (SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL, (void*)&this_fd, 1) && this_fd >= 0) { ++ if (this_fd > FD_SETSIZE) ++ continue; ++ + + PHP_SAFE_FD_SET(this_fd, fds); + --- php5-5.2.10.dfsg.1.orig/debian/patches/use_embedded_timezonedb.patch +++ php5-5.2.10.dfsg.1/debian/patches/use_embedded_timezonedb.patch @@ -0,0 +1,307 @@ + +Add support for use of the system timezone database, rather +than embedding a copy. Discussed upstream but was not desired. + +History: +r4: added "System/Localtime" tzname which uses /etc/localtime +r3: fix a crash if /usr/share/zoneinfo doesn't exist (Raphael Geissert) +r2: add filesystem trawl to set up name alias index +r1: initial revision + +--- php.orig/ext/date/lib/parse_tz.c ++++ php/ext/date/lib/parse_tz.c +@@ -20,6 +20,16 @@ + + #include "timelib.h" + ++#ifdef HAVE_SYSTEM_TZDATA ++#include ++#include ++#include ++#include ++#include ++ ++#include "php_scandir.h" ++#endif ++ + #include + + #ifdef HAVE_LOCALE_H +@@ -31,7 +41,10 @@ + #else + #include + #endif ++ ++#ifndef HAVE_SYSTEM_TZDATA + #include "timezonedb.h" ++#endif + + #if (defined(__APPLE__) || defined(__APPLE_CC__)) && (defined(__BIG_ENDIAN__) || defined(__LITTLE_ENDIAN__)) + # if defined(__LITTLE_ENDIAN__) +@@ -212,6 +225,211 @@ void timelib_dump_tzinfo(timelib_tzinfo + } + } + ++#ifdef HAVE_SYSTEM_TZDATA ++ ++#ifdef HAVE_SYSTEM_TZDATA_PREFIX ++#define ZONEINFO_PREFIX HAVE_SYSTEM_TZDATA_PREFIX ++#else ++#define ZONEINFO_PREFIX "/usr/share/zoneinfo" ++#endif ++ ++#define SYSTEM_TZFILE "/etc/localtime" ++ ++static const timelib_tzdb *timezonedb_system = NULL; ++ ++/* Filter out some non-tzdata files and the posix/right databases, if ++ * present. */ ++static int index_filter(const struct dirent *ent) ++{ ++ return strcmp(ent->d_name, ".") != 0 ++ && strcmp(ent->d_name, "..") != 0 ++ && strcmp(ent->d_name, "posix") != 0 ++ && strcmp(ent->d_name, "posixrules") != 0 ++ && strcmp(ent->d_name, "right") != 0 ++ && strstr(ent->d_name, ".tab") == NULL; ++} ++ ++/* Create the zone identifier index by trawling the filesystem. */ ++static void create_zone_index(timelib_tzdb *db) ++{ ++ size_t dirstack_size, dirstack_top; ++ size_t index_size, index_next; ++ timelib_tzdb_index_entry *db_index; ++ char **dirstack; ++ ++ /* LIFO stack to hold directory entries to scan; each slot is a ++ * directory name relative to the zoneinfo prefix. */ ++ dirstack_size = 32; ++ dirstack = malloc(dirstack_size * sizeof *dirstack); ++ dirstack_top = 1; ++ dirstack[0] = strdup(""); ++ ++ /* Index array. */ ++ index_size = 64; ++ db_index = malloc(index_size * sizeof *db_index); ++ index_next = 0; ++ ++ do { ++ struct dirent **ents; ++ char name[PATH_MAX], *top; ++ int count; ++ ++ /* Pop the top stack entry, and iterate through its contents. */ ++ top = dirstack[--dirstack_top]; ++ snprintf(name, sizeof name, ZONEINFO_PREFIX "/%s", top); ++ ++ count = php_scandir(name, &ents, index_filter, php_alphasort); ++ ++ while (count > 0) { ++ struct stat st; ++ const char *leaf = ents[count - 1]->d_name; ++ ++ snprintf(name, sizeof name, ZONEINFO_PREFIX "/%s/%s", ++ top, leaf); ++ ++ if (strlen(name) && stat(name, &st) == 0) { ++ /* Name, relative to the zoneinfo prefix. */ ++ const char *root = top; ++ ++ if (root[0] == '/') root++; ++ ++ snprintf(name, sizeof name, "%s%s%s", root, ++ *root ? "/": "", leaf); ++ ++ if (S_ISDIR(st.st_mode)) { ++ if (dirstack_top == dirstack_size) { ++ dirstack_size *= 2; ++ dirstack = realloc(dirstack, ++ dirstack_size * sizeof *dirstack); ++ } ++ dirstack[dirstack_top++] = strdup(name); ++ } ++ else { ++ if (index_next == index_size) { ++ index_size *= 2; ++ db_index = realloc(db_index, ++ index_size * sizeof *db_index); ++ } ++ ++ db_index[index_next].id = strdup(name); ++ db_index[index_next++].pos = 0; ++ } ++ } ++ ++ free(ents[--count]); ++ } ++ ++ if (count != -1) free(ents); ++ free(top); ++ } while (dirstack_top); ++ ++ db->index = db_index; ++ db->index_size = index_next; ++ ++ free(dirstack); ++} ++ ++/* Return the mmap()ed tzfile if found, else NULL. On success, the ++ * length of the mapped data is placed in *length. */ ++static char *map_tzfile(const char *timezone, size_t *length) ++{ ++ char fname[PATH_MAX]; ++ const char *fn; ++ struct stat st; ++ char *p; ++ int fd; ++ ++ if (strcmp(timezone, TIMELIB_SYSTEM_TZID) == 0) { ++ fn = SYSTEM_TZFILE; ++ } ++ else { ++ if (strstr(timezone, "..") != NULL) { ++ return NULL; ++ } ++ ++ snprintf(fname, sizeof fname, ZONEINFO_PREFIX "/%s", timezone); ++ fn = fname; ++ } ++ ++ fd = open(fn, O_RDONLY); ++ if (fd == -1) { ++ return NULL; ++ } else if (fstat(fd, &st) != 0 || st.st_size < 21) { ++ close(fd); ++ return NULL; ++ } ++ ++ *length = st.st_size; ++ p = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); ++ close(fd); ++ ++ return p != MAP_FAILED ? p : NULL; ++} ++ ++const timelib_tzdb *timelib_builtin_db(void) ++{ ++ if (timezonedb_system == NULL) { ++ timelib_tzdb *tmp = malloc(sizeof *tmp); ++ ++ tmp->version = "0.system"; ++ tmp->data = NULL; ++ create_zone_index(tmp); ++ timezonedb_system = tmp; ++ } ++ ++ return timezonedb_system; ++} ++ ++const timelib_tzdb_index_entry *timelib_timezone_builtin_identifiers_list(int *count) ++{ ++ *count = timezonedb_system->index_size; ++ return timezonedb_system->index; ++} ++ ++int timelib_timezone_id_is_valid(char *timezone, const timelib_tzdb *tzdb) ++{ ++ char fname[PATH_MAX]; ++ const char *fn; ++ ++ if (strcmp(timezone, TIMELIB_SYSTEM_TZID) == 0) { ++ fn = SYSTEM_TZFILE; ++ } ++ else { ++ if (strstr(timezone, "..") != NULL) { ++ return 0; ++ } ++ ++ snprintf(fname, sizeof fname, ZONEINFO_PREFIX "/%s", timezone); ++ fn = fname; ++ } ++ ++ return access(fn, R_OK) == 0 ? 1 : 0; ++} ++ ++timelib_tzinfo *timelib_parse_tzfile(char *timezone, const timelib_tzdb *tzdb) ++{ ++ char *tzf, *orig; ++ timelib_tzinfo *tmp; ++ size_t len; ++ ++ orig = map_tzfile(timezone, &len); ++ if (orig == NULL) { ++ return NULL; ++ } ++ ++ tmp = timelib_tzinfo_ctor(timezone); ++ ++ tzf = orig + 20; ++ read_header(&tzf, tmp); ++ read_transistions(&tzf, tmp); ++ read_types(&tzf, tmp); ++ ++ munmap(orig, len); ++ ++ return tmp; ++} ++#else /* !HAVE_SYSTEM_TZDATA */ ++ + static int seek_to_tz_position(const unsigned char **tzf, char *timezone, const timelib_tzdb *tzdb) + { + int left = 0, right = tzdb->index_size - 1; +@@ -285,6 +503,7 @@ timelib_tzinfo *timelib_parse_tzfile(cha + + return tmp; + } ++#endif + + static ttinfo* fetch_timezone_offset(timelib_tzinfo *tz, timelib_sll ts, timelib_sll *transition_time) + { +--- php.orig/ext/date/lib/timelib.h ++++ php/ext/date/lib/timelib.h +@@ -32,6 +32,10 @@ + + #define TIMELIB_SPECIAL_WEEKDAY 0x01 + ++#ifdef HAVE_SYSTEM_TZDATA ++#define TIMELIB_SYSTEM_TZID "System/Localtime" ++#endif ++ + #ifndef LONG_MAX + #define LONG_MAX 2147483647L + #endif +--- php.orig/ext/date/lib/timelib.m4 ++++ php/ext/date/lib/timelib.m4 +@@ -78,3 +78,17 @@ stdlib.h + + dnl Check for strtoll, atoll + AC_CHECK_FUNCS(strtoll atoll strftime) ++ ++PHP_ARG_WITH(system-tzdata, for use of system timezone data, ++[ --with-system-tzdata[=DIR] to specify use of system timezone data], ++no, no) ++ ++if test "$PHP_SYSTEM_TZDATA" != "no"; then ++ AC_DEFINE(HAVE_SYSTEM_TZDATA, 1, [Define if system timezone data is used]) ++ ++ if test "$PHP_SYSTEM_TZDATA" != "yes"; then ++ AC_DEFINE_UNQUOTED(HAVE_SYSTEM_TZDATA_PREFIX, "$PHP_SYSTEM_TZDATA", ++ [Define for location of system timezone data]) ++ fi ++fi ++ +--- php.orig/ext/date/php_date.c ++++ php/ext/date/php_date.c +@@ -595,6 +595,11 @@ static char* guess_timezone(const timeli + if (DATEG(default_timezone) && (strlen(DATEG(default_timezone)) > 0) && timelib_timezone_id_is_valid(DATEG(default_timezone), tzdb)) { + return DATEG(default_timezone); + } ++#ifdef TIMELIB_SYSTEM_TZID ++ if (timelib_timezone_id_is_valid(TIMELIB_SYSTEM_TZID, tzdb)) { ++ return TIMELIB_SYSTEM_TZID; ++ } ++#endif + #if HAVE_TM_ZONE + /* Try to guess timezone from system information */ + { --- php5-5.2.10.dfsg.1.orig/debian/patches/CVE-2009-3292.patch +++ php5-5.2.10.dfsg.1/debian/patches/CVE-2009-3292.patch @@ -0,0 +1,71 @@ +Description: fix denial of service via malformed exif images +upstream, Origin: http://svn.php.net/viewvc?view=revision&revision=287371 +Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/php5/+bug/446313 + +diff -Nur php5-5.2.10.dfsg.1/ext/exif/exif.c php5-5.2.10.dfsg.1.new/ext/exif/exif.c +--- php5-5.2.10.dfsg.1/ext/exif/exif.c 2009-11-24 15:17:07.000000000 -0500 ++++ php5-5.2.10.dfsg.1.new/ext/exif/exif.c 2009-11-24 15:17:11.000000000 -0500 +@@ -3247,7 +3247,7 @@ + { + /* Check the APP1 for Exif Identifier Code */ + static const uchar ExifHeader[] = {0x45, 0x78, 0x69, 0x66, 0x00, 0x00}; +- if (memcmp(CharBuf+2, ExifHeader, 6)) { ++ if (length <= 8 || memcmp(CharBuf+2, ExifHeader, 6)) { + exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Incorrect APP1 Exif Identifier Code"); + return; + } +@@ -3330,8 +3330,14 @@ + } + + /* Read the length of the section. */ +- lh = php_stream_getc(ImageInfo->infile); +- ll = php_stream_getc(ImageInfo->infile); ++ if ((lh = php_stream_getc(ImageInfo->infile)) == EOF) { ++ EXIF_ERRLOG_CORRUPT(ImageInfo) ++ return FALSE; ++ } ++ if ((ll = php_stream_getc(ImageInfo->infile)) == EOF) { ++ EXIF_ERRLOG_CORRUPT(ImageInfo) ++ return FALSE; ++ } + + itemlen = (lh << 8) | ll; + +@@ -3531,6 +3537,10 @@ + int entry_tag , entry_type; + tag_table_type tag_table = exif_get_tag_table(section_index); + ++ if (ImageInfo->ifd_nesting_level > MAX_IFD_NESTING_LEVEL) { ++ return FALSE; ++ } ++ + if (ImageInfo->FileSize >= dir_offset+2) { + sn = exif_file_sections_add(ImageInfo, M_PSEUDO, 2, NULL); + #ifdef EXIF_DEBUG +@@ -3674,6 +3684,7 @@ + #ifdef EXIF_DEBUG + exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Next IFD: %s @x%04X", exif_get_sectionname(sub_section_index), entry_offset); + #endif ++ ImageInfo->ifd_nesting_level++; + exif_process_IFD_in_TIFF(ImageInfo, entry_offset, sub_section_index TSRMLS_CC); + if (section_index!=SECTION_THUMBNAIL && entry_tag==TAG_SUB_IFD) { + if (ImageInfo->Thumbnail.filetype != IMAGE_FILETYPE_UNKNOWN +@@ -3713,6 +3724,7 @@ + #ifdef EXIF_DEBUG + exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Read next IFD (THUMBNAIL) at x%04X", next_offset); + #endif ++ ImageInfo->ifd_nesting_level++; + exif_process_IFD_in_TIFF(ImageInfo, next_offset, SECTION_THUMBNAIL TSRMLS_CC); + #ifdef EXIF_DEBUG + exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "%s THUMBNAIL @0x%04X + 0x%04X", ImageInfo->Thumbnail.data ? "Ignore" : "Read", ImageInfo->Thumbnail.offset, ImageInfo->Thumbnail.size); +@@ -3785,9 +3797,7 @@ + } else { + exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_WARNING, "Invalid TIFF file"); + } +- } +- else +- if (!memcmp(file_header, "MM\x00\x2a", 4)) { ++ } else if (!memcmp(file_header, "MM\x00\x2a", 4)) { + ImageInfo->FileType = IMAGE_FILETYPE_TIFF_MM; + ImageInfo->motorola_intel = 1; + #ifdef EXIF_DEBUG --- php5-5.2.10.dfsg.1.orig/debian/patches/CVE-2010-1128.patch +++ php5-5.2.10.dfsg.1/debian/patches/CVE-2010-1128.patch @@ -0,0 +1,27 @@ +Description: fix weak entropy in Linear Congruential Generator (LCG) +Origin: upstream, http://svn.php.net/viewvc?view=revision&revision=293253 + +diff -Nur php5-5.2.10.dfsg.1/ext/standard/lcg.c php5-5.2.10.dfsg.1.new/ext/standard/lcg.c +--- php5-5.2.10.dfsg.1/ext/standard/lcg.c 2008-12-31 06:17:45.000000000 -0500 ++++ php5-5.2.10.dfsg.1.new/ext/standard/lcg.c 2010-09-14 14:36:59.000000000 -0400 +@@ -78,7 +78,7 @@ + struct timeval tv; + + if (gettimeofday(&tv, NULL) == 0) { +- LCG(s1) = tv.tv_sec ^ (~tv.tv_usec); ++ LCG(s1) = tv.tv_sec ^ (tv.tv_usec<<11); + } else { + LCG(s1) = 1; + } +@@ -88,6 +88,11 @@ + LCG(s2) = (long) getpid(); + #endif + ++ /* Add entropy to s2 by calling gettimeofday() again */ ++ if (gettimeofday(&tv, NULL) == 0) { ++ LCG(s2) ^= (tv.tv_usec<<11); ++ } ++ + LCG(seeded) = 1; + } + --- php5-5.2.10.dfsg.1.orig/debian/patches/108-64_bit_datetime.patch +++ php5-5.2.10.dfsg.1/debian/patches/108-64_bit_datetime.patch @@ -0,0 +1,12 @@ +--- php.orig/ext/standard/datetime.c ++++ php/ext/standard/datetime.c +@@ -20,6 +20,9 @@ + + /* $Id: datetime.c,v 1.134.2.2.2.6 2008/12/31 11:17:44 sebastian Exp $ */ + ++#define _XOPEN_SOURCE /* needed to get strptime() declared */ ++#define _BSD_SOURCE /* needed to get ulong declared */ ++ + #include "php.h" + #include "zend_operators.h" + #include "datetime.h" --- php5-5.2.10.dfsg.1.orig/debian/patches/suhosin.patch +++ php5-5.2.10.dfsg.1/debian/patches/suhosin.patch @@ -0,0 +1,2576 @@ +suhosin hardening patch + +this patch was downloaded from: + + http://download.suhosin.org/suhosin-patch-5.2.10-0.9.7.patch.gz + +the following modifications have been made: + + * removed changes to ./configure since this file is autogenerated + * "quilt refresh" has been run to clean up the offsets, etc +--- php.orig/TSRM/TSRM.h ++++ php/TSRM/TSRM.h +@@ -38,6 +38,13 @@ typedef long tsrm_intptr_t; + typedef unsigned long tsrm_uintptr_t; + #endif + ++#if SUHOSIN_PATCH ++# if HAVE_REALPATH ++# undef realpath ++# define realpath php_realpath ++# endif ++#endif ++ + /* Only compile multi-threading functions if we're in ZTS mode */ + #ifdef ZTS + +@@ -93,6 +100,7 @@ typedef void (*ts_allocate_dtor)(void *, + + #define THREAD_HASH_OF(thr,ts) (unsigned long)thr%(unsigned long)ts + ++ + #ifdef __cplusplus + extern "C" { + #endif +--- php.orig/TSRM/tsrm_virtual_cwd.c ++++ php/TSRM/tsrm_virtual_cwd.c +@@ -273,6 +273,191 @@ static char *tsrm_strndup(const char *s, + } + /* }}} */ + ++#if SUHOSIN_PATCH ++CWD_API char *php_realpath(const char *path, char *resolved) ++{ ++ struct stat sb; ++ char *p, *q, *s; ++ size_t left_len, resolved_len; ++ unsigned symlinks; ++ int serrno, slen; ++ int is_dir = 1; ++ char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX]; ++ ++ serrno = errno; ++ symlinks = 0; ++ if (path[0] == '/') { ++ resolved[0] = '/'; ++ resolved[1] = '\0'; ++ if (path[1] == '\0') ++ return (resolved); ++ resolved_len = 1; ++ left_len = strlcpy(left, path + 1, sizeof(left)); ++ } else { ++ if (getcwd(resolved, PATH_MAX) == NULL) { ++ strlcpy(resolved, ".", PATH_MAX); ++ return (NULL); ++ } ++ resolved_len = strlen(resolved); ++ left_len = strlcpy(left, path, sizeof(left)); ++ } ++ if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ ++ /* ++ * Iterate over path components in `left'. ++ */ ++ while (left_len != 0) { ++ /* ++ * Extract the next path component and adjust `left' ++ * and its length. ++ */ ++ p = strchr(left, '/'); ++ s = p ? p : left + left_len; ++ if (s - left >= sizeof(next_token)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ memcpy(next_token, left, s - left); ++ next_token[s - left] = '\0'; ++ left_len -= s - left; ++ if (p != NULL) ++ memmove(left, s + 1, left_len + 1); ++ if (resolved[resolved_len - 1] != '/') { ++ if (resolved_len + 1 >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ resolved[resolved_len++] = '/'; ++ resolved[resolved_len] = '\0'; ++ } ++ if (next_token[0] == '\0') ++ continue; ++ else if (strcmp(next_token, ".") == 0){ ++ if (!is_dir) { ++ resolved_len = strlcat(resolved, "#", PATH_MAX); ++ if (resolved_len >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ return resolved; ++ } ++ continue; ++ } else if (strcmp(next_token, "..") == 0) { ++ /* ++ * Strip the last path component except when we have ++ * single "/" ++ */ ++ if (!is_dir) { ++ errno = ENOENT; ++ return (NULL); ++ } ++ if (resolved_len > 1) { ++ resolved[resolved_len - 1] = '\0'; ++ q = strrchr(resolved, '/'); ++ *q = '\0'; ++ resolved_len = q - resolved; ++ } ++ continue; ++ } ++ ++ /* ++ * Append the next path component and lstat() it. If ++ * lstat() fails we still can return successfully if ++ * there are no more path components left. ++ */ ++ resolved_len = strlcat(resolved, next_token, PATH_MAX); ++ if (resolved_len >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ if (lstat(resolved, &sb) != 0) { ++ if (errno == ENOENT) { ++ if (p == NULL) { ++ errno = serrno; ++ return NULL; ++ return (resolved); ++ } /*else if (strstr(left, "/.") == NULL && strstr(left, "./") == NULL) { ++ resolved_len = strlcat(resolved, "/", PATH_MAX); ++ resolved_len = strlcat(resolved, left, PATH_MAX); ++ if (resolved_len >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ errno = serrno; ++ return (resolved); ++ } */ ++ } ++ return (NULL); ++ } ++ if (S_ISLNK(sb.st_mode)) { ++ if (symlinks++ > MAXSYMLINKS) { ++ errno = ELOOP; ++ return (NULL); ++ } ++ slen = readlink(resolved, symlink, sizeof(symlink) - 1); ++ if (slen < 0) ++ return (NULL); ++ symlink[slen] = '\0'; ++ if (symlink[0] == '/') { ++ resolved[1] = 0; ++ resolved_len = 1; ++ } else if (resolved_len > 1) { ++ /* Strip the last path component. */ ++ resolved[resolved_len - 1] = '\0'; ++ q = strrchr(resolved, '/'); ++ *q = '\0'; ++ resolved_len = q - resolved; ++ } ++ ++ /* ++ * If there are any path components left, then ++ * append them to symlink. The result is placed ++ * in `left'. ++ */ ++ if (p != NULL) { ++ if (symlink[slen - 1] != '/') { ++ if (slen + 1 >= sizeof(symlink)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ symlink[slen] = '/'; ++ symlink[slen + 1] = 0; ++ } ++ left_len = strlcat(symlink, left, sizeof(left)); ++ if (left_len >= sizeof(left)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ } ++ left_len = strlcpy(left, symlink, sizeof(left)); ++ } else { ++ if (S_ISDIR(sb.st_mode)) { ++ is_dir = 1; ++ } else { ++ is_dir = 0; ++ } ++ } ++ } ++ ++ /* ++ * Remove trailing slash except when the resolved pathname ++ * is a single "/". ++ */ ++ if (resolved_len > 1 && resolved[resolved_len - 1] == '/') { ++ if (!is_dir) { ++ errno = ENOENT; ++ return (NULL); ++ } ++ resolved[resolved_len - 1] = '\0'; ++ } ++ return (resolved); ++} ++#endif ++ ++ + CWD_API void virtual_cwd_startup(void) /* {{{ */ + { + char cwd[MAXPATHLEN]; +--- php.orig/TSRM/tsrm_virtual_cwd.h ++++ php/TSRM/tsrm_virtual_cwd.h +@@ -139,6 +139,22 @@ typedef struct _cwd_state { + + typedef int (*verify_path_func)(const cwd_state *); + ++#ifndef HAVE_STRLCPY ++CWD_API size_t php_strlcpy(char *dst, const char *src, size_t siz); ++#undef strlcpy ++#define strlcpy php_strlcpy ++#endif ++ ++#ifndef HAVE_STRLCAT ++CWD_API size_t php_strlcat(char *dst, const char *src, size_t siz); ++#undef strlcat ++#define strlcat php_strlcat ++#endif ++ ++ ++#if SUHOSIN_PATCH ++CWD_API char *php_realpath(const char *path, char *resolved); ++#endif + CWD_API void virtual_cwd_startup(void); + CWD_API void virtual_cwd_shutdown(void); + CWD_API char *virtual_getcwd_ex(size_t *length TSRMLS_DC); +--- php.orig/Zend/Makefile.am ++++ php/Zend/Makefile.am +@@ -17,7 +17,7 @@ libZend_la_SOURCES=\ + zend_objects_API.c zend_ts_hash.c zend_stream.c \ + zend_default_classes.c \ + zend_iterators.c zend_interfaces.c zend_exceptions.c \ +- zend_strtod.c zend_multibyte.c ++ zend_strtod.c zend_multibyte.c zend_canary.c + + libZend_la_LDFLAGS = + libZend_la_LIBADD = @ZEND_EXTRA_LIBS@ +--- php.orig/Zend/Zend.dsp ++++ php/Zend/Zend.dsp +@@ -239,6 +239,10 @@ SOURCE=.\zend_strtod.c + # End Source File + # Begin Source File + ++SOURCE=.\zend_canary.c ++# End Source File ++# Begin Source File ++ + SOURCE=.\zend_ts_hash.c + # End Source File + # Begin Source File +--- php.orig/Zend/ZendTS.dsp ++++ php/Zend/ZendTS.dsp +@@ -273,6 +273,10 @@ SOURCE=.\zend_strtod.c + # End Source File + # Begin Source File + ++SOURCE=.\zend_canary.c ++# End Source File ++# Begin Source File ++ + SOURCE=.\zend_ts_hash.c + # End Source File + # Begin Source File +--- php.orig/Zend/zend.c ++++ php/Zend/zend.c +@@ -57,7 +57,9 @@ ZEND_API void (*zend_ticks_function)(int + ZEND_API void (*zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args); + int (*zend_vspprintf)(char **pbuf, size_t max_len, const char *format, va_list ap); + ZEND_API char *(*zend_getenv)(char *name, size_t name_len TSRMLS_DC); +- ++#if SUHOSIN_PATCH ++ZEND_API void (*zend_suhosin_log)(int loglevel, char *fmt, ...); ++#endif + void (*zend_on_timeout)(int seconds TSRMLS_DC); + + static void (*zend_message_dispatcher_p)(long message, void *data); +@@ -74,9 +76,88 @@ static ZEND_INI_MH(OnUpdateErrorReportin + return SUCCESS; + } + ++#if SUHOSIN_PATCH ++static ZEND_INI_MH(OnUpdateSuhosin_log_syslog) ++{ ++ if (!new_value) { ++ SPG(log_syslog) = S_ALL & ~S_SQL | S_MEMORY; ++ } else { ++ SPG(log_syslog) = atoi(new_value) | S_MEMORY; ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateSuhosin_log_syslog_facility) ++{ ++ if (!new_value) { ++ SPG(log_syslog_facility) = LOG_USER; ++ } else { ++ SPG(log_syslog_facility) = atoi(new_value); ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateSuhosin_log_syslog_priority) ++{ ++ if (!new_value) { ++ SPG(log_syslog_priority) = LOG_ALERT; ++ } else { ++ SPG(log_syslog_priority) = atoi(new_value); ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateSuhosin_log_sapi) ++{ ++ if (!new_value) { ++ SPG(log_sapi) = S_ALL & ~S_SQL; ++ } else { ++ SPG(log_sapi) = atoi(new_value); ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateSuhosin_log_script) ++{ ++ if (!new_value) { ++ SPG(log_script) = S_ALL & ~S_MEMORY; ++ } else { ++ SPG(log_script) = atoi(new_value) & (~S_MEMORY) & (~S_INTERNAL); ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateSuhosin_log_scriptname) ++{ ++ if (SPG(log_scriptname)) { ++ pefree(SPG(log_scriptname),1); ++ } ++ SPG(log_scriptname) = NULL; ++ if (new_value) { ++ SPG(log_scriptname) = pestrdup(new_value,1); ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateSuhosin_log_phpscript) ++{ ++ if (!new_value) { ++ SPG(log_phpscript) = S_ALL & ~S_MEMORY; ++ } else { ++ SPG(log_phpscript) = atoi(new_value) & (~S_MEMORY) & (~S_INTERNAL); ++ } ++ return SUCCESS; ++} ++#endif + + ZEND_INI_BEGIN() + ZEND_INI_ENTRY("error_reporting", NULL, ZEND_INI_ALL, OnUpdateErrorReporting) ++#if SUHOSIN_PATCH ++ ZEND_INI_ENTRY("suhosin.log.syslog", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateSuhosin_log_syslog) ++ ZEND_INI_ENTRY("suhosin.log.syslog.facility", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateSuhosin_log_syslog_facility) ++ ZEND_INI_ENTRY("suhosin.log.syslog.priority", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateSuhosin_log_syslog_priority) ++ ZEND_INI_ENTRY("suhosin.log.sapi", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateSuhosin_log_sapi) ++ ZEND_INI_ENTRY("suhosin.log.script", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateSuhosin_log_script) ++ ZEND_INI_ENTRY("suhosin.log.script.name", NULL, ZEND_INI_SYSTEM, OnUpdateSuhosin_log_scriptname) ++ STD_ZEND_INI_BOOLEAN("suhosin.log.use-x-forwarded-for", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateBool, log_use_x_forwarded_for, suhosin_patch_globals_struct, suhosin_patch_globals) ++ ZEND_INI_ENTRY("suhosin.log.phpscript", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateSuhosin_log_phpscript) ++ STD_ZEND_INI_ENTRY("suhosin.log.phpscript.name", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateString, log_phpscriptname, suhosin_patch_globals_struct, suhosin_patch_globals) ++ STD_ZEND_INI_BOOLEAN("suhosin.log.phpscript.is_safe", "0", ZEND_INI_SYSTEM, OnUpdateBool, log_phpscript_is_safe, suhosin_patch_globals_struct, suhosin_patch_globals) ++#endif + STD_ZEND_INI_BOOLEAN("zend.ze1_compatibility_mode", "0", ZEND_INI_ALL, OnUpdateBool, ze1_compatibility_mode, zend_executor_globals, executor_globals) + #ifdef ZEND_MULTIBYTE + STD_ZEND_INI_BOOLEAN("detect_unicode", "1", ZEND_INI_ALL, OnUpdateBool, detect_unicode, zend_compiler_globals, compiler_globals) +--- php.orig/Zend/zend.h ++++ php/Zend/zend.h +@@ -550,6 +550,9 @@ extern void (*zend_on_timeout)(int secon + extern ZEND_API int (*zend_stream_open_function)(const char *filename, zend_file_handle *handle TSRMLS_DC); + extern int (*zend_vspprintf)(char **pbuf, size_t max_len, const char *format, va_list ap); + extern ZEND_API char *(*zend_getenv)(char *name, size_t name_len TSRMLS_DC); ++#if SUHOSIN_PATCH ++extern ZEND_API void (*zend_suhosin_log)(int loglevel, char *fmt, ...); ++#endif + + + ZEND_API void zend_error(int type, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); +@@ -681,6 +684,13 @@ END_EXTERN_C() + #include "zend_operators.h" + #include "zend_variables.h" + ++#if SUHOSIN_PATCH ++#include "suhosin_globals.h" ++#include "php_syslog.h" ++ ++ZEND_API size_t zend_canary(); ++#endif ++ + #endif /* ZEND_H */ + + /* +--- php.orig/Zend/zend_alloc.c ++++ php/Zend/zend_alloc.c +@@ -316,13 +316,26 @@ static const zend_mm_mem_handlers mem_ha + #define MEM_BLOCK_GUARD 0x2A8FCC84 + #define MEM_BLOCK_LEAK 0x6C5E8F2D + ++#if SUHOSIN_PATCH ++# define CANARY_SIZE sizeof(size_t) ++#else ++# define CANARY_SIZE 0 ++#endif ++ + /* mm block type */ + typedef struct _zend_mm_block_info { + #if ZEND_MM_COOKIES + size_t _cookie; + #endif +- size_t _size; +- size_t _prev; ++#if SUHOSIN_PATCH ++ size_t canary_1; ++#endif ++ size_t _size; ++ size_t _prev; ++#if SUHOSIN_PATCH ++ size_t size; ++ size_t canary_2; ++#endif + } zend_mm_block_info; + + #if ZEND_DEBUG +@@ -428,6 +441,9 @@ struct _zend_mm_heap { + int miss; + } cache_stat[ZEND_MM_NUM_BUCKETS+1]; + #endif ++#if SUHOSIN_PATCH ++ size_t canary_1,canary_2,canary_3; ++#endif + }; + + #define ZEND_MM_SMALL_FREE_BUCKET(heap, index) \ +@@ -517,15 +533,15 @@ static unsigned int _zend_mm_cookie = 0; + #define ZEND_MM_ALIGNED_SIZE(size) ((size + ZEND_MM_ALIGNMENT - 1) & ZEND_MM_ALIGNMENT_MASK) + #define ZEND_MM_ALIGNED_HEADER_SIZE ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_block)) + #define ZEND_MM_ALIGNED_FREE_HEADER_SIZE ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_small_free_block)) +-#define ZEND_MM_MIN_ALLOC_BLOCK_SIZE ZEND_MM_ALIGNED_SIZE(ZEND_MM_ALIGNED_HEADER_SIZE + END_MAGIC_SIZE) ++#define ZEND_MM_MIN_ALLOC_BLOCK_SIZE ZEND_MM_ALIGNED_SIZE(ZEND_MM_ALIGNED_HEADER_SIZE + END_MAGIC_SIZE + CANARY_SIZE) + #define ZEND_MM_ALIGNED_MIN_HEADER_SIZE (ZEND_MM_MIN_ALLOC_BLOCK_SIZE>ZEND_MM_ALIGNED_FREE_HEADER_SIZE?ZEND_MM_MIN_ALLOC_BLOCK_SIZE:ZEND_MM_ALIGNED_FREE_HEADER_SIZE) + #define ZEND_MM_ALIGNED_SEGMENT_SIZE ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_segment)) + +-#define ZEND_MM_MIN_SIZE ((ZEND_MM_ALIGNED_MIN_HEADER_SIZE>(ZEND_MM_ALIGNED_HEADER_SIZE+END_MAGIC_SIZE))?(ZEND_MM_ALIGNED_MIN_HEADER_SIZE-(ZEND_MM_ALIGNED_HEADER_SIZE+END_MAGIC_SIZE)):0) ++#define ZEND_MM_MIN_SIZE ((ZEND_MM_ALIGNED_MIN_HEADER_SIZE>(ZEND_MM_ALIGNED_HEADER_SIZE+END_MAGIC_SIZE+CANARY_SIZE))?(ZEND_MM_ALIGNED_MIN_HEADER_SIZE-(ZEND_MM_ALIGNED_HEADER_SIZE+END_MAGIC_SIZE+CANARY_SIZE)):0) + + #define ZEND_MM_MAX_SMALL_SIZE ((ZEND_MM_NUM_BUCKETS<>ZEND_MM_ALIGNMENT_LOG2)-(ZEND_MM_ALIGNED_MIN_HEADER_SIZE>>ZEND_MM_ALIGNMENT_LOG2)) + +@@ -587,6 +603,48 @@ static unsigned int _zend_mm_cookie = 0; + + #endif + ++#if SUHOSIN_PATCH ++ ++# define SUHOSIN_MM_CHECK_CANARIES(block, MFUNCTION) do { \ ++ char *p = SUHOSIN_MM_END_CANARY_PTR(block); size_t check; \ ++ if (((block)->info.canary_1 != heap->canary_1) || ((block)->info.canary_2 != heap->canary_2)) { \ ++ canary_mismatch: \ ++ zend_suhosin_log(S_MEMORY, "canary mismatch on " MFUNCTION " - heap overflow detected"); \ ++ exit(1); \ ++ } \ ++ memcpy(&check, p, CANARY_SIZE); \ ++ if (check != heap->canary_3) { \ ++ zend_suhosin_log(S_MEMORY, "canary mismatch on " MFUNCTION " - heap overflow detected"); \ ++ exit(1); \ ++ goto canary_mismatch; \ ++ } \ ++ } while (0) ++ ++# define SUHOSIN_MM_SET_CANARIES(block) do { \ ++ (block)->info.canary_1 = heap->canary_1; \ ++ (block)->info.canary_2 = heap->canary_2; \ ++ } while (0) ++ ++# define SUHOSIN_MM_END_CANARY_PTR(block) \ ++ (char *)(((char*)(ZEND_MM_DATA_OF(block))) + ((zend_mm_block*)(block))->info.size + END_MAGIC_SIZE) ++ ++# define SUHOSIN_MM_SET_END_CANARY(block) do { \ ++ char *p = SUHOSIN_MM_END_CANARY_PTR(block); \ ++ memcpy(p, &heap->canary_3, CANARY_SIZE); \ ++ } while (0) ++ ++#else ++ ++# define SUHOSIN_MM_CHECK_CANARIES(block) ++ ++# define SUHOSIN_MM_SET_CANARIES(block) ++ ++# define SUHOSIN_MM_END_CANARY_PTR(block) ++ ++# define SUHOSIN_MM_SET_END_CANARY(block) ++ ++#endif ++ + + #if ZEND_MM_HEAP_PROTECTION + +@@ -795,6 +853,12 @@ static inline void zend_mm_remove_from_f + if (EXPECTED(prev == mm_block)) { + zend_mm_free_block **rp, **cp; + ++#if SUHOSIN_PATCH ++ if (next != mm_block) { ++ zend_suhosin_log(S_MEMORY, "heap corrupt on efree() - heap corruption detected"); ++ exit(1); ++ } ++#endif + #if ZEND_MM_SAFE_UNLINKING + if (UNEXPECTED(next != mm_block)) { + zend_mm_panic("zend_mm_heap corrupted"); +@@ -833,6 +897,12 @@ subst_block: + } + } else { + ++#if SUHOSIN_PATCH ++ if (prev->next_free_block != mm_block || next->prev_free_block != mm_block) { ++ zend_suhosin_log(S_MEMORY, "linked list corrupt on efree() - heap corruption detected"); ++ exit(1); ++ } ++#endif + #if ZEND_MM_SAFE_UNLINKING + if (UNEXPECTED(prev->next_free_block != mm_block) || UNEXPECTED(next->prev_free_block != mm_block)) { + zend_mm_panic("zend_mm_heap corrupted"); +@@ -880,6 +950,11 @@ static inline void zend_mm_init(zend_mm_ + heap->large_free_buckets[i] = NULL; + } + heap->rest_buckets[0] = heap->rest_buckets[1] = ZEND_MM_REST_BUCKET(heap); ++#if SUHOSIN_PATCH ++ heap->canary_1 = zend_canary(); ++ heap->canary_2 = zend_canary(); ++ heap->canary_3 = zend_canary(); ++#endif + } + + static void zend_mm_del_segment(zend_mm_heap *heap, zend_mm_segment *segment) +@@ -1784,6 +1859,11 @@ static void *_zend_mm_alloc_int(zend_mm_ + best_fit = heap->cache[index]; + heap->cache[index] = best_fit->prev_free_block; + heap->cached -= true_size; ++#if SUHOSIN_PATCH ++ SUHOSIN_MM_SET_CANARIES(best_fit); ++ ((zend_mm_block*)best_fit)->info.size = size; ++ SUHOSIN_MM_SET_END_CANARY(best_fit); ++#endif + ZEND_MM_CHECK_MAGIC(best_fit, MEM_BLOCK_CACHED); + ZEND_MM_SET_DEBUG_INFO(best_fit, size, 1, 0); + return ZEND_MM_DATA_OF(best_fit); +@@ -1923,6 +2003,12 @@ zend_mm_finished_searching_for_block: + + ZEND_MM_SET_DEBUG_INFO(best_fit, size, 1, 1); + ++#if SUHOSIN_PATCH ++ SUHOSIN_MM_SET_CANARIES(best_fit); ++ ((zend_mm_block*)best_fit)->info.size = size; ++ SUHOSIN_MM_SET_END_CANARY(best_fit); ++#endif ++ + heap->size += true_size; + if (heap->peak < heap->size) { + heap->peak = heap->size; +@@ -1946,6 +2032,9 @@ static void _zend_mm_free_int(zend_mm_he + + mm_block = ZEND_MM_HEADER_OF(p); + size = ZEND_MM_BLOCK_SIZE(mm_block); ++#if SUHOSIN_PATCH ++ SUHOSIN_MM_CHECK_CANARIES(mm_block, "efree()"); ++#endif + ZEND_MM_CHECK_PROTECTION(mm_block); + + #if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION +@@ -2008,6 +2097,9 @@ static void *_zend_mm_realloc_int(zend_m + mm_block = ZEND_MM_HEADER_OF(p); + true_size = ZEND_MM_TRUE_SIZE(size); + orig_size = ZEND_MM_BLOCK_SIZE(mm_block); ++#if SUHOSIN_PATCH ++ SUHOSIN_MM_CHECK_CANARIES(mm_block, "erealloc()"); ++#endif + ZEND_MM_CHECK_PROTECTION(mm_block); + + if (UNEXPECTED(true_size < size)) { +@@ -2039,6 +2131,11 @@ static void *_zend_mm_realloc_int(zend_m + HANDLE_UNBLOCK_INTERRUPTIONS(); + } + ZEND_MM_SET_DEBUG_INFO(mm_block, size, 0, 0); ++#if SUHOSIN_PATCH ++ SUHOSIN_MM_SET_CANARIES(mm_block); ++ ((zend_mm_block*)mm_block)->info.size = size; ++ SUHOSIN_MM_SET_END_CANARY(mm_block); ++#endif + return p; + } + +@@ -2058,13 +2155,18 @@ static void *_zend_mm_realloc_int(zend_m + heap->cache[index] = best_fit->prev_free_block; + ZEND_MM_CHECK_MAGIC(best_fit, MEM_BLOCK_CACHED); + ZEND_MM_SET_DEBUG_INFO(best_fit, size, 1, 0); ++#if SUHOSIN_PATCH ++ SUHOSIN_MM_SET_CANARIES(best_fit); ++ ((zend_mm_block*)best_fit)->info.size = size; ++ SUHOSIN_MM_SET_END_CANARY(best_fit); ++#endif + + ptr = ZEND_MM_DATA_OF(best_fit); + + #if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION + memcpy(ptr, p, mm_block->debug.size); + #else +- memcpy(ptr, p, orig_size - ZEND_MM_ALIGNED_HEADER_SIZE); ++ memcpy(ptr, p, orig_size - ZEND_MM_ALIGNED_HEADER_SIZE - CANARY_SIZE); + #endif + + heap->cached -= true_size - orig_size; +@@ -2122,6 +2224,11 @@ static void *_zend_mm_realloc_int(zend_m + if (heap->peak < heap->size) { + heap->peak = heap->size; + } ++#if SUHOSIN_PATCH ++ SUHOSIN_MM_SET_CANARIES(mm_block); ++ ((zend_mm_block*)mm_block)->info.size = size; ++ SUHOSIN_MM_SET_END_CANARY(mm_block); ++#endif + HANDLE_UNBLOCK_INTERRUPTIONS(); + return p; + } else if (ZEND_MM_IS_FIRST_BLOCK(mm_block) && +@@ -2225,6 +2332,11 @@ out_of_memory: + } + + HANDLE_UNBLOCK_INTERRUPTIONS(); ++#if SUHOSIN_PATCH ++ SUHOSIN_MM_SET_CANARIES(mm_block); ++ ((zend_mm_block*)mm_block)->info.size = size; ++ SUHOSIN_MM_SET_END_CANARY(mm_block); ++#endif + return ZEND_MM_DATA_OF(mm_block); + } + +@@ -2232,7 +2344,7 @@ out_of_memory: + #if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION + memcpy(ptr, p, mm_block->debug.size); + #else +- memcpy(ptr, p, orig_size - ZEND_MM_ALIGNED_HEADER_SIZE); ++ memcpy(ptr, p, orig_size - ZEND_MM_ALIGNED_HEADER_SIZE - CANARY_SIZE); + #endif + _zend_mm_free_int(heap, p ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); + return ptr; +@@ -2499,6 +2611,17 @@ ZEND_API void shutdown_memory_manager(in + zend_mm_shutdown(AG(mm_heap), full_shutdown, silent); + } + ++#if SUHOSIN_PATCH ++ZEND_API void suhosin_clear_mm_canaries(TSRMLS_D) ++{ ++/* NOT HERE ++ ++ AG(mm_heap)->canary_1 = zend_canary(); ++ AG(mm_heap)->canary_2 = zend_canary(); ++ AG(mm_heap)->canary_3 = zend_canary(); */ ++} ++#endif ++ + static void alloc_globals_ctor(zend_alloc_globals *alloc_globals TSRMLS_DC) + { + char *tmp; +--- php.orig/Zend/zend_alloc.h ++++ php/Zend/zend_alloc.h +@@ -129,6 +129,9 @@ ZEND_API int zend_set_memory_limit(size_ + + ZEND_API void start_memory_manager(TSRMLS_D); + ZEND_API void shutdown_memory_manager(int silent, int full_shutdown TSRMLS_DC); ++#if SUHOSIN_PATCH ++ZEND_API void suhosin_clear_mm_canaries(TSRMLS_D); ++#endif + ZEND_API int is_zend_mm(TSRMLS_D); + + #if ZEND_DEBUG +--- /dev/null ++++ php/Zend/zend_canary.c +@@ -0,0 +1,64 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Suhosin-Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2006 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++/* $Id: zend_canary.c,v 1.1 2004/11/26 12:45:41 ionic Exp $ */ ++ ++#include "zend.h" ++ ++#include ++#include ++ ++ ++#if SUHOSIN_PATCH ++ ++static size_t last_canary = 0x73625123; ++ ++/* will be replaced later with more compatible method */ ++ZEND_API size_t zend_canary() ++{ ++ time_t t; ++ size_t canary; ++ int fd; ++ ++#ifndef PHP_WIN32 ++ fd = open("/dev/urandom", 0); ++ if (fd != -1) { ++ int r = read(fd, &canary, sizeof(canary)); ++ close(fd); ++ if (r == sizeof(canary)) { ++ return (canary); ++ } ++ } ++#endif ++ /* not good but we never want to do this */ ++ time(&t); ++ canary = *(unsigned int *)&t + getpid() << 16 + last_canary; ++ last_canary ^= (canary << 5) | (canary >> (32-5)); ++ return (canary); ++} ++ ++#endif ++ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: sw=4 ts=4 fdm=marker ++ * vim<600: sw=4 ts=4 ++ */ +--- php.orig/Zend/zend_compile.c ++++ php/Zend/zend_compile.c +@@ -54,7 +54,6 @@ static void zend_duplicate_property_info + property_info->name = zend_strndup(property_info->name, property_info->name_length); + } + +- + static void zend_destroy_property_info(zend_property_info *property_info) + { + efree(property_info->name); +@@ -68,6 +67,10 @@ static void zend_destroy_property_info_i + { + free(property_info->name); + } ++#if SUHOSIN_PATCH ++void *suhosin_zend_destroy_property_info_internal = zend_destroy_property_info_internal; ++void *suhosin_zend_destroy_property_info = zend_destroy_property_info; ++#endif + + static void build_runtime_defined_function_key(zval *result, char *name, int name_length TSRMLS_DC) + { +--- php.orig/Zend/zend_compile.h ++++ php/Zend/zend_compile.h +@@ -564,6 +564,11 @@ ZEND_API int zend_auto_global_disable_ji + + int zendlex(znode *zendlval TSRMLS_DC); + ++#if SUHOSIN_PATCH ++extern void *suhosin_zend_destroy_property_info_internal; ++extern void *suhosin_zend_destroy_property_info; ++#endif ++ + /* BEGIN: OPCODES */ + + #include "zend_vm_opcodes.h" +@@ -689,6 +694,7 @@ int zendlex(znode *zendlval TSRMLS_DC); + #define ZEND_RETURNS_FUNCTION 1<<0 + #define ZEND_RETURNS_NEW 1<<1 + ++ + END_EXTERN_C() + + #define ZEND_CLONE_FUNC_NAME "__clone" +--- php.orig/Zend/zend_constants.c ++++ php/Zend/zend_constants.c +@@ -110,6 +110,75 @@ void zend_register_standard_constants(TS + REGISTER_MAIN_LONG_CONSTANT("E_USER_NOTICE", E_USER_NOTICE, CONST_PERSISTENT | CONST_CS); + + REGISTER_MAIN_LONG_CONSTANT("E_ALL", E_ALL, CONST_PERSISTENT | CONST_CS); ++#if SUHOSIN_PATCH ++ REGISTER_MAIN_LONG_CONSTANT("S_MEMORY", S_MEMORY, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_VARS", S_VARS, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_FILES", S_FILES, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_INCLUDE", S_INCLUDE, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_SQL", S_SQL, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_EXECUTOR", S_EXECUTOR, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_MAIL", S_MAIL, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_SESSION", S_SESSION, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_MISC", S_MISC, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_INTERNAL", S_INTERNAL, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_ALL", S_ALL, CONST_PERSISTENT | CONST_CS); ++ ++ /* error levels */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_EMERG", LOG_EMERG, CONST_CS | CONST_PERSISTENT); /* system unusable */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_ALERT", LOG_ALERT, CONST_CS | CONST_PERSISTENT); /* immediate action required */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_CRIT", LOG_CRIT, CONST_CS | CONST_PERSISTENT); /* critical conditions */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_ERR", LOG_ERR, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_WARNING", LOG_WARNING, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NOTICE", LOG_NOTICE, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_INFO", LOG_INFO, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_DEBUG", LOG_DEBUG, CONST_CS | CONST_PERSISTENT); ++ /* facility: type of program logging the message */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_KERN", LOG_KERN, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_USER", LOG_USER, CONST_CS | CONST_PERSISTENT); /* generic user level */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_MAIL", LOG_MAIL, CONST_CS | CONST_PERSISTENT); /* log to email */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_DAEMON", LOG_DAEMON, CONST_CS | CONST_PERSISTENT); /* other system daemons */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_AUTH", LOG_AUTH, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_SYSLOG", LOG_SYSLOG, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LPR", LOG_LPR, CONST_CS | CONST_PERSISTENT); ++#ifdef LOG_NEWS ++ /* No LOG_NEWS on HP-UX */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NEWS", LOG_NEWS, CONST_CS | CONST_PERSISTENT); /* usenet new */ ++#endif ++#ifdef LOG_UUCP ++ /* No LOG_UUCP on HP-UX */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_UUCP", LOG_UUCP, CONST_CS | CONST_PERSISTENT); ++#endif ++#ifdef LOG_CRON ++ /* apparently some systems don't have this one */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_CRON", LOG_CRON, CONST_CS | CONST_PERSISTENT); ++#endif ++#ifdef LOG_AUTHPRIV ++ /* AIX doesn't have LOG_AUTHPRIV */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_AUTHPRIV", LOG_AUTHPRIV, CONST_CS | CONST_PERSISTENT); ++#endif ++#if !defined(PHP_WIN32) && !defined(NETWARE) ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL0", LOG_LOCAL0, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL1", LOG_LOCAL1, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL2", LOG_LOCAL2, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL3", LOG_LOCAL3, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL4", LOG_LOCAL4, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL5", LOG_LOCAL5, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL6", LOG_LOCAL6, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL7", LOG_LOCAL7, CONST_CS | CONST_PERSISTENT); ++#endif ++ /* options */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_PID", LOG_PID, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_CONS", LOG_CONS, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_ODELAY", LOG_ODELAY, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NDELAY", LOG_NDELAY, CONST_CS | CONST_PERSISTENT); ++#ifdef LOG_NOWAIT ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NOWAIT", LOG_NOWAIT, CONST_CS | CONST_PERSISTENT); ++#endif ++#ifdef LOG_PERROR ++ /* AIX doesn't have LOG_PERROR */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_PERROR", LOG_PERROR, CONST_CS | CONST_PERSISTENT); /*log to stderr*/ ++#endif ++#endif + + /* true/false constants */ + { +--- php.orig/Zend/zend_errors.h ++++ php/Zend/zend_errors.h +@@ -39,6 +39,20 @@ + #define E_ALL (E_ERROR | E_WARNING | E_PARSE | E_NOTICE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING | E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE | E_RECOVERABLE_ERROR) + #define E_CORE (E_CORE_ERROR | E_CORE_WARNING) + ++#if SUHOSIN_PATCH ++#define S_MEMORY (1<<0L) ++#define S_MISC (1<<1L) ++#define S_VARS (1<<2L) ++#define S_FILES (1<<3L) ++#define S_INCLUDE (1<<4L) ++#define S_SQL (1<<5L) ++#define S_EXECUTOR (1<<6L) ++#define S_MAIL (1<<7L) ++#define S_SESSION (1<<8L) ++#define S_INTERNAL (1<<29L) ++#define S_ALL (S_MEMORY | S_VARS | S_INCLUDE | S_FILES | S_MAIL | S_SESSION | S_MISC | S_SQL | S_EXECUTOR) ++#endif ++ + #endif /* ZEND_ERRORS_H */ + + /* +--- php.orig/Zend/zend_hash.c ++++ php/Zend/zend_hash.c +@@ -20,6 +20,7 @@ + /* $Id: zend_hash.c,v 1.121.2.4.2.11 2009/06/07 19:28:32 mattwil Exp $ */ + + #include "zend.h" ++#include "zend_compile.h" + + #define CONNECT_TO_BUCKET_DLLIST(element, list_head) \ + (element)->pNext = (list_head); \ +@@ -132,7 +133,189 @@ ZEND_API ulong zend_hash_func(char *arKe + (p)->pDataPtr=NULL; \ + } + ++#if SUHOSIN_PATCH ++#ifdef ZTS ++MUTEX_T zend_hash_dprot_mx_reader; ++MUTEX_T zend_hash_dprot_mx_writer; ++unsigned int zend_hash_dprot_reader; ++#endif ++unsigned int zend_hash_dprot_counter; ++unsigned int zend_hash_dprot_curmax; ++dtor_func_t *zend_hash_dprot_table = NULL; ++ ++static void zend_hash_dprot_begin_read() ++{ ++#ifdef ZTS ++ tsrm_mutex_lock(zend_hash_dprot_mx_reader); ++ if ((++(zend_hash_dprot_reader)) == 1) { ++ tsrm_mutex_lock(zend_hash_dprot_mx_writer); ++ } ++ tsrm_mutex_unlock(zend_hash_dprot_mx_reader); ++#endif ++} ++ ++static void zend_hash_dprot_end_read() ++{ ++#ifdef ZTS ++ tsrm_mutex_lock(zend_hash_dprot_mx_reader); ++ if ((--(zend_hash_dprot_reader)) == 0) { ++ tsrm_mutex_unlock(zend_hash_dprot_mx_writer); ++ } ++ tsrm_mutex_unlock(zend_hash_dprot_mx_reader); ++#endif ++} ++ ++static void zend_hash_dprot_begin_write() ++{ ++#ifdef ZTS ++ tsrm_mutex_lock(zend_hash_dprot_mx_writer); ++#endif ++} ++ ++static void zend_hash_dprot_end_write() ++{ ++#ifdef ZTS ++ tsrm_mutex_unlock(zend_hash_dprot_mx_writer); ++#endif ++} ++ ++/*ZEND_API void zend_hash_dprot_dtor() ++{ ++#ifdef ZTS ++ tsrm_mutex_free(zend_hash_dprot_mx_reader); ++ tsrm_mutex_free(zend_hash_dprot_mx_writer); ++#endif ++ free(zend_hash_dprot_table); ++}*/ ++ ++static void zend_hash_add_destructor(dtor_func_t pDestructor) ++{ ++ int left, right, mid; ++ zend_bool found = 0; ++ unsigned long value; ++ ++ if (pDestructor == NULL || pDestructor == ZVAL_PTR_DTOR || pDestructor == ZVAL_INTERNAL_PTR_DTOR ++ || pDestructor == ZEND_FUNCTION_DTOR || pDestructor == ZEND_CLASS_DTOR) { ++ return; ++ } ++ ++ if (zend_hash_dprot_table == NULL) { ++#ifdef ZTS ++ zend_hash_dprot_mx_reader = tsrm_mutex_alloc(); ++ zend_hash_dprot_mx_writer = tsrm_mutex_alloc(); ++ zend_hash_dprot_reader = 0; ++#endif ++ zend_hash_dprot_counter = 0; ++ zend_hash_dprot_curmax = 256; ++ zend_hash_dprot_table = (dtor_func_t *) malloc(256 * sizeof(dtor_func_t)); ++ } ++ ++ zend_hash_dprot_begin_write(); ++ ++ if (zend_hash_dprot_counter == 0) { ++ zend_hash_dprot_counter++; ++ zend_hash_dprot_table[0] = pDestructor; ++ } else { ++ value = (unsigned long) pDestructor; ++ left = 0; ++ right = zend_hash_dprot_counter-1; ++ mid = 0; ++ ++ while (left < right) { ++ mid = (right - left) >> 1; ++ mid += left; ++ if ((unsigned long)zend_hash_dprot_table[mid] == value) { ++ found = 1; ++ break; ++ } ++ if (value < (unsigned long)zend_hash_dprot_table[mid]) { ++ right = mid-1; ++ } else { ++ left = mid+1; ++ } ++ } ++ if ((unsigned long)zend_hash_dprot_table[left] == value) { ++ found = 1; ++ } ++ ++ if (!found) { ++ ++ if (zend_hash_dprot_counter >= zend_hash_dprot_curmax) { ++ zend_hash_dprot_curmax += 256; ++ zend_hash_dprot_table = (dtor_func_t *) realloc(zend_hash_dprot_table, zend_hash_dprot_curmax * sizeof(dtor_func_t)); ++ } ++ ++ if ((unsigned long)zend_hash_dprot_table[left] < value) { ++ memmove(zend_hash_dprot_table+left+2, zend_hash_dprot_table+left+1, (zend_hash_dprot_counter-left-1)*sizeof(dtor_func_t)); ++ zend_hash_dprot_table[left+1] = pDestructor; ++ } else { ++ memmove(zend_hash_dprot_table+left+1, zend_hash_dprot_table+left, (zend_hash_dprot_counter-left)*sizeof(dtor_func_t)); ++ zend_hash_dprot_table[left] = pDestructor; ++ } ++ ++ zend_hash_dprot_counter++; ++ } ++ } ++ ++ zend_hash_dprot_end_write(); ++} ++ ++static void zend_hash_check_destructor(dtor_func_t pDestructor) ++{ ++ unsigned long value; ++ ++ if (pDestructor == NULL || pDestructor == ZVAL_PTR_DTOR || pDestructor == ZVAL_INTERNAL_PTR_DTOR ++#ifdef ZEND_ENGINE_2 ++ || pDestructor == suhosin_zend_destroy_property_info_internal || pDestructor == suhosin_zend_destroy_property_info ++#endif ++ || pDestructor == ZEND_FUNCTION_DTOR || pDestructor == ZEND_CLASS_DTOR) { ++ return; ++ } ++ ++ zend_hash_dprot_begin_read(); ++ ++ if (zend_hash_dprot_counter > 0) { ++ int left, right, mid; ++ zend_bool found = 0; ++ ++ value = (unsigned long) pDestructor; ++ left = 0; ++ right = zend_hash_dprot_counter-1; ++ ++ while (left < right) { ++ mid = (right - left) >> 1; ++ mid += left; ++ if ((unsigned long)zend_hash_dprot_table[mid] == value) { ++ found = 1; ++ break; ++ } ++ if (value < (unsigned long)zend_hash_dprot_table[mid]) { ++ right = mid-1; ++ } else { ++ left = mid+1; ++ } ++ } ++ if ((unsigned long)zend_hash_dprot_table[left] == value) { ++ found = 1; ++ } ++ ++ if (!found) { ++ zend_hash_dprot_end_read(); ++ ++ zend_suhosin_log(S_MEMORY, "possible memory corruption detected - unknown Hashtable destructor"); ++ exit(1); ++ return; ++ } ++ ++ } ++ ++ zend_hash_dprot_end_read(); ++} + ++#else ++#define zend_hash_add_destructor(pDestructor) do {} while(0) ++#define zend_hash_check_destructor(pDestructor) do {} while(0) ++#endif + + ZEND_API int _zend_hash_init(HashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, zend_bool persistent ZEND_FILE_LINE_DC) + { +@@ -153,6 +336,7 @@ ZEND_API int _zend_hash_init(HashTable * + + ht->nTableMask = ht->nTableSize - 1; + ht->pDestructor = pDestructor; ++ zend_hash_add_destructor(pDestructor); + ht->arBuckets = NULL; + ht->pListHead = NULL; + ht->pListTail = NULL; +@@ -230,6 +414,8 @@ ZEND_API int _zend_hash_add_or_update(Ha + return FAILURE; + } + #endif ++ ++ zend_hash_check_destructor(ht->pDestructor); + if (ht->pDestructor) { + ht->pDestructor(p->pData); + } +@@ -295,6 +481,7 @@ ZEND_API int _zend_hash_quick_add_or_upd + return FAILURE; + } + #endif ++ zend_hash_check_destructor(ht->pDestructor); + if (ht->pDestructor) { + ht->pDestructor(p->pData); + } +@@ -370,6 +557,7 @@ ZEND_API int _zend_hash_index_update_or_ + return FAILURE; + } + #endif ++ zend_hash_check_destructor(ht->pDestructor); + if (ht->pDestructor) { + ht->pDestructor(p->pData); + } +@@ -493,6 +681,7 @@ ZEND_API int zend_hash_del_key_or_index( + if (ht->pInternalPointer == p) { + ht->pInternalPointer = p->pListNext; + } ++ zend_hash_check_destructor(ht->pDestructor); + if (ht->pDestructor) { + ht->pDestructor(p->pData); + } +@@ -518,6 +707,8 @@ ZEND_API void zend_hash_destroy(HashTabl + + SET_INCONSISTENT(HT_IS_DESTROYING); + ++ zend_hash_check_destructor(ht->pDestructor); ++ + p = ht->pListHead; + while (p != NULL) { + q = p; +@@ -544,6 +735,8 @@ ZEND_API void zend_hash_clean(HashTable + + SET_INCONSISTENT(HT_CLEANING); + ++ zend_hash_check_destructor(ht->pDestructor); ++ + p = ht->pListHead; + while (p != NULL) { + q = p; +@@ -607,6 +800,7 @@ static Bucket *zend_hash_apply_deleter(H + ht->nNumOfElements--; + HANDLE_UNBLOCK_INTERRUPTIONS(); + ++ zend_hash_check_destructor(ht->pDestructor); + if (ht->pDestructor) { + ht->pDestructor(p->pData); + } +--- php.orig/Zend/zend_llist.c ++++ php/Zend/zend_llist.c +@@ -23,6 +23,184 @@ + #include "zend_llist.h" + #include "zend_qsort.h" + ++#if SUHOSIN_PATCH ++#ifdef ZTS ++MUTEX_T zend_llist_dprot_mx_reader; ++MUTEX_T zend_llist_dprot_mx_writer; ++unsigned int zend_llist_dprot_reader; ++#endif ++unsigned int zend_llist_dprot_counter; ++unsigned int zend_llist_dprot_curmax; ++llist_dtor_func_t *zend_llist_dprot_table = NULL; ++ ++static void zend_llist_dprot_begin_read() ++{ ++#ifdef ZTS ++ tsrm_mutex_lock(zend_llist_dprot_mx_reader); ++ if ((++(zend_llist_dprot_reader)) == 1) { ++ tsrm_mutex_lock(zend_llist_dprot_mx_writer); ++ } ++ tsrm_mutex_unlock(zend_llist_dprot_mx_reader); ++#endif ++} ++ ++static void zend_llist_dprot_end_read() ++{ ++#ifdef ZTS ++ tsrm_mutex_lock(zend_llist_dprot_mx_reader); ++ if ((--(zend_llist_dprot_reader)) == 0) { ++ tsrm_mutex_unlock(zend_llist_dprot_mx_writer); ++ } ++ tsrm_mutex_unlock(zend_llist_dprot_mx_reader); ++#endif ++} ++ ++static void zend_llist_dprot_begin_write() ++{ ++#ifdef ZTS ++ tsrm_mutex_lock(zend_llist_dprot_mx_writer); ++#endif ++} ++ ++static void zend_llist_dprot_end_write() ++{ ++#ifdef ZTS ++ tsrm_mutex_unlock(zend_llist_dprot_mx_writer); ++#endif ++} ++ ++/*ZEND_API void zend_llist_dprot_dtor() ++{ ++#ifdef ZTS ++ tsrm_mutex_free(zend_llist_dprot_mx_reader); ++ tsrm_mutex_free(zend_llist_dprot_mx_writer); ++#endif ++ free(zend_llist_dprot_table); ++}*/ ++ ++static void zend_llist_add_destructor(llist_dtor_func_t pDestructor) ++{ ++ int left, right, mid; ++ zend_bool found = 0; ++ unsigned long value; ++ ++ if (pDestructor == NULL || pDestructor == ZVAL_PTR_DTOR) { ++ return; ++ } ++ ++ if (zend_llist_dprot_table == NULL) { ++#ifdef ZTS ++ zend_llist_dprot_mx_reader = tsrm_mutex_alloc(); ++ zend_llist_dprot_mx_writer = tsrm_mutex_alloc(); ++ zend_llist_dprot_reader = 0; ++#endif ++ zend_llist_dprot_counter = 0; ++ zend_llist_dprot_curmax = 256; ++ zend_llist_dprot_table = (llist_dtor_func_t *) malloc(256 * sizeof(llist_dtor_func_t)); ++ } ++ ++ zend_llist_dprot_begin_write(); ++ ++ if (zend_llist_dprot_counter == 0) { ++ zend_llist_dprot_counter++; ++ zend_llist_dprot_table[0] = pDestructor; ++ } else { ++ value = (unsigned long) pDestructor; ++ left = 0; ++ right = zend_llist_dprot_counter-1; ++ mid = 0; ++ ++ while (left < right) { ++ mid = (right - left) >> 1; ++ mid += left; ++ if ((unsigned long)zend_llist_dprot_table[mid] == value) { ++ found = 1; ++ break; ++ } ++ if (value < (unsigned long)zend_llist_dprot_table[mid]) { ++ right = mid-1; ++ } else { ++ left = mid+1; ++ } ++ } ++ if ((unsigned long)zend_llist_dprot_table[left] == value) { ++ found = 1; ++ } ++ ++ if (!found) { ++ ++ if (zend_llist_dprot_counter >= zend_llist_dprot_curmax) { ++ zend_llist_dprot_curmax += 256; ++ zend_llist_dprot_table = (llist_dtor_func_t *) realloc(zend_llist_dprot_table, zend_llist_dprot_curmax * sizeof(llist_dtor_func_t)); ++ } ++ ++ if ((unsigned long)zend_llist_dprot_table[left] < value) { ++ memmove(zend_llist_dprot_table+left+2, zend_llist_dprot_table+left+1, (zend_llist_dprot_counter-left-1)*sizeof(llist_dtor_func_t)); ++ zend_llist_dprot_table[left+1] = pDestructor; ++ } else { ++ memmove(zend_llist_dprot_table+left+1, zend_llist_dprot_table+left, (zend_llist_dprot_counter-left)*sizeof(llist_dtor_func_t)); ++ zend_llist_dprot_table[left] = pDestructor; ++ } ++ ++ zend_llist_dprot_counter++; ++ } ++ } ++ ++ zend_llist_dprot_end_write(); ++} ++ ++static void zend_llist_check_destructor(llist_dtor_func_t pDestructor) ++{ ++ unsigned long value; ++ ++ if (pDestructor == NULL || pDestructor == ZVAL_PTR_DTOR) { ++ return; ++ } ++ ++ zend_llist_dprot_begin_read(); ++ ++ if (zend_llist_dprot_counter > 0) { ++ int left, right, mid; ++ zend_bool found = 0; ++ ++ value = (unsigned long) pDestructor; ++ left = 0; ++ right = zend_llist_dprot_counter-1; ++ ++ while (left < right) { ++ mid = (right - left) >> 1; ++ mid += left; ++ if ((unsigned long)zend_llist_dprot_table[mid] == value) { ++ found = 1; ++ break; ++ } ++ if (value < (unsigned long)zend_llist_dprot_table[mid]) { ++ right = mid-1; ++ } else { ++ left = mid+1; ++ } ++ } ++ if ((unsigned long)zend_llist_dprot_table[left] == value) { ++ found = 1; ++ } ++ ++ if (!found) { ++ zend_llist_dprot_end_read(); ++ ++ zend_suhosin_log(S_MEMORY, "possible memory corruption detected - unknown llist destructor"); ++ exit(1); ++ return; ++ } ++ ++ } ++ ++ zend_llist_dprot_end_read(); ++} ++#else ++#define zend_llist_add_destructor(pDestructor) do {} while(0) ++#define zend_llist_check_destructor(pDestructor) do {} while(0) ++#endif ++ + ZEND_API void zend_llist_init(zend_llist *l, size_t size, llist_dtor_func_t dtor, unsigned char persistent) + { + l->head = NULL; +@@ -30,6 +208,7 @@ ZEND_API void zend_llist_init(zend_llist + l->count = 0; + l->size = size; + l->dtor = dtor; ++ zend_llist_add_destructor(dtor); + l->persistent = persistent; + } + +@@ -81,6 +260,7 @@ ZEND_API void zend_llist_prepend_element + } else {\ + (l)->tail = (current)->prev;\ + }\ ++ zend_llist_check_destructor((l)->dtor); \ + if ((l)->dtor) {\ + (l)->dtor((current)->data);\ + }\ +@@ -108,6 +288,7 @@ ZEND_API void zend_llist_destroy(zend_ll + { + zend_llist_element *current=l->head, *next; + ++ zend_llist_check_destructor(l->dtor); + while (current) { + next = current->next; + if (l->dtor) { +@@ -133,6 +314,7 @@ ZEND_API void *zend_llist_remove_tail(ze + zend_llist_element *old_tail; + void *data; + ++ zend_llist_check_destructor(l->dtor); + if ((old_tail = l->tail)) { + if (old_tail->prev) { + old_tail->prev->next = NULL; +--- php.orig/configure.in ++++ php/configure.in +@@ -262,6 +262,7 @@ sinclude(Zend/Zend.m4) + sinclude(TSRM/threads.m4) + sinclude(TSRM/tsrm.m4) + ++sinclude(main/suhosin_patch.m4) + + divert(2) + +@@ -1385,7 +1386,7 @@ PHP_ADD_SOURCES(main, main.c snprintf.c + php_ini.c SAPI.c rfc1867.c php_content_types.c strlcpy.c \ + strlcat.c mergesort.c reentrancy.c php_variables.c php_ticks.c \ + network.c php_open_temporary_file.c php_logos.c \ +- output.c ) ++ output.c suhosin_patch.c ) + + PHP_ADD_SOURCES(main/streams, streams.c cast.c memory.c filter.c \ + plain_wrapper.c userspace.c transports.c xp_socket.c mmap.c) +@@ -1411,7 +1412,7 @@ PHP_ADD_SOURCES(Zend, \ + zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \ + zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \ + zend_ini.c zend_qsort.c zend_multibyte.c zend_ts_hash.c zend_stream.c \ +- zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c) ++ zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c zend_canary.c ) + + if test -r "$abs_srcdir/Zend/zend_objects.c"; then + PHP_ADD_SOURCES(Zend, zend_objects.c zend_object_handlers.c zend_objects_API.c zend_default_classes.c) +--- php.orig/ext/standard/basic_functions.c ++++ php/ext/standard/basic_functions.c +@@ -3575,7 +3575,9 @@ zend_function_entry basic_functions[] = + PHP_FALIAS(socket_get_status, stream_get_meta_data, arginfo_stream_get_meta_data) + + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) +- PHP_FE(realpath, arginfo_realpath) ++#undef realpath ++ PHP_NAMED_FE(realpath, PHP_FN(real_path), arginfo_realpath) ++#define realpath real_path + #endif + + #ifdef HAVE_FNMATCH +--- php.orig/ext/standard/dl.c ++++ php/ext/standard/dl.c +@@ -241,6 +241,19 @@ void php_dl(zval *file, int type, zval * + RETURN_FALSE; + } + } ++#if SUHOSIN_PATCH ++ if (strncmp("suhosin", module_entry->name, sizeof("suhosin")-1) == 0) { ++ void *log_func; ++ /* sucessfully loaded suhosin extension, now check for logging function replacement */ ++ log_func = (void *) DL_FETCH_SYMBOL(handle, "suhosin_log"); ++ if (log_func == NULL) { ++ log_func = (void *) DL_FETCH_SYMBOL(handle, "_suhosin_log"); ++ } ++ if (log_func != NULL) { ++ zend_suhosin_log = log_func; ++ } ++ } ++#endif + RETURN_TRUE; + } + /* }}} */ +--- php.orig/ext/standard/file.c ++++ php/ext/standard/file.c +@@ -2403,7 +2403,7 @@ out: + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) + /* {{{ proto string realpath(string path) + Return the resolved path */ +-PHP_FUNCTION(realpath) ++PHP_FUNCTION(real_path) + { + zval **path; + char resolved_path_buff[MAXPATHLEN]; +--- php.orig/ext/standard/file.h ++++ php/ext/standard/file.h +@@ -61,7 +61,7 @@ PHP_FUNCTION(flock); + PHP_FUNCTION(fd_set); + PHP_FUNCTION(fd_isset); + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) +-PHP_FUNCTION(realpath); ++PHP_FUNCTION(real_path); + #endif + #ifdef HAVE_FNMATCH + PHP_FUNCTION(fnmatch); +--- php.orig/ext/standard/info.c ++++ php/ext/standard/info.c +@@ -648,6 +648,31 @@ PHPAPI void php_print_info(int flag TSRM + + php_info_print_table_end(); + ++ /* Suhosin Patch */ ++ php_info_print_box_start(0); ++ if (expose_php && !sapi_module.phpinfo_as_text) { ++ PUTS("\"Suhosin\n"); ++ } ++ PUTS("This server is protected with the Suhosin Patch "); ++ if (sapi_module.phpinfo_as_text) { ++ PUTS(SUHOSIN_PATCH_VERSION); ++ } else { ++ zend_html_puts(SUHOSIN_PATCH_VERSION, strlen(SUHOSIN_PATCH_VERSION) TSRMLS_CC); ++ } ++ PUTS(!sapi_module.phpinfo_as_text?"
":"\n"); ++ if (sapi_module.phpinfo_as_text) { ++ PUTS("Copyright (c) 2006 Hardened-PHP Project\n"); ++ } else { ++ PUTS("Copyright (c) 2006 Hardened-PHP Project\n"); ++ } ++ php_info_print_box_end(); ++ + /* Zend Engine */ + php_info_print_box_start(0); + if (expose_php && !sapi_module.phpinfo_as_text) { +--- php.orig/ext/standard/syslog.c ++++ php/ext/standard/syslog.c +@@ -42,6 +42,7 @@ static void start_syslog(TSRMLS_D); + */ + PHP_MINIT_FUNCTION(syslog) + { ++#if !SUHOSIN_PATCH + /* error levels */ + REGISTER_LONG_CONSTANT("LOG_EMERG", LOG_EMERG, CONST_CS | CONST_PERSISTENT); /* system unusable */ + REGISTER_LONG_CONSTANT("LOG_ALERT", LOG_ALERT, CONST_CS | CONST_PERSISTENT); /* immediate action required */ +@@ -97,6 +98,7 @@ PHP_MINIT_FUNCTION(syslog) + /* AIX doesn't have LOG_PERROR */ + REGISTER_LONG_CONSTANT("LOG_PERROR", LOG_PERROR, CONST_CS | CONST_PERSISTENT); /*log to stderr*/ + #endif ++#endif + BG(syslog_device)=NULL; + + return SUCCESS; +--- php.orig/main/fopen_wrappers.c ++++ php/main/fopen_wrappers.c +@@ -110,7 +110,7 @@ PHPAPI int php_check_specific_open_based + + /* normalize and expand path */ + if (expand_filepath(path, resolved_name TSRMLS_CC) == NULL) { +- return -1; ++ return -2; + } + + path_len = strlen(resolved_name); +@@ -182,6 +182,12 @@ PHPAPI int php_check_specific_open_based + } + } + ++ if (resolved_name_len == resolved_basedir_len - 1) { ++ if (resolved_basedir[resolved_basedir_len - 1] == PHP_DIR_SEPARATOR) { ++ resolved_basedir_len--; ++ } ++ } ++ + /* Check the path */ + #if defined(PHP_WIN32) || defined(NETWARE) + if (strncasecmp(resolved_basedir, resolved_name, resolved_basedir_len) == 0) { +@@ -205,7 +211,7 @@ PHPAPI int php_check_specific_open_based + } + } else { + /* Unable to resolve the real path, return -1 */ +- return -1; ++ return -3; + } + } + /* }}} */ +@@ -224,22 +230,44 @@ PHPAPI int php_check_open_basedir_ex(con + char *pathbuf; + char *ptr; + char *end; ++ char path_copy[MAXPATHLEN]; ++ int path_len; ++ ++ /* Special case path ends with a trailing slash */ ++ path_len = strlen(path); ++ if (path_len >= MAXPATHLEN) { ++ errno = EPERM; /* we deny permission to open it */ ++ return -1; ++ } ++ if (path_len > 0 && path[path_len-1] == PHP_DIR_SEPARATOR) { ++ memcpy(path_copy, path, path_len+1); ++ while (path_len > 1 && path_copy[path_len-1] == PHP_DIR_SEPARATOR) path_len--; ++ path_copy[path_len] = '\0'; ++ path = (const char *)&path_copy; ++ } + + pathbuf = estrdup(PG(open_basedir)); + + ptr = pathbuf; + + while (ptr && *ptr) { ++ int res; + end = strchr(ptr, DEFAULT_DIR_SEPARATOR); + if (end != NULL) { + *end = '\0'; + end++; + } + +- if (php_check_specific_open_basedir(ptr, path TSRMLS_CC) == 0) { ++ res = php_check_specific_open_basedir(ptr, path TSRMLS_CC); ++ if (res == 0) { + efree(pathbuf); + return 0; + } ++ if (res == -2) { ++ efree(pathbuf); ++ errno = EPERM; ++ return -1; ++ } + + ptr = end; + } +--- php.orig/main/main.c ++++ php/main/main.c +@@ -90,6 +90,9 @@ + + #include "SAPI.h" + #include "rfc1867.h" ++#if SUHOSIN_PATCH ++#include "suhosin_globals.h" ++#endif + /* }}} */ + + #ifndef ZTS +@@ -1376,7 +1379,7 @@ void php_request_shutdown_for_exec(void + + /* used to close fd's in the 3..255 range here, but it's problematic + */ +- shutdown_memory_manager(1, 1 TSRMLS_CC); ++ shutdown_memory_manager(1, 1 TSRMLS_CC); + } + /* }}} */ + +@@ -1417,6 +1420,9 @@ void php_request_shutdown_for_hook(void + + zend_try { + shutdown_memory_manager(CG(unclean_shutdown), 0 TSRMLS_CC); ++#if SUHOSIN_PATCH ++ suhosin_clear_mm_canaries(TSRMLS_C); ++#endif + } zend_end_try(); + + zend_try { +@@ -1511,6 +1517,9 @@ void php_request_shutdown(void *dummy) + /* 11. Free Willy (here be crashes) */ + zend_try { + shutdown_memory_manager(CG(unclean_shutdown) || !report_memleaks, 0 TSRMLS_CC); ++#if SUHOSIN_PATCH ++ suhosin_clear_mm_canaries(TSRMLS_C); ++#endif + } zend_end_try(); + + /* 12. Reset max_execution_time */ +@@ -1670,6 +1679,9 @@ int php_module_startup(sapi_module_struc + #ifdef ZTS + tsrm_ls = ts_resource(0); + #endif ++#if SUHOSIN_PATCH ++ suhosin_startup(); ++#endif + + module_shutdown = 0; + module_startup = 1; +@@ -1811,6 +1823,10 @@ int php_module_startup(sapi_module_struc + REGISTER_MAIN_STRINGL_CONSTANT("PHP_CONFIG_FILE_PATH", PHP_CONFIG_FILE_PATH, strlen(PHP_CONFIG_FILE_PATH), CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_STRINGL_CONSTANT("PHP_CONFIG_FILE_SCAN_DIR", PHP_CONFIG_FILE_SCAN_DIR, sizeof(PHP_CONFIG_FILE_SCAN_DIR)-1, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_STRINGL_CONSTANT("PHP_SHLIB_SUFFIX", PHP_SHLIB_SUFFIX, sizeof(PHP_SHLIB_SUFFIX)-1, CONST_PERSISTENT | CONST_CS); ++#if SUHOSIN_PATCH ++ REGISTER_MAIN_LONG_CONSTANT("SUHOSIN_PATCH", 1, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_STRINGL_CONSTANT("SUHOSIN_PATCH_VERSION", SUHOSIN_PATCH_VERSION, sizeof(SUHOSIN_PATCH_VERSION)-1, CONST_PERSISTENT | CONST_CS); ++#endif + REGISTER_MAIN_STRINGL_CONSTANT("PHP_EOL", PHP_EOL, sizeof(PHP_EOL)-1, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_LONG_CONSTANT("PHP_INT_MAX", LONG_MAX, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_LONG_CONSTANT("PHP_INT_SIZE", sizeof(long), CONST_PERSISTENT | CONST_CS); +@@ -1860,7 +1876,9 @@ int php_module_startup(sapi_module_struc + module_startup = 0; + + shutdown_memory_manager(1, 0 TSRMLS_CC); +- ++#if SUHOSIN_PATCH ++ suhosin_clear_mm_canaries(TSRMLS_C); ++#endif + /* we're done */ + return SUCCESS; + } +@@ -1919,6 +1937,9 @@ void php_module_shutdown(TSRMLS_D) + #ifndef ZTS + zend_ini_shutdown(TSRMLS_C); + shutdown_memory_manager(CG(unclean_shutdown), 1 TSRMLS_CC); ++#if SUHOSIN_PATCH ++ suhosin_clear_mm_canaries(TSRMLS_C); ++#endif + core_globals_dtor(&core_globals TSRMLS_CC); + #else + zend_ini_global_shutdown(TSRMLS_C); +--- php.orig/main/php.h ++++ php/main/php.h +@@ -40,6 +40,13 @@ + #undef sprintf + #define sprintf php_sprintf + ++#if SUHOSIN_PATCH ++#if HAVE_REALPATH ++#undef realpath ++#define realpath php_realpath ++#endif ++#endif ++ + /* PHP's DEBUG value must match Zend's ZEND_DEBUG value */ + #undef PHP_DEBUG + #define PHP_DEBUG ZEND_DEBUG +@@ -448,6 +455,10 @@ END_EXTERN_C() + #endif + #endif /* !XtOffsetOf */ + ++#if SUHOSIN_PATCH ++#include "suhosin_patch.h" ++#endif ++ + #endif + + /* +--- php.orig/main/php_config.h.in ++++ php/main/php_config.h.in +@@ -809,6 +809,9 @@ + /* Define if the target system has /dev/urandom device */ + #undef HAVE_DEV_URANDOM + ++/* Suhosin-Patch for PHP */ ++#undef SUHOSIN_PATCH ++ + /* Whether you have AOLserver */ + #undef HAVE_AOLSERVER + +--- php.orig/main/php_logos.c ++++ php/main/php_logos.c +@@ -50,6 +50,10 @@ PHPAPI int php_unregister_info_logo(char + return zend_hash_del(&phpinfo_logo_hash, logo_string, strlen(logo_string)); + } + ++#if SUHOSIN_PATCH ++#include "suhosin_logo.h" ++#endif ++ + int php_init_info_logos(void) + { + if(zend_hash_init(&phpinfo_logo_hash, 0, NULL, NULL, 1)==FAILURE) +@@ -58,6 +62,9 @@ int php_init_info_logos(void) + php_register_info_logo(PHP_LOGO_GUID , "image/gif", php_logo , sizeof(php_logo)); + php_register_info_logo(PHP_EGG_LOGO_GUID, "image/gif", php_egg_logo, sizeof(php_egg_logo)); + php_register_info_logo(ZEND_LOGO_GUID , "image/gif", zend_logo , sizeof(zend_logo)); ++#if SUHOSIN_PATCH ++ php_register_info_logo(SUHOSIN_LOGO_GUID, "image/jpeg", suhosin_logo, sizeof(suhosin_logo)); ++#endif + + return SUCCESS; + } +--- php.orig/main/snprintf.c ++++ php/main/snprintf.c +@@ -1077,7 +1077,11 @@ static int format_converter(register buf + + + case 'n': ++#if SUHOSIN_PATCH ++ zend_suhosin_log(S_MISC, "'n' specifier within format string"); ++#else + *(va_arg(ap, int *)) = cc; ++#endif + goto skip_output; + + /* +--- php.orig/main/spprintf.c ++++ php/main/spprintf.c +@@ -683,7 +683,11 @@ static void xbuf_format_converter(smart_ + + + case 'n': ++#if SUHOSIN_PATCH ++ zend_suhosin_log(S_MISC, "'n' specifier within format string"); ++#else + *(va_arg(ap, int *)) = xbuf->len; ++#endif + goto skip_output; + + /* +--- /dev/null ++++ php/main/suhosin_globals.h +@@ -0,0 +1,61 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Suhosin-Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2006 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++ ++#ifndef SUHOSIN_GLOBALS_H ++#define SUHOSIN_GLOBALS_H ++ ++typedef struct _suhosin_patch_globals suhosin_patch_globals_struct; ++ ++#ifdef ZTS ++# define SPG(v) TSRMG(suhosin_patch_globals_id, suhosin_patch_globals_struct *, v) ++extern int suhosin_patch_globals_id; ++#else ++# define SPG(v) (suhosin_patch_globals.v) ++extern struct _suhosin_patch_globals suhosin_patch_globals; ++#endif ++ ++ ++struct _suhosin_patch_globals { ++ /* logging */ ++ int log_syslog; ++ int log_syslog_facility; ++ int log_syslog_priority; ++ int log_sapi; ++ int log_script; ++ int log_phpscript; ++ char *log_scriptname; ++ char *log_phpscriptname; ++ zend_bool log_phpscript_is_safe; ++ zend_bool log_use_x_forwarded_for; ++ ++ /* memory manager canary protection */ ++ unsigned int canary_1; ++ unsigned int canary_2; ++ unsigned int canary_3; ++ unsigned int dummy; ++}; ++ ++ ++#endif /* SUHOSIN_GLOBALS_H */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ */ +--- /dev/null ++++ php/main/suhosin_logo.h +@@ -0,0 +1,178 @@ ++static unsigned char suhosin_logo[] = ++ "\xff\xd8\xff\xe0\x00\x10\x4a\x46\x49\x46\x00\x01\x01\x01\x00\x48" ++ "\x00\x48\x00\x00\xff\xe1\x00\x16\x45\x78\x69\x66\x00\x00\x4d\x4d" ++ "\x00\x2a\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\xff\xdb\x00\x43" ++ "\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01" ++ "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01" ++ "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01" ++ "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01" ++ "\x01\xff\xc0\x00\x0b\x08\x00\x27\x00\x71\x01\x01\x22\x00\xff\xc4" ++ "\x00\x1e\x00\x00\x02\x02\x02\x03\x01\x01\x00\x00\x00\x00\x00\x00" ++ "\x00\x00\x00\x00\x09\x06\x08\x05\x07\x02\x03\x0a\x01\x04\xff\xc4" ++ "\x00\x32\x10\x00\x01\x04\x03\x00\x02\x00\x05\x01\x05\x09\x01\x00" ++ "\x00\x00\x00\x05\x02\x03\x04\x06\x01\x07\x08\x00\x09\x11\x12\x13" ++ "\x14\x21\x15\x0a\x16\x31\x56\x96\x17\x18\x19\x23\x32\x41\x58\x98" ++ "\xd4\xd6\xff\xda\x00\x08\x01\x01\x00\x00\x3f\x00\xf4\xc1\xe1\xe5" ++ "\x69\xe9\x3e\xb9\xd1\x7c\x8a\x2e\x9d\x66\xe8\x3b\x29\x4d\x7f\x46" ++ "\xba\x58\x55\x54\x8d\xb1\x5f\xaa\xd9\x8d\x51\x2b\xb6\x27\x5a\x69" ++ "\xd1\x43\xaf\x16\x1a\xf0\xb2\xb1\xe9\x6d\x9f\xc2\xa4\x36\x18\xb5" ++ "\x85\x10\x41\xbe\xfc\x09\xac\x49\x29\x11\xd4\x32\x97\xec\x08\x13" ++ "\xc1\x2d\x20\xc3\x59\xeb\x26\x05\xd8\x6b\x76\x31\x43\x8f\x57\xcf" ++ "\x84\x9f\x14\xa8\x53\x81\x0b\xc3\x64\x80\xa3\x02\x0a\x41\x75\xf8" ++ "\x44\x85\x93\x81\x22\x3c\xd8\x13\xe1\xbe\xf4\x59\x91\x1f\x6a\x44" ++ "\x77\x5c\x69\xc4\x2f\x39\x5f\x0f\x2a\x8d\xeb\xba\xf8\xc3\x56\x6c" ++ "\x3b\x36\xa7\xda\xbd\x4d\xa1\xb5\x4e\xc6\xa7\xa4\x3a\xec\x15\x2d" ++ "\xa5\xb3\xea\x5a\xdc\xac\x46\xac\x01\x60\xd8\x43\xc8\x8e\x8b\xb1" ++ "\x40\x4c\x95\x8b\x34\x41\x28\x52\x91\x28\x43\xd3\xa3\xb6\xa7\x55" ++ "\x15\xe7\x5a\x96\xcb\xf1\xda\xe5\x55\xee\xfe\x1e\xbd\xd9\x41\xd3" ++ "\x28\xfd\x97\xca\x57\x2b\x85\x9c\xa4\x30\x95\xaa\xa5\x57\xa2\x35" ++ "\x15\x86\xcb\x61\x34\x41\xe4\xc7\x80\x20\x18\x21\x17\x09\x85\x0b" ++ "\x14\x9d\x21\x68\x62\x1c\x08\x11\x64\x4b\x92\xf2\xd2\xd3\x2d\x2d" ++ "\x6a\xc2\x73\x6b\x3c\x3c\x8b\x9e\xbc\x52\xaa\xa4\xab\x81\x6c\xf6" ++ "\xfa\xbd\x70\xc5\xc6\x7b\xc2\xaa\x22\x4f\x58\x04\x87\x25\x6a\x27" ++ "\x1d\xa4\x3d\x20\x75\x72\x01\x09\x71\xe5\x1c\x9e\xc3\x2e\x36\xf3" ++ "\xd0\xc6\x35\x2a\x43\x4d\x2d\x0e\x2d\xb4\xa1\x49\xce\x65\x1e\x52" ++ "\x9e\xa1\xf6\x09\xcc\xdc\x63\x66\xa8\x01\xe9\x3b\x0d\xd7\x5a\x85" ++ "\xbb\xc5\x65\xc0\x7b\x2e\x46\xa9\xd9\x56\x1d\x4c\x92\x72\x26\x4e" ++ "\x86\xd5\x68\xae\xc4\xaa\x55\xce\xd7\x83\x59\xb3\x81\xee\xce\x74" ++ "\x39\x39\x31\x9f\x8a\x25\xe8\xa5\xa5\xe5\x81\xf2\x11\x23\xcb\xa1" ++ "\x1e\x43\x12\xe3\xb1\x2a\x2b\xcd\xc8\x8d\x25\x96\xa4\x47\x7d\x95" ++ "\xa5\xc6\x9f\x61\xe4\x25\xc6\x5e\x69\xc4\xe7\x29\x5b\x6e\xb6\xa4" ++ "\xad\x0b\x4e\x72\x95\x25\x58\x56\x33\x9c\x67\xce\xef\x0f\x17\xbf" ++ "\x4c\x7b\x2d\xe6\xfe\x76\x35\x27\x5a\x07\x97\x67\xe8\xae\x8d\x71" ++ "\x0f\xb2\x13\x99\xb9\xbc\x14\xad\xb3\xb7\xe6\x11\x6f\xe0\xda\x58" ++ "\xb1\x08\xac\xa6\x6c\x2d\x7f\x05\xb7\x56\xd2\xe6\xcf\xbb\x4d\x0c" ++ "\xe3\x50\xb2\xec\x91\xf0\x4a\xb8\xd6\x22\xb8\xa7\xf6\x67\xaf\xcf" ++ "\x63\x7e\xd7\xe7\x42\xd8\xbd\xc3\x71\xa1\xf2\x7e\x9b\xa8\x97\x83" ++ "\x6e\xd1\xdc\x4b\x06\x11\x2d\xae\x26\x61\x98\x72\x10\xf4\x42\x5d" ++ "\x20\x4a\xa3\x73\xd7\xf2\xcd\x3c\x48\x32\xe4\x03\x9f\x80\x37\x08" ++ "\x36\x11\xd0\xcb\x97\x6c\x08\xed\x6d\x33\x24\xa2\x1b\xb4\x77\xdf" ++ "\x61\x5d\x5f\xc1\x43\xc2\x82\xeb\x0f\x5d\x84\x08\x68\xaa\xa4\x01" ++ "\xe1\x19\xdf\xbc\x31\x65\xfe\xd1\xf5\x7d\x7a\xb2\x2a\x33\x50\x21" ++ "\x2a\x56\x9d\xb1\x81\xab\xdb\x35\x78\x30\x83\xd9\x89\x1d\x31\xac" ++ "\x96\x14\x07\x61\xbc\x20\x68\x42\x85\x33\x19\xac\xbe\xdb\x34\x56" ++ "\xf1\xd5\xfd\x29\xa9\x28\xdb\xcb\x4c\x5a\x23\xdc\xf5\x96\xc5\x10" ++ "\xa3\x35\x5b\x14\x68\xd3\x61\x62\x64\x76\x26\xcb\x17\x3e\x34\x98" ++ "\x04\xa3\xc4\x20\x38\x90\x92\xe3\xc8\x07\x2c\x36\x74\x66\x26\x0e" ++ "\x29\x02\x64\x29\x2d\x21\xe6\x16\x9c\x6b\xce\xa3\x89\xd9\x4f\xd3" ++ "\xc4\xbd\xc5\x87\x79\x9c\x65\xf6\x39\x45\x60\xe8\xce\x9e\xab\x6d" ++ "\x13\x15\x22\xe1\x5e\x4b\x38\x42\xc4\x1e\xd5\x76\xe0\xc5\xeb\x85" ++ "\x07\x2d\x0f\xb8\xb6\xa6\xd6\x6d\x71\x0d\xa2\x43\x4c\x25\xea\xfa" ++ "\xa1\xae\x4c\xe4\x7d\xbd\x76\xa9\xfb\x06\xc2\x83\x42\xeb\xad\xe7" ++ "\xe9\x5f\x68\x6f\xba\xfb\x2f\x07\xce\xb8\x13\xc1\x9b\xeb\xb0\x76" ++ "\x45\x57\x28\x7b\xea\xbe\x0f\xf4\x30\x7b\xa0\xed\xe4\x22\x93\x21" ++ "\xfc\xbc\xe0\xb9\x75\xc1\x4f\xfc\xef\xb6\xfa\xa1\xfc\x64\xa1\x4a" ++ "\x82\xc7\x33\xad\x75\xed\x82\xbd\x3d\xdb\xf7\xa8\xbe\x5e\xbb\x36" ++ "\x62\x04\x9a\x2e\xc5\xd9\x9e\x9c\x3a\x0b\x98\x0b\x57\xac\xf1\x24" ++ "\x62\x58\x83\x15\x5b\xa6\xf2\xda\x34\x70\x03\xce\x0f\x93\x1b\x12" ++ "\xc7\xce\x54\x87\x33\x15\xd6\x53\x25\x1f\x2a\x90\x87\x12\xe3\x78" ++ "\xef\x55\x77\x4d\x4a\xd8\x7e\xef\xd2\xfd\xd1\xaf\x3a\xaf\x55\xdb" ++ "\x6a\x2d\x3d\x42\xac\x51\x79\xee\x91\xab\xe1\x05\x2d\x3c\x80\xa2" ++ "\x43\xad\x22\x2e\xd5\x33\x13\xa4\x9e\x00\xe0\x04\x10\x84\xc8\xf2" ++ "\x19\x30\x92\x1f\xaa\xc3\x28\xc9\x76\x30\x3f\xe9\x10\x61\x5e\x79" ++ "\xd5\xf7\xdf\xd0\x54\xdb\xae\xb6\xae\xfa\xe8\xa3\x57\xe0\x6c\x2d" ++ "\xf7\xbd\x49\xd6\x6e\x76\x79\xcc\x54\x0c\x5f\xff\x00\xbb\x06\x98" ++ "\xa6\x9e\x89\x61\xb4\x6f\xc3\xe3\x6a\xc2\x4f\x59\x03\xc9\x80\x2c" ++ "\x59\x24\x44\x70\x38\xd5\x96\x6a\x9e\x8b\x81\x64\xe5\xbc\xa0\x3c" ++ "\x33\xaf\x17\x9d\xff\x00\x71\x1a\xd1\x3a\x80\x66\xb3\xd9\x31\x77" ++ "\x0d\x12\xbd\xae\x29\xb5\x6a\xd6\xcf\x8d\x68\x87\x75\xcd\xe8\x65" ++ "\x5a\xbe\x3c\x04\x7b\x34\xdb\x54\x19\xa4\x63\x9c\x2a\x5d\x23\xbe" ++ "\xf4\xb1\x1c\x4d\x90\xec\x92\x2f\x49\x71\xf7\x14\xf2\x97\x9f\x15" ++ "\x57\xed\x13\x21\x2a\xf5\x33\xd1\x2a\x52\x52\xac\xb7\x62\xd1\xcb" ++ "\x46\x73\x8c\x67\x28\x56\x77\x86\xbf\x6f\x2a\x4e\x73\xfe\x95\x65" ++ "\x0b\x5a\x3e\x38\xfc\xfc\xaa\x56\x3f\x86\x73\xe3\xb9\x4a\x52\x84" ++ "\xa5\x08\x4e\x12\x94\x27\x09\x4a\x53\x8c\x61\x29\x4a\x71\xf0\x4a" ++ "\x53\x8c\x7e\x31\x8c\x63\x18\xc6\x31\x8f\xc6\x31\xf8\xc7\x9f\x7c" ++ "\xd5\xbb\xae\x5e\xe2\x1f\xab\x6e\x24\x34\x00\x8a\x25\x83\x70\x40" ++ "\x1c\xcc\xda\x45\x7f\x66\x4e\x30\x2e\x94\x7e\x74\x49\xf0\xe4\x4e" ++ "\x06\x5c\xa8\x2f\x89\x21\x2e\x98\x0e\xd9\x21\xc2\x0b\x21\x0f\xc4" ++ "\x16\x6e\x48\xd9\xe4\xe3\x4a\x19\x1e\x64\x67\x54\xff\x00\x3a\x6d" ++ "\x4f\x62\xb5\x00\x4a\xaa\x51\xfd\x2d\xe8\x0e\x6c\xaf\xc6\x7d\x6d" ++ "\xc8\x88\xc7\x67\xea\x8a\x58\x02\x73\xe3\x65\x4d\xc9\x24\xc0\x3d" ++ "\x57\xa3\x2e\x53\x16\x99\x4f\xe5\xe7\x19\x97\x3e\x3b\xcf\xc9\x4b" ++ "\x99\x7f\x33\x25\xa5\xdf\xba\x77\x2b\xd3\x3e\xc2\x7b\x8b\x94\x07" ++ "\xe9\x52\x5b\x43\x87\x34\x14\x86\x37\xcf\x41\x6b\x8e\x6a\xa5\x22" ++ "\xab\xdb\x96\xa2\xcf\x46\xd8\x9b\x45\x93\xef\xd6\xdf\x3e\x99\x9c" ++ "\x7e\x29\x10\x6b\x6c\xa2\xb8\x43\x05\x09\x44\x70\x8c\xb8\xaa\x54" ++ "\x7c\x30\x36\x5e\x1c\x5e\x5b\x9f\x6c\x0d\x81\xee\xa0\x93\x8d\x67" ++ "\x55\xf3\x87\xaf\xaa\x6b\x58\xf9\xbe\xb2\x36\x07\x42\x6e\xbd\x96" ++ "\xe3\x9f\x1f\x8f\xc9\xf4\x9d\xae\x6a\x7d\x4c\x96\xbe\x5f\xc7\xcd" ++ "\xf3\xb2\xf7\xcd\xf0\xcf\xc3\xe4\xf8\xfe\x37\x4f\x1c\x4d\xf6\x40" ++ "\xf1\x6b\x7c\x4e\xe0\xa6\x71\xad\x56\xa7\x1c\x5c\x15\x6b\xfc\xf3" ++ "\x01\x5d\xac\xf1\x75\x9a\x72\x6b\xaa\x28\xc5\x88\x6d\xfb\x33\x85" ++ "\xe0\x4e\x61\xab\xeb\x31\x2c\x71\x08\x73\x11\x3b\xfc\xb5\xc0\x96" ++ "\xcc\x87\x24\x44\xb5\x9b\x9e\xb3\x71\xba\xe9\xed\xb1\x4e\xd7\x76" ++ "\x6c\xd2\xb6\x05\xb7\x5a\xde\xeb\x34\x5b\x96\x16\xfb\x59\xa9\x5c" ++ "\x4f\x55\xca\x8a\xac\x59\xb0\xe4\x54\x39\x25\xbc\x81\x37\x2a\x09" ++ "\x5f\x9e\x3b\x6b\x7d\x1f\x69\xf3\x34\x85\x39\x84\xa7\x28\x0b\xd3" ++ "\xfd\xfb\x4b\x7a\xea\xe7\xd2\x3c\xd3\xda\x15\x68\xbc\x73\xd3\x22" ++ "\x6f\xd7\x72\x5b\x2b\x66\xee\xa8\x0d\x54\xe8\x5b\xf9\x92\x96\x92" ++ "\x93\xea\x97\x4a\xc7\x43\x10\x46\x35\xc5\xc0\x60\x8a\xe4\xc1\xb5" ++ "\x36\xc6\xae\xed\xf7\x70\xa5\x86\x99\x3d\x91\xf8\xfd\x4e\x53\xeb" ++ "\xbb\xbd\x6d\xec\x8f\xd7\x89\x3d\x31\x7f\xd7\x78\xba\x50\xbb\x74" ++ "\x9d\xf6\xac\x4e\xb9\x03\x9c\x79\xd5\xe1\xbd\x17\x68\xd9\x13\x0b" ++ "\x45\x75\x88\x00\x1d\x1f\xae\x73\x6a\x1d\x5c\x6e\x44\x9f\xa6\xfa" ++ "\x4e\xd8\x25\x8b\xc0\xbc\xb2\x99\xe3\x17\x24\xb3\x23\xe2\x48\x8b" ++ "\xfa\x22\xe7\x7e\x8f\xe6\x3f\x5f\x55\x0d\x75\xd3\x51\x0b\xd7\xed" ++ "\xd3\x6f\x97\x3b\x85\x42\x80\x7e\x5f\xdc\x1b\xd6\xba\xee\xc4\x80" ++ "\xce\x06\xa9\x15\x8c\x97\x5f\x40\x69\xb2\x4d\xc5\xb2\x5c\x1e\x01" ++ "\x87\x7e\xe0\x36\x6d\x78\x80\x4e\x3c\x02\xec\x90\x1d\x11\x81\x74" ++ "\xa5\x8b\xa4\xa0\x56\x06\xd5\x79\x72\x85\x57\x3b\xb2\x2e\xae\x90" ++ "\x18\x8d\x91\xb2\x0e\x44\x19\xaa\xb4\xcc\x08\xed\x46\xfa\xd7\x2b" ++ "\x78\x58\x72\x5d\xbb\x5e\x49\xe7\xee\xf3\x8a\x9d\x22\xa4\x19\xc8" ++ "\xe7\x08\xc3\x90\x9b\x35\x9a\xa4\x25\x8c\x4b\x9b\xa7\xf8\xbf\x81" ++ "\xf5\xdf\x22\x66\xf1\x7e\x9f\x66\x3d\xbb\xfa\x73\x73\x4d\xfd\x67" ++ "\x7b\xf4\xce\xc3\x62\x2e\x6f\xbb\x0c\xa2\xdc\x69\xfc\x8a\x17\x0e" ++ "\x3a\x9e\x83\x46\xd7\xe3\x5e\x65\x86\xc0\x51\x00\xbb\x91\xe3\xe1" ++ "\xc1\x16\xc4\xe9\x65\x5c\x14\x3e\x44\x6a\x6b\xd1\x1e\xb0\x36\xdd" ++ "\x0b\x7d\x8a\xeb\xaf\x58\x5b\x64\x3f\x38\xed\x52\x76\xe8\x46\xf7" ++ "\x86\x84\xb3\x93\xb1\x0b\xe5\xfd\xfd\x0d\xe9\x6d\xe4\xf1\x1b\x1d" ++ "\x56\xb4\x34\xe4\x6a\xf5\xa4\x9c\x2c\xc9\x64\x94\xc1\xf5\x79\x6d" ++ "\x12\x96\xf3\x47\xc5\x48\xa8\xdb\xd8\x95\x64\x29\xcf\xf6\x88\xf1" ++ "\x95\x7a\x98\xe8\xbc\x27\x19\xce\x73\x61\xd1\xb8\xc6\x31\x8c\xe7" ++ "\x39\xce\x77\x9e\xbc\xc6\x31\x8c\x63\xf3\x9c\xe7\x39\xc6\x31\x8f" ++ "\xf7\xce\x7e\x1e\x3b\x7f\x0f\x0f\x0f\x13\x57\xb9\x0a\xe1\x0b\x64" ++ "\x5f\x58\x40\xc6\xc7\x7a\x4b\xf2\x3d\xbc\x71\xf4\xa7\xd2\xca\x14" ++ "\xe2\x98\x1a\x30\x1e\xe0\x26\x5a\x6a\xf0\x9c\x67\x38\x66\x00\xb8" ++ "\x72\xe6\xbe\xac\xfe\x12\xd3\x0b\x56\x73\x8c\x63\xc7\x2b\xe1\xe2" ++ "\xe8\xdd\x7b\xff\x00\xd8\xe5\x23\x6c\xce\xa8\x69\xcf\x5e\x3a\xef" ++ "\x77\xea\xe5\xab\x0e\x82\xdb\xd9\xed\x7a\x9e\xb8\x6d\x51\x32\xdb" ++ "\x79\xc3\x36\x9a\x2d\xa3\x50\x39\x65\x0a\x63\x0e\xe5\xd4\x39\x12" ++ "\xbf\x8b\x98\xa4\xa1\x2d\xad\xb3\xcf\x65\x6a\x43\x78\xb3\x3b\x07" ++ "\xd8\xd5\xea\xae\x76\xad\x6f\xf5\xff\x00\xca\x93\xab\x96\xb0\x64" ++ "\xeb\xd6\x4a\xd5\x87\xba\xec\x24\x60\x97\x06\x76\x03\xe3\x4c\x07" ++ "\x29\x11\x8e\x34\x25\x02\x64\x29\xf0\x25\x48\x85\x3a\x33\x8b\x7a" ++ "\x3c\x86\x1e\x75\xa5\x61\xc6\x97\x9f\x8d\x25\xf5\xc9\xcd\xde\xc9" ++ "\x7d\x77\xf2\xc8\x7e\x70\xaf\x73\x5f\x2d\xec\xa2\x51\x2d\x96\xfb" ++ "\x89\xad\x80\x57\xb2\x36\x1d\x7d\x83\x45\xac\xf3\xdb\xcc\x6c\x31" ++ "\x4f\xcf\x30\x58\xd0\x12\x28\x90\x50\x42\x86\xfb\x48\x16\x3c\xc5" ++ "\x9c\xf8\xe7\xcc\x29\x88\xb3\x4a\x4b\x4e\x6c\xbc\xdb\xc7\xbb\xe9" ++ "\xb6\xa0\x8b\x11\xa1\x7d\x73\xd7\xe9\xbf\x7e\xc2\x6c\x10\x8d\xee" ++ "\x9d\xef\x63\x3a\xe0\xf5\xbe\x8c\x3e\xa1\xc7\xc5\xd1\x00\x44\x1e" ++ "\xf3\x51\xf2\xe2\xb0\xe3\xb5\x13\x7f\x32\xf1\x8c\xa6\x22\xfe\x1f" ++ "\x49\x4d\xbb\xcf\x3a\x5d\xed\x4c\xd2\xfc\x85\xed\x23\xd6\xc7\x50" ++ "\xb6\x5b\x3a\x16\x83\xb8\x6f\xfd\x32\x3f\xaa\x36\x34\xbb\xf5\x96" ++ "\xa9\xab\xcf\x9f\x8f\xac\xc3\xca\xd5\x8b\xd8\x48\x9e\x79\xaa\x30" ++ "\x87\xca\x58\x4d\x59\x96\xb9\x4f\xc5\x1b\x1c\xd2\xda\x5b\xe6\x57" ++ "\x29\xa1\x28\x7a\x2b\x5b\xff\x00\x12\x2f\x5e\x3f\xf3\xbb\x8e\x7f" ++ "\xec\xc6\x98\xff\x00\xed\x3c\xa6\xdd\xa9\xdc\x7e\xa0\xf7\xd6\x99" ++ "\x31\xa2\xf7\xaf\x6b\xe9\x82\x74\x4b\x3d\x8f\x5e\x58\x0b\x33\xab" ++ "\xef\xc3\xaf\x84\x64\xb9\xae\xb6\x25\x5f\x62\x8f\x1c\xe3\xf4\x51" ++ "\xb7\x96\xe3\x0e\x30\x42\xa9\x18\x39\xbf\x9e\x2a\x1f\x74\x19\x02" ++ "\x2d\x43\x93\x06\x63\xb1\xa7\x47\x6a\xfa\x9b\x6c\xeb\xbd\xe9\xae" ++ "\x6a\x7b\x6f\x53\x5a\x60\x5d\xb5\xcd\xe8\x67\xeb\x35\x3b\x48\xc6" ++ "\xa6\xb3\x04\xc8\xdf\xb8\x7e\x26\x64\xb0\xc9\x18\xb0\xa7\x33\xf2" ++ "\x4a\x8b\x22\x3b\x8d\x4b\x89\x1d\xf6\x9d\x65\xc4\x38\xd2\x54\x9c" ++ "\xe3\xcd\x89\xe1\xe1\xe6\x3e\x70\x81\x45\x1d\x18\xf9\x31\x83\xc8" ++ "\xbe\x14\x82\x4b\x87\x7a\x74\x28\xd2\xdd\x12\x55\x30\xe6\x0e\x49" ++ "\x31\x8e\x48\x69\xc5\xc0\x20\x91\xe4\x48\x41\x4c\xd8\xb9\x6a\x4e" ++ "\x21\xce\x99\x1b\x0e\xfd\x09\x4f\xa1\x79\x0f\x0f\x0f\x0f\x0f\x0f" ++ "\x0f\x3f\x3c\xb8\x71\x27\xc7\x72\x24\xe8\xb1\xa6\xc5\x7b\x18\xc3" ++ "\xb1\xa5\xb0\xd4\x98\xee\xe3\x19\xc6\x71\x87\x19\x79\x2b\x6d\x78" ++ "\xc6\x71\x8c\xe3\x0a\x4e\x71\x8c\xe3\x19\xfe\x38\xf2\x3b\xfb\x8b" ++ "\x48\xfe\x4e\xaa\xff\x00\x4f\x08\xff\x00\xc7\xe1\xfb\x8b\x48\xfe" ++ "\x4e\xaa\xff\x00\x4f\x08\xff\x00\xc7\xe4\x95\x86\x18\x8a\xcb\x31" ++ "\xa3\x32\xd4\x78\xf1\xdb\x43\x2c\x47\x61\xb4\x32\xcb\x2c\xb4\x9c" ++ "\x21\xb6\x99\x69\xbc\x25\xb6\xdb\x6d\x18\xc2\x10\xda\x12\x94\xa1" ++ "\x38\xc2\x53\x8c\x63\x18\xc7\x9d\xbe\x7f\xff\xd9" ++ ; +--- /dev/null ++++ php/main/suhosin_patch.c +@@ -0,0 +1,380 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Suhosin Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2006 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++/* $Id: suhosin_patch.c,v 1.2 2004/11/21 09:38:52 ionic Exp $ */ ++ ++#include "php.h" ++ ++#include ++#include ++ ++#if HAVE_UNISTD_H ++#include ++#endif ++#include "SAPI.h" ++#include "php_globals.h" ++ ++#if SUHOSIN_PATCH ++ ++#ifdef HAVE_SYS_SOCKET_H ++#include ++#endif ++ ++#if defined(PHP_WIN32) || defined(__riscos__) || defined(NETWARE) ++#undef AF_UNIX ++#endif ++ ++#if defined(AF_UNIX) ++#include ++#endif ++ ++#define SYSLOG_PATH "/dev/log" ++ ++#ifdef PHP_WIN32 ++static HANDLE log_source = 0; ++#endif ++ ++#include "snprintf.h" ++ ++#include "suhosin_patch.h" ++ ++#ifdef ZTS ++#include "suhosin_globals.h" ++int suhosin_patch_globals_id; ++#else ++struct _suhosin_patch_globals suhosin_patch_globals; ++#endif ++ ++static void php_security_log(int loglevel, char *fmt, ...); ++ ++static void suhosin_patch_globals_ctor(suhosin_patch_globals_struct *suhosin_patch_globals TSRMLS_DC) ++{ ++ memset(suhosin_patch_globals, 0, sizeof(*suhosin_patch_globals)); ++} ++ ++PHPAPI void suhosin_startup() ++{ ++#ifdef ZTS ++ ts_allocate_id(&suhosin_patch_globals_id, sizeof(suhosin_patch_globals_struct), (ts_allocate_ctor) suhosin_patch_globals_ctor, NULL); ++#else ++ suhosin_patch_globals_ctor(&suhosin_patch_globals TSRMLS_CC); ++#endif ++ zend_suhosin_log = php_security_log; ++} ++ ++/*PHPAPI void suhosin_clear_mm_canaries(TSRMLS_D) ++{ ++ zend_alloc_clear_mm_canaries(AG(heap)); ++ SPG(canary_1) = zend_canary(); ++ SPG(canary_2) = zend_canary(); ++ SPG(canary_3) = zend_canary(); ++}*/ ++ ++static char *loglevel2string(int loglevel) ++{ ++ switch (loglevel) { ++ case S_FILES: ++ return "FILES"; ++ case S_INCLUDE: ++ return "INCLUDE"; ++ case S_MEMORY: ++ return "MEMORY"; ++ case S_MISC: ++ return "MISC"; ++ case S_SESSION: ++ return "SESSION"; ++ case S_SQL: ++ return "SQL"; ++ case S_EXECUTOR: ++ return "EXECUTOR"; ++ case S_VARS: ++ return "VARS"; ++ default: ++ return "UNKNOWN"; ++ } ++} ++ ++static void php_security_log(int loglevel, char *fmt, ...) ++{ ++ int s, r, i=0; ++#if defined(AF_UNIX) ++ struct sockaddr_un saun; ++#endif ++#ifdef PHP_WIN32 ++ LPTSTR strs[2]; ++ unsigned short etype; ++ DWORD evid; ++#endif ++ char buf[4096+64]; ++ char error[4096+100]; ++ char *ip_address; ++ char *fname; ++ char *alertstring; ++ int lineno; ++ va_list ap; ++ TSRMLS_FETCH(); ++ ++ /*SDEBUG("(suhosin_log) loglevel: %d log_syslog: %u - log_sapi: %u - log_script: %u", loglevel, SPG(log_syslog), SPG(log_sapi), SPG(log_script));*/ ++ ++ if (SPG(log_use_x_forwarded_for)) { ++ ip_address = sapi_getenv("HTTP_X_FORWARDED_FOR", 20 TSRMLS_CC); ++ if (ip_address == NULL) { ++ ip_address = "X-FORWARDED-FOR not set"; ++ } ++ } else { ++ ip_address = sapi_getenv("REMOTE_ADDR", 11 TSRMLS_CC); ++ if (ip_address == NULL) { ++ ip_address = "REMOTE_ADDR not set"; ++ } ++ } ++ ++ ++ va_start(ap, fmt); ++ ap_php_vsnprintf(error, sizeof(error), fmt, ap); ++ va_end(ap); ++ while (error[i]) { ++ if (error[i] < 32) error[i] = '.'; ++ i++; ++ } ++ ++/* if (SPG(simulation)) { ++ alertstring = "ALERT-SIMULATION"; ++ } else { */ ++ alertstring = "ALERT"; ++/* }*/ ++ ++ if (zend_is_executing(TSRMLS_C)) { ++ if (EG(current_execute_data)) { ++ lineno = EG(current_execute_data)->opline->lineno; ++ fname = EG(current_execute_data)->op_array->filename; ++ } else { ++ lineno = zend_get_executed_lineno(TSRMLS_C); ++ fname = zend_get_executed_filename(TSRMLS_C); ++ } ++ ap_php_snprintf(buf, sizeof(buf), "%s - %s (attacker '%s', file '%s', line %u)", alertstring, error, ip_address, fname, lineno); ++ } else { ++ fname = sapi_getenv("SCRIPT_FILENAME", 15 TSRMLS_CC); ++ if (fname==NULL) { ++ fname = "unknown"; ++ } ++ ap_php_snprintf(buf, sizeof(buf), "%s - %s (attacker '%s', file '%s')", alertstring, error, ip_address, fname); ++ } ++ ++ /* Syslog-Logging disabled? */ ++ if (((SPG(log_syslog)|S_INTERNAL) & loglevel)==0) { ++ goto log_sapi; ++ } ++ ++#if defined(AF_UNIX) ++ ap_php_snprintf(error, sizeof(error), "<%u>suhosin[%u]: %s\n", (unsigned int)(SPG(log_syslog_facility)|SPG(log_syslog_priority)),getpid(),buf); ++ ++ s = socket(AF_UNIX, SOCK_DGRAM, 0); ++ if (s == -1) { ++ goto log_sapi; ++ } ++ ++ memset(&saun, 0, sizeof(saun)); ++ saun.sun_family = AF_UNIX; ++ strcpy(saun.sun_path, SYSLOG_PATH); ++ /*saun.sun_len = sizeof(saun);*/ ++ ++ r = connect(s, (struct sockaddr *)&saun, sizeof(saun)); ++ if (r) { ++ close(s); ++ s = socket(AF_UNIX, SOCK_STREAM, 0); ++ if (s == -1) { ++ goto log_sapi; ++ } ++ ++ memset(&saun, 0, sizeof(saun)); ++ saun.sun_family = AF_UNIX; ++ strcpy(saun.sun_path, SYSLOG_PATH); ++ /*saun.sun_len = sizeof(saun);*/ ++ ++ r = connect(s, (struct sockaddr *)&saun, sizeof(saun)); ++ if (r) { ++ close(s); ++ goto log_sapi; ++ } ++ } ++ send(s, error, strlen(error), 0); ++ ++ close(s); ++#endif ++#ifdef PHP_WIN32 ++ ap_php_snprintf(error, sizeof(error), "suhosin[%u]: %s", getpid(),buf); ++ ++ switch (SPG(log_syslog_priority)) { /* translate UNIX type into NT type */ ++ case 1: /*LOG_ALERT:*/ ++ etype = EVENTLOG_ERROR_TYPE; ++ break; ++ case 6: /*LOG_INFO:*/ ++ etype = EVENTLOG_INFORMATION_TYPE; ++ break; ++ default: ++ etype = EVENTLOG_WARNING_TYPE; ++ } ++ evid = loglevel; ++ strs[0] = error; ++ /* report the event */ ++ if (log_source == NULL) { ++ log_source = RegisterEventSource(NULL, "Suhosin-Patch-" SUHOSIN_PATCH_VERSION); ++ } ++ ReportEvent(log_source, etype, (unsigned short) SPG(log_syslog_priority), evid, NULL, 1, 0, strs, NULL); ++ ++#endif ++log_sapi: ++ /* SAPI Logging activated? */ ++ /*SDEBUG("(suhosin_log) log_syslog: %u - log_sapi: %u - log_script: %u - log_phpscript: %u", SPG(log_syslog), SPG(log_sapi), SPG(log_script), SPG(log_phpscript));*/ ++ if (((SPG(log_sapi)|S_INTERNAL) & loglevel)!=0) { ++ sapi_module.log_message(buf); ++ } ++ ++/*log_script:*/ ++ /* script logging activaed? */ ++ if (((SPG(log_script) & loglevel)!=0) && SPG(log_scriptname)!=NULL) { ++ char cmd[8192], *cmdpos, *bufpos; ++ FILE *in; ++ int space; ++ ++ ap_php_snprintf(cmd, sizeof(cmd), "%s %s \'", SPG(log_scriptname), loglevel2string(loglevel)); ++ space = sizeof(cmd) - strlen(cmd); ++ cmdpos = cmd + strlen(cmd); ++ bufpos = buf; ++ if (space <= 1) return; ++ while (space > 2 && *bufpos) { ++ if (*bufpos == '\'') { ++ if (space<=5) break; ++ *cmdpos++ = '\''; ++ *cmdpos++ = '\\'; ++ *cmdpos++ = '\''; ++ *cmdpos++ = '\''; ++ bufpos++; ++ space-=4; ++ } else { ++ *cmdpos++ = *bufpos++; ++ space--; ++ } ++ } ++ *cmdpos++ = '\''; ++ *cmdpos = 0; ++ ++ if ((in=VCWD_POPEN(cmd, "r"))==NULL) { ++ php_security_log(S_INTERNAL, "Unable to execute logging shell script: %s", SPG(log_scriptname)); ++ return; ++ } ++ /* read and forget the result */ ++ while (1) { ++ int readbytes = fread(cmd, 1, sizeof(cmd), in); ++ if (readbytes<=0) { ++ break; ++ } ++ } ++ pclose(in); ++ } ++/*log_phpscript:*/ ++ if ((SPG(log_phpscript) & loglevel)!=0 && EG(in_execution) && SPG(log_phpscriptname) && SPG(log_phpscriptname)[0]) { ++ zend_file_handle file_handle; ++ zend_op_array *new_op_array; ++ zval *result = NULL; ++ ++ /*long orig_execution_depth = SPG(execution_depth);*/ ++ zend_bool orig_safe_mode = PG(safe_mode); ++ char *orig_basedir = PG(open_basedir); ++ ++ char *phpscript = SPG(log_phpscriptname); ++/*SDEBUG("scriptname %s", SPG(log_phpscriptname));`*/ ++#ifdef ZEND_ENGINE_2 ++ if (zend_stream_open(phpscript, &file_handle TSRMLS_CC) == SUCCESS) { ++#else ++ if (zend_open(phpscript, &file_handle) == SUCCESS && ZEND_IS_VALID_FILE_HANDLE(&file_handle)) { ++ file_handle.filename = phpscript; ++ file_handle.free_filename = 0; ++#endif ++ if (!file_handle.opened_path) { ++ file_handle.opened_path = estrndup(phpscript, strlen(phpscript)); ++ } ++ new_op_array = zend_compile_file(&file_handle, ZEND_REQUIRE TSRMLS_CC); ++ zend_destroy_file_handle(&file_handle TSRMLS_CC); ++ if (new_op_array) { ++ HashTable *active_symbol_table = EG(active_symbol_table); ++ zval *zerror, *zerror_class; ++ ++ if (active_symbol_table == NULL) { ++ active_symbol_table = &EG(symbol_table); ++ } ++ EG(return_value_ptr_ptr) = &result; ++ EG(active_op_array) = new_op_array; ++ ++ MAKE_STD_ZVAL(zerror); ++ MAKE_STD_ZVAL(zerror_class); ++ ZVAL_STRING(zerror, buf, 1); ++ ZVAL_LONG(zerror_class, loglevel); ++ ++ zend_hash_update(active_symbol_table, "SUHOSIN_ERROR", sizeof("SUHOSIN_ERROR"), (void **)&zerror, sizeof(zval *), NULL); ++ zend_hash_update(active_symbol_table, "SUHOSIN_ERRORCLASS", sizeof("SUHOSIN_ERRORCLASS"), (void **)&zerror_class, sizeof(zval *), NULL); ++ ++ /*SPG(execution_depth) = 0;*/ ++ if (SPG(log_phpscript_is_safe)) { ++ PG(safe_mode) = 0; ++ PG(open_basedir) = NULL; ++ } ++ ++ zend_execute(new_op_array TSRMLS_CC); ++ ++ /*SPG(execution_depth) = orig_execution_depth;*/ ++ PG(safe_mode) = orig_safe_mode; ++ PG(open_basedir) = orig_basedir; ++ ++#ifdef ZEND_ENGINE_2 ++ destroy_op_array(new_op_array TSRMLS_CC); ++#else ++ destroy_op_array(new_op_array); ++#endif ++ efree(new_op_array); ++#ifdef ZEND_ENGINE_2 ++ if (!EG(exception)) ++#endif ++ { ++ if (EG(return_value_ptr_ptr)) { ++ zval_ptr_dtor(EG(return_value_ptr_ptr)); ++ EG(return_value_ptr_ptr) = NULL; ++ } ++ } ++ } else { ++ php_security_log(S_INTERNAL, "Unable to execute logging PHP script: %s", SPG(log_phpscriptname)); ++ return; ++ } ++ } else { ++ php_security_log(S_INTERNAL, "Unable to execute logging PHP script: %s", SPG(log_phpscriptname)); ++ return; ++ } ++ } ++ ++} ++ ++ ++#endif ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: sw=4 ts=4 fdm=marker ++ * vim<600: sw=4 ts=4 ++ */ +--- /dev/null ++++ php/main/suhosin_patch.h +@@ -0,0 +1,40 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Suhosin Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2006 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++ ++#ifndef SUHOSIN_PATCH_H ++#define SUHOSIN_PATCH_H ++ ++#if SUHOSIN_PATCH ++ ++#include "zend.h" ++ ++PHPAPI void suhosin_startup(); ++#define SUHOSIN_PATCH_VERSION "0.9.7" ++ ++#define SUHOSIN_LOGO_GUID "SUHO8567F54-D428-14d2-A769-00DA302A5F18" ++ ++#endif ++ ++#endif /* SUHOSIN_PATCH_H */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ */ +--- /dev/null ++++ php/main/suhosin_patch.m4 +@@ -0,0 +1,8 @@ ++dnl ++dnl $Id: suhosin_patch.m4,v 1.1 2004/11/14 13:24:24 ionic Exp $ ++dnl ++dnl This file contains Suhosin Patch for PHP specific autoconf functions. ++dnl ++ ++AC_DEFINE(SUHOSIN_PATCH, 1, [Suhosin Patch]) ++ +--- php.orig/sapi/apache/mod_php5.c ++++ php/sapi/apache/mod_php5.c +@@ -951,7 +951,11 @@ static void php_init_handler(server_rec + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if SUHOSIN_PATCH ++ ap_add_version_component("PHP/" PHP_VERSION " with Suhosin-Patch"); ++#else + ap_add_version_component("PHP/" PHP_VERSION); ++#endif + } + } + #endif +--- php.orig/sapi/apache2filter/sapi_apache2.c ++++ php/sapi/apache2filter/sapi_apache2.c +@@ -566,7 +566,11 @@ static void php_apache_add_version(apr_p + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if SUHOSIN_PATCH ++ ap_add_version_component(p, "PHP/" PHP_VERSION " with Suhosin-Patch"); ++#else + ap_add_version_component(p, "PHP/" PHP_VERSION); ++#endif + } + } + +--- php.orig/sapi/apache2handler/sapi_apache2.c ++++ php/sapi/apache2handler/sapi_apache2.c +@@ -370,7 +370,11 @@ static void php_apache_add_version(apr_p + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if SUHOSIN_PATCH ++ ap_add_version_component(p, "PHP/" PHP_VERSION " with Suhosin-Patch"); ++#else + ap_add_version_component(p, "PHP/" PHP_VERSION); ++#endif + } + } + +--- php.orig/sapi/cgi/cgi_main.c ++++ php/sapi/cgi/cgi_main.c +@@ -1801,11 +1801,19 @@ consult the installation file that came + SG(headers_sent) = 1; + SG(request_info).no_headers = 1; + } ++#if SUHOSIN_PATCH ++#if ZEND_DEBUG ++ php_printf("PHP %s with Suhosin-Patch %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2009 The PHP Group\n%s", PHP_VERSION, SUHOSIN_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#else ++ php_printf("PHP %s with Suhosin-Patch %s (%s) (built: %s %s)\nCopyright (c) 1997-2009 The PHP Group\n%s", PHP_VERSION, SUHOSIN_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#endif ++#else + #if ZEND_DEBUG + php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2009 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #else + php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2009 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #endif ++#endif + php_request_shutdown((void *) 0); + exit_status = 0; + goto out; +--- php.orig/sapi/cli/php_cli.c ++++ php/sapi/cli/php_cli.c +@@ -801,8 +801,14 @@ int main(int argc, char *argv[]) + } + + request_started = 1; +- php_printf("PHP %s (%s) (built: %s %s) %s\nCopyright (c) 1997-2009 The PHP Group\n%s", +- PHP_VERSION, sapi_module.name, __DATE__, __TIME__, ++#if SUHOSIN_PATCH ++ php_printf("PHP %s with Suhosin-Patch %s (%s) (built: %s %s) %s\nCopyright (c) 1997-2009 The PHP Group\n%s", ++ PHP_VERSION, SUHOSIN_PATCH_VERSION, ++#else ++ php_printf("PHP %s (%s) (built: %s %s) %s\nCopyright (c) 1997-2009 The PHP Group\n%s", ++ PHP_VERSION, ++#endif ++ sapi_module.name, __DATE__, __TIME__, + #if ZEND_DEBUG && defined(HAVE_GCOV) + "(DEBUG GCOV)", + #elif ZEND_DEBUG +--- php.orig/win32/build/config.w32 ++++ php/win32/build/config.w32 +@@ -305,7 +305,7 @@ ADD_SOURCES("Zend", "zend_language_parse + zend_sprintf.c zend_ini.c zend_qsort.c zend_multibyte.c zend_ts_hash.c \ + zend_stream.c zend_iterators.c zend_interfaces.c zend_objects.c \ + zend_object_handlers.c zend_objects_API.c \ +- zend_default_classes.c zend_execute.c zend_strtod.c"); ++ zend_default_classes.c zend_execute.c zend_strtod.c zend_canary.c"); + + ADD_SOURCES("main", "main.c snprintf.c spprintf.c safe_mode.c fopen_wrappers.c \ + php_scandir.c php_ini.c SAPI.c rfc1867.c php_content_types.c strlcpy.c \ +@@ -354,6 +354,8 @@ if (PHP_ZEND_MULTIBYTE == "yes") { + AC_DEFINE('HAVE_USLEEP', 1); + AC_DEFINE('HAVE_STRCOLL', 1); + ++AC_DEFINE('SUHOSIN_PATCH', 1); ++ + /* For snapshot builders, where can we find the additional + * files that make up the snapshot template? */ + ARG_WITH("snapshot-template", "Path to snapshot builder template dir", "no"); --- php5-5.2.10.dfsg.1.orig/debian/patches/fix_broken_upstream_tests.patch +++ php5-5.2.10.dfsg.1/debian/patches/fix_broken_upstream_tests.patch @@ -0,0 +1,42 @@ +--- php.orig/ext/soap/tests/server009.phpt ++++ php/ext/soap/tests/server009.phpt +@@ -7,6 +7,10 @@ SOAP Server 9: setclass and setpersisten + die('skip this test needs session extension'); + } + ?> ++--INI-- ++session.auto_start=1 ++session.save_handler=files ++session.save_path=temp_session_store + --FILE-- + + --FILE-- + Command Line Interface + Virtual Directory Support => %s + Configuration File (php.ini) Path => %s + Loaded Configuration File => %a ++Scan this dir for additional .ini files => %s + PHP API => %d + PHP Extension => %d + Zend Extension => %d +--- php.orig/ext/standard/tests/strings/moneyformat.phpt ++++ php/ext/standard/tests/strings/moneyformat.phpt +@@ -5,6 +5,8 @@ money_format test + if (!function_exists('money_format') || !function_exists('setlocale')) { + die("SKIP money_format - not supported\n"); + } ++ if (!setlocale(LC_MONETARY, 'en_US')) ++ die("SKIP money_format - en_US locale not available\n"); + ?> + --FILE-- + FORMAT_CONV_MAX_PRECISION) { ++ precision = FORMAT_CONV_MAX_PRECISION; ++ } + } else + adjust_precision = NO; + } else +Index: main/spprintf.c +=================================================================== +--- main/spprintf.c (revision 308524) ++++ main/spprintf.c (revision 308525) +@@ -285,10 +285,6 @@ + + /* + * Check if a precision was specified +- * +- * XXX: an unreasonable amount of precision may be specified +- * resulting in overflow of num_buf. Currently we +- * ignore this possibility. + */ + if (*fmt == '.') { + adjust_precision = YES; +@@ -302,6 +298,10 @@ + precision = 0; + } else + precision = 0; ++ ++ if (precision > FORMAT_CONV_MAX_PRECISION) { ++ precision = FORMAT_CONV_MAX_PRECISION; ++ } + } else + adjust_precision = NO; + } else +Index: main/snprintf.h +=================================================================== +--- main/snprintf.h (revision 308524) ++++ main/snprintf.h (revision 308525) +@@ -12,7 +12,7 @@ + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ +- | Author: Stig Sther Bakken | ++ | Author: Stig Sæther Bakken | + | Marcus Boerger | + +----------------------------------------------------------------------+ + */ +@@ -158,6 +158,17 @@ + extern char * ap_php_conv_p2(register u_wide_int num, register int nbits, + char format, char *buf_end, register int *len); + ++/* The maximum precision that's allowed for float conversion. Does not include ++ * decimal separator, exponent, sign, terminator. Currently does not affect ++ * the modes e/f, only g/k/H, as those have a different limit enforced at ++ * another level (see NDIG in php_conv_fp()). ++ * Applies to the formatting functions of both spprintf.c and snprintf.c, which ++ * use equally sized buffers of MAX_BUF_SIZE = 512 to hold the result of the ++ * call to php_gcvt(). ++ * This should be reasonably smaller than MAX_BUF_SIZE (I think MAX_BUF_SIZE - 9 ++ * should be enough, but let's give some more space) */ ++#define FORMAT_CONV_MAX_PRECISION 500 ++ + #endif /* SNPRINTF_H */ + + /* --- php5-5.2.10.dfsg.1.orig/debian/patches/045-exif_nesting_level.patch +++ php5-5.2.10.dfsg.1/debian/patches/045-exif_nesting_level.patch @@ -0,0 +1,11 @@ +--- php.orig/ext/exif/exif.c ++++ php/ext/exif/exif.c +@@ -99,7 +99,7 @@ typedef unsigned char uchar; + + #define EFREE_IF(ptr) if (ptr) efree(ptr) + +-#define MAX_IFD_NESTING_LEVEL 100 ++#define MAX_IFD_NESTING_LEVEL 250 + + /* {{{ arginfo */ + static --- php5-5.2.10.dfsg.1.orig/debian/patches/php5-CVE-2011-0421.patch +++ php5-5.2.10.dfsg.1/debian/patches/php5-CVE-2011-0421.patch @@ -0,0 +1,48 @@ +Subject: fix bug 53885 (ZipArchive segfault with FL_UNCHANGED on empty archive) +Origin: http://svn.php.net/viewvc/?view=revision&revision=307867 +Bug: http://bugs.php.net/bug.php?id=53885 + +CVE-2011-421 + +Patch has been modified from upstream commit to remove edits to NEWS, to +reduce conflicts when applying. + +Index: ext/zip/tests/bug53885.phpt +=================================================================== +--- ext/zip/tests/bug53885.phpt (revision 0) ++++ ext/zip/tests/bug53885.phpt (revision 307867) +@@ -0,0 +1,19 @@ ++--TEST-- ++Bug #53885 (ZipArchive segfault with FL_UNCHANGED on empty archive) ++--SKIPIF-- ++ ++--FILE-- ++open($fname); ++$nx->locateName("a",ZIPARCHIVE::FL_UNCHANGED); ++$nx->statName("a",ZIPARCHIVE::FL_UNCHANGED); ++?> ++==DONE== ++--EXPECTF-- ++==DONE== +Index: ext/zip/lib/zip_name_locate.c +=================================================================== +--- ext/zip/lib/zip_name_locate.c (revision 307866) ++++ ext/zip/lib/zip_name_locate.c (revision 307867) +@@ -60,6 +60,10 @@ + return -1; + } + ++ if((flags & ZIP_FL_UNCHANGED) && !za->cdir) { ++ return -1; ++ } ++ + cmp = (flags & ZIP_FL_NOCASE) ? strcmpi : strcmp; + + n = (flags & ZIP_FL_UNCHANGED) ? za->cdir->nentry : za->nentry; --- php5-5.2.10.dfsg.1.orig/debian/patches/php5-CVE-2010-3710.patch +++ php5-5.2.10.dfsg.1/debian/patches/php5-CVE-2010-3710.patch @@ -0,0 +1,53 @@ +Subject: Segfault in filter_var with FILTER_VALIDATE_EMAIL with large amount of data +Origin: http://svn.php.net/viewvc?view=revision&revision=303779 +Bug: http://bugs.php.net/bug.php?id=52929 + +CVE-2010-3710 + +[Ubuntu note: patch differs from upstream commit in that the change to + the NEWS file has been dropped to reduce conflicts - sbeattie] + +--- + ext/filter/logical_filters.c | 5 +++++ + ext/filter/tests/bug52929.phpt | 18 ++++++++++++++++++ + 2 files changed, 23 insertions(+) + +Index: b/ext/filter/tests/bug52929.phpt +=================================================================== +--- /dev/null ++++ b/ext/filter/tests/bug52929.phpt +@@ -0,0 +1,18 @@ ++--TEST-- ++Bug #52929 (Segfault in filter_var with FILTER_VALIDATE_EMAIL with large amount of data) ++--SKIPIF-- ++ ++--FILE-- ++ 320) { ++ RETURN_VALIDATION_FAILED ++ } ++ + re = pcre_get_compiled_regex((char *)regexp, &pcre_extra, &preg_options TSRMLS_CC); + if (!re) { + RETURN_VALIDATION_FAILED --- php5-5.2.10.dfsg.1.orig/debian/patches/112-proc_open.patch +++ php5-5.2.10.dfsg.1/debian/patches/112-proc_open.patch @@ -0,0 +1,11 @@ +--- php.orig/ext/standard/proc_open.c ++++ php/ext/standard/proc_open.c +@@ -61,7 +61,7 @@ + * */ + #ifdef PHP_CAN_SUPPORT_PROC_OPEN + +-#if 0 && HAVE_PTSNAME && HAVE_GRANTPT && HAVE_UNLOCKPT && HAVE_SYS_IOCTL_H && HAVE_TERMIOS_H ++#if HAVE_PTSNAME && HAVE_GRANTPT && HAVE_UNLOCKPT && HAVE_SYS_IOCTL_H && HAVE_TERMIOS_H + # include + # include + # define PHP_CAN_DO_PTS 1 --- php5-5.2.10.dfsg.1.orig/debian/patches/php5-CVE-2011-1466.patch +++ php5-5.2.10.dfsg.1/debian/patches/php5-CVE-2011-1466.patch @@ -0,0 +1,102 @@ +Subject: Fixed bug #53574 (Integer overflow in SdnToJulian, sometimes leading to segfault). +Origin: http://svn.php.net/viewvc?view=revision&revision=306475 + +CVE-2011-1466 + +Patch differs from upstream commit in that the edit to the NEWS file was +dropped to reduce patch conflicts. + +Index: ext/calendar/tests/bug53574.phpt +=================================================================== +--- ext/calendar/tests/bug53574.phpt (revision 0) ++++ ext/calendar/tests/bug53574.phpt (revision 306475) +@@ -0,0 +1,35 @@ ++--TEST-- ++Bug #53574 (Integer overflow in SdnToJulian; leads to segfault) ++--SKIPIF-- ++ ++--FILE-- ++ ++ string(5) "0/0/0" ++ ["month"]=> ++ int(0) ++ ["day"]=> ++ int(0) ++ ["year"]=> ++ int(0) ++ ["dow"]=> ++ int(3) ++ ["abbrevdayname"]=> ++ string(3) "Wed" ++ ["dayname"]=> ++ string(9) "Wednesday" ++ ["abbrevmonth"]=> ++ string(0) "" ++ ["monthname"]=> ++ string(0) "" ++} ++ +Index: ext/calendar/julian.c +=================================================================== +--- ext/calendar/julian.c (revision 306474) ++++ ext/calendar/julian.c (revision 306475) +@@ -146,6 +146,7 @@ + **************************************************************************/ + + #include "sdncal.h" ++#include + + #define JULIAN_SDN_OFFSET 32083 + #define DAYS_PER_5_MONTHS 153 +@@ -164,15 +165,22 @@ + int dayOfYear; + + if (sdn <= 0) { +- *pYear = 0; +- *pMonth = 0; +- *pDay = 0; +- return; ++ goto fail; + } +- temp = (sdn + JULIAN_SDN_OFFSET) * 4 - 1; ++ /* Check for overflow */ ++ if (sdn > (LONG_MAX - JULIAN_SDN_OFFSET * 4 + 1) / 4 || sdn < LONG_MIN / 4) { ++ goto fail; ++ } ++ temp = sdn * 4 + (JULIAN_SDN_OFFSET * 4 - 1); + + /* Calculate the year and day of year (1 <= dayOfYear <= 366). */ +- year = temp / DAYS_PER_4_YEARS; ++ { ++ long yearl = temp / DAYS_PER_4_YEARS; ++ if (yearl > INT_MAX || yearl < INT_MIN) { ++ goto fail; ++ } ++ year = (int) yearl; ++ } + dayOfYear = (temp % DAYS_PER_4_YEARS) / 4 + 1; + + /* Calculate the month and day of month. */ +@@ -196,6 +204,12 @@ + *pYear = year; + *pMonth = month; + *pDay = day; ++ return; ++ ++fail: ++ *pYear = 0; ++ *pMonth = 0; ++ *pDay = 0; + } + + long int JulianToSdn( --- php5-5.2.10.dfsg.1.orig/debian/patches/php5-CVE-2010-3709.patch +++ php5-5.2.10.dfsg.1/debian/patches/php5-CVE-2010-3709.patch @@ -0,0 +1,24 @@ +Subject: fix Fixed NULL pointer dereference in ZipArchive::getArchiveComment +Origin: http://svn.php.net/viewvc?view=revision&revision=304505 + +CVE-2010-3709 +report & patch from Maksymilian Arciemowicz + +--- + ext/zip/php_zip.c | 3 +++ + 1 file changed, 3 insertions(+) + +Index: b/ext/zip/php_zip.c +=================================================================== +--- a/ext/zip/php_zip.c ++++ b/ext/zip/php_zip.c +@@ -1961,6 +1961,9 @@ static ZIPARCHIVE_METHOD(getArchiveComme + } + + comment = zip_get_archive_comment(intern, &comment_len, (int)flags); ++ if(comment==NULL) { ++ RETURN_FALSE; ++ } + RETURN_STRINGL((char *)comment, (long)comment_len, 1); + } + /* }}} */ --- php5-5.2.10.dfsg.1.orig/debian/patches/CVE-2009-4142.patch +++ php5-5.2.10.dfsg.1/debian/patches/CVE-2009-4142.patch @@ -0,0 +1,4587 @@ +Description: fix Cross-site scripting via incomplete htmlspecialchars filtering +Origin: upstream, http://svn.php.net/viewvc/?view=revision&revision=289411 +Origin: upstream, http://svn.php.net/viewvc/?view=revision&revision=289554 +Origin: upstream, http://svn.php.net/viewvc/?view=revision&revision=289565 +Origin: upstream, http://svn.php.net/viewvc/?view=revision&revision=289567 +Origin: upstream, http://svn.php.net/viewvc/?view=revision&revision=289605 +Origin: upstream, http://svn.php.net/viewvc/?view=revision&revision=291821 +Origin: upstream, http://svn.php.net/viewvc/?view=revision&revision=292575 +Bug: http://bugs.php.net/bug.php?id=49785 + +diff -Nur php5-5.2.10.dfsg.1/ext/standard/html.c php5-5.2.10.dfsg.1.new/ext/standard/html.c +--- php5-5.2.10.dfsg.1/ext/standard/html.c 2008-12-31 06:17:45.000000000 -0500 ++++ php5-5.2.10.dfsg.1.new/ext/standard/html.c 2010-01-05 13:12:55.000000000 -0500 +@@ -484,15 +484,31 @@ + } \ + mbseq[mbpos++] = (mbchar); } + ++/* skip one byte and return */ ++#define MB_FAILURE(pos) do { \ ++ *newpos = pos + 1; \ ++ *status = FAILURE; \ ++ return 0; \ ++} while (0) ++ + #define CHECK_LEN(pos, chars_need) \ +- if((str_len - (pos)) < chars_need) { \ +- *status = FAILURE; \ +- return 0; \ ++ if (chars_need < 1) { \ ++ if((str_len - (pos)) < chars_need) { \ ++ *newpos = pos; \ ++ *status = FAILURE; \ ++ return 0; \ ++ } \ ++ } else { \ ++ if((str_len - (pos)) < chars_need) { \ ++ *newpos = pos + 1; \ ++ *status = FAILURE; \ ++ return 0; \ ++ } \ + } + + /* {{{ get_next_char + */ +-inline static unsigned short get_next_char(enum entity_charset charset, ++inline static unsigned int get_next_char(enum entity_charset charset, + unsigned char * str, + int str_len, + int * newpos, +@@ -503,205 +519,191 @@ + int pos = *newpos; + int mbpos = 0; + int mbspace = *mbseqlen; +- unsigned short this_char = str[pos++]; ++ unsigned int this_char = 0; + unsigned char next_char; + + *status = SUCCESS; +- ++ + if (mbspace <= 0) { + *mbseqlen = 0; +- return this_char; ++ CHECK_LEN(pos, 1); ++ *newpos = pos + 1; ++ return str[pos]; + } +- +- MB_WRITE((unsigned char)this_char); +- ++ + switch (charset) { + case cs_utf_8: + { +- unsigned long utf = 0; +- int stat = 0; +- int more = 1; +- +- /* unpack utf-8 encoding into a wide char. +- * Code stolen from the mbstring extension */ +- +- do { +- if (this_char < 0x80) { +- more = 0; +- if(stat) { +- /* we didn't finish the UTF sequence correctly */ +- *status = FAILURE; +- } +- break; +- } else if (this_char < 0xc0) { +- switch (stat) { +- case 0x10: /* 2, 2nd */ +- case 0x21: /* 3, 3rd */ +- case 0x32: /* 4, 4th */ +- case 0x43: /* 5, 5th */ +- case 0x54: /* 6, 6th */ +- /* last byte in sequence */ +- more = 0; +- utf |= (this_char & 0x3f); +- this_char = (unsigned short)utf; +- break; +- case 0x20: /* 3, 2nd */ +- case 0x31: /* 4, 3rd */ +- case 0x42: /* 5, 4th */ +- case 0x53: /* 6, 5th */ +- /* penultimate char */ +- utf |= ((this_char & 0x3f) << 6); +- stat++; +- break; +- case 0x30: /* 4, 2nd */ +- case 0x41: /* 5, 3rd */ +- case 0x52: /* 6, 4th */ +- utf |= ((this_char & 0x3f) << 12); +- stat++; +- break; +- case 0x40: /* 5, 2nd */ +- case 0x51: +- utf |= ((this_char & 0x3f) << 18); +- stat++; +- break; +- case 0x50: /* 6, 2nd */ +- utf |= ((this_char & 0x3f) << 24); +- stat++; +- break; +- default: +- /* invalid */ +- *status = FAILURE; +- more = 0; +- } +- } +- /* lead byte */ +- else if (this_char < 0xe0) { +- stat = 0x10; /* 2 byte */ +- utf = (this_char & 0x1f) << 6; +- CHECK_LEN(pos, 1); +- } else if (this_char < 0xf0) { +- stat = 0x20; /* 3 byte */ +- utf = (this_char & 0xf) << 12; +- CHECK_LEN(pos, 2); +- } else if (this_char < 0xf8) { +- stat = 0x30; /* 4 byte */ +- utf = (this_char & 0x7) << 18; +- CHECK_LEN(pos, 3); +- } else if (this_char < 0xfc) { +- stat = 0x40; /* 5 byte */ +- utf = (this_char & 0x3) << 24; +- CHECK_LEN(pos, 4); +- } else if (this_char < 0xfe) { +- stat = 0x50; /* 6 byte */ +- utf = (this_char & 0x1) << 30; +- CHECK_LEN(pos, 5); +- } else { +- /* invalid; bail */ +- more = 0; +- *status = FAILURE; +- break; ++ unsigned char c; ++ CHECK_LEN(pos, 1); ++ c = str[pos]; ++ if (c < 0x80) { ++ MB_WRITE(c); ++ this_char = c; ++ pos++; ++ } else if (c < 0xc0) { ++ MB_FAILURE(pos); ++ } else if (c < 0xe0) { ++ CHECK_LEN(pos, 2); ++ if (str[pos + 1] < 0x80 || str[pos + 1] > 0xbf) { ++ MB_FAILURE(pos); + } +- +- if (more) { +- this_char = str[pos++]; +- MB_WRITE((unsigned char)this_char); ++ this_char = ((c & 0x1f) << 6) | (str[pos + 1] & 0x3f); ++ if (this_char < 0x80) { ++ MB_FAILURE(pos); + } +- } while (more); ++ MB_WRITE((unsigned char)c); ++ MB_WRITE((unsigned char)str[pos + 1]); ++ pos += 2; ++ } else if (c < 0xf0) { ++ CHECK_LEN(pos, 3); ++ if (str[pos + 1] < 0x80 || str[pos + 1] > 0xbf) { ++ MB_FAILURE(pos); ++ } ++ if (str[pos + 2] < 0x80 || str[pos + 2] > 0xbf) { ++ MB_FAILURE(pos); ++ } ++ this_char = ((c & 0x0f) << 12) | ((str[pos + 1] & 0x3f) << 6) | (str[pos + 2] & 0x3f); ++ if (this_char < 0x800) { ++ MB_FAILURE(pos); ++ } else if (this_char >= 0xd800 && this_char <= 0xdfff) { ++ MB_FAILURE(pos); ++ } ++ MB_WRITE((unsigned char)c); ++ MB_WRITE((unsigned char)str[pos + 1]); ++ MB_WRITE((unsigned char)str[pos + 2]); ++ pos += 3; ++ } else if (c < 0xf8) { ++ CHECK_LEN(pos, 4); ++ if (str[pos + 1] < 0x80 || str[pos + 1] > 0xbf) { ++ MB_FAILURE(pos); ++ } ++ if (str[pos + 2] < 0x80 || str[pos + 2] > 0xbf) { ++ MB_FAILURE(pos); ++ } ++ if (str[pos + 3] < 0x80 || str[pos + 3] > 0xbf) { ++ MB_FAILURE(pos); ++ } ++ this_char = ((c & 0x07) << 18) | ((str[pos + 1] & 0x3f) << 12) | ((str[pos + 2] & 0x3f) << 6) | (str[pos + 3] & 0x3f); ++ if (this_char < 0x10000) { ++ MB_FAILURE(pos); ++ } ++ MB_WRITE((unsigned char)c); ++ MB_WRITE((unsigned char)str[pos + 1]); ++ MB_WRITE((unsigned char)str[pos + 2]); ++ MB_WRITE((unsigned char)str[pos + 3]); ++ pos += 4; ++ } else { ++ MB_FAILURE(pos); ++ } + } + break; + case cs_big5: + case cs_gb2312: + case cs_big5hkscs: + { ++ CHECK_LEN(pos, 1); ++ this_char = str[pos++]; + /* check if this is the first of a 2-byte sequence */ +- if (this_char >= 0xa1 && this_char <= 0xfe) { ++ if (this_char >= 0x81 && this_char <= 0xfe) { + /* peek at the next char */ + CHECK_LEN(pos, 1); +- next_char = str[pos]; ++ next_char = str[pos++]; + if ((next_char >= 0x40 && next_char <= 0x7e) || + (next_char >= 0xa1 && next_char <= 0xfe)) { + /* yes, this a wide char */ +- this_char <<= 8; ++ MB_WRITE(this_char); + MB_WRITE(next_char); +- this_char |= next_char; +- pos++; ++ this_char = (this_char << 8) | next_char; ++ } else { ++ MB_FAILURE(pos); + } +- ++ } else { ++ MB_WRITE(this_char); + } +- break; + } ++ break; + case cs_sjis: + { ++ CHECK_LEN(pos, 1); ++ this_char = str[pos++]; + /* check if this is the first of a 2-byte sequence */ +- if ( (this_char >= 0x81 && this_char <= 0x9f) || +- (this_char >= 0xe0 && this_char <= 0xef) +- ) { ++ if ((this_char >= 0x81 && this_char <= 0x9f) || ++ (this_char >= 0xe0 && this_char <= 0xfc)) { + /* peek at the next char */ + CHECK_LEN(pos, 1); +- next_char = str[pos]; ++ next_char = str[pos++]; + if ((next_char >= 0x40 && next_char <= 0x7e) || + (next_char >= 0x80 && next_char <= 0xfc)) + { + /* yes, this a wide char */ +- this_char <<= 8; ++ MB_WRITE(this_char); + MB_WRITE(next_char); +- this_char |= next_char; +- pos++; ++ this_char = (this_char << 8) | next_char; ++ } else { ++ MB_FAILURE(pos); + } +- ++ } else { ++ MB_WRITE(this_char); + } + break; + } + case cs_eucjp: + { ++ CHECK_LEN(pos, 1); ++ this_char = str[pos++]; + /* check if this is the first of a multi-byte sequence */ + if (this_char >= 0xa1 && this_char <= 0xfe) { + /* peek at the next char */ + CHECK_LEN(pos, 1); +- next_char = str[pos]; ++ next_char = str[pos++]; + if (next_char >= 0xa1 && next_char <= 0xfe) { + /* yes, this a jis kanji char */ +- this_char <<= 8; ++ MB_WRITE(this_char); + MB_WRITE(next_char); +- this_char |= next_char; +- pos++; ++ this_char = (this_char << 8) | next_char; ++ } else { ++ MB_FAILURE(pos); + } +- + } else if (this_char == 0x8e) { + /* peek at the next char */ + CHECK_LEN(pos, 1); +- next_char = str[pos]; ++ next_char = str[pos++]; + if (next_char >= 0xa1 && next_char <= 0xdf) { + /* JIS X 0201 kana */ +- this_char <<= 8; ++ MB_WRITE(this_char); + MB_WRITE(next_char); +- this_char |= next_char; +- pos++; ++ this_char = (this_char << 8) | next_char; ++ } else { ++ MB_FAILURE(pos); + } +- + } else if (this_char == 0x8f) { + /* peek at the next two char */ + unsigned char next2_char; + CHECK_LEN(pos, 2); + next_char = str[pos]; +- next2_char = str[pos+1]; ++ next2_char = str[pos + 1]; ++ pos += 2; + if ((next_char >= 0xa1 && next_char <= 0xfe) && + (next2_char >= 0xa1 && next2_char <= 0xfe)) { + /* JIS X 0212 hojo-kanji */ +- this_char <<= 8; ++ MB_WRITE(this_char); + MB_WRITE(next_char); +- this_char |= next_char; +- pos++; +- this_char <<= 8; + MB_WRITE(next2_char); +- this_char |= next2_char; +- pos++; ++ this_char = (this_char << 16) | (next_char << 8) | next2_char; ++ } else { ++ MB_FAILURE(pos); + } +- ++ } else { ++ MB_WRITE(this_char); + } + break; + } + default: ++ /* single-byte charsets */ ++ CHECK_LEN(pos, 1); ++ this_char = str[pos++]; ++ MB_WRITE(this_char); + break; + } + MB_RETURN; +@@ -1132,7 +1134,7 @@ + unsigned char mbsequence[16]; /* allow up to 15 characters in a multibyte sequence */ + int mbseqlen = sizeof(mbsequence); + int status = SUCCESS; +- unsigned short this_char = get_next_char(charset, old, oldlen, &i, mbsequence, &mbseqlen, &status); ++ unsigned int this_char = get_next_char(charset, old, oldlen, &i, mbsequence, &mbseqlen, &status); + + if(status == FAILURE) { + /* invalid MB sequence */ +diff -Nur php5-5.2.10.dfsg.1/ext/standard/tests/strings/bug49785.phpt php5-5.2.10.dfsg.1.new/ext/standard/tests/strings/bug49785.phpt +--- php5-5.2.10.dfsg.1/ext/standard/tests/strings/bug49785.phpt 1969-12-31 19:00:00.000000000 -0500 ++++ php5-5.2.10.dfsg.1.new/ext/standard/tests/strings/bug49785.phpt 2010-01-05 13:12:55.000000000 -0500 +@@ -0,0 +1,4114 @@ ++--TEST-- ++Bug #49785 (insufficient input string validation of htmlspecialchars()) ++--FILE-- ++= 0x80 ++var_dump(_bin2hex(htmlspecialchars("\x80", ENT_QUOTES, 'Shift_JIS'))); ++foreach (array_map('chr', range(0xa0, 0xdf)) as $c) { ++ var_dump(_bin2hex(htmlspecialchars($c, ENT_QUOTES, 'Shift_JIS'))); ++} ++var_dump(_bin2hex(htmlspecialchars("\xfd", ENT_QUOTES, 'Shift_JIS'))); ++var_dump(_bin2hex(htmlspecialchars("\xfe", ENT_QUOTES, 'Shift_JIS'))); ++var_dump(_bin2hex(htmlspecialchars("\xff", ENT_QUOTES, 'Shift_JIS'))); ++ ++echo "--\n"; ++// Shift_JIS: incomplete / invalid multibyte sequences ++foreach (array_map('chr', array_merge(range(0x81, 0x9f), range(0xe0, 0xfc))) as $c) { ++ var_dump(_bin2hex(htmlspecialchars("$c", ENT_QUOTES, 'Shift_JIS'))); ++ var_dump(_bin2hex(htmlspecialchars("$c\x3f", ENT_QUOTES, 'Shift_JIS'))); ++ var_dump(_bin2hex(htmlspecialchars("$c\x40", ENT_QUOTES, 'Shift_JIS'))); ++ var_dump(_bin2hex(htmlspecialchars("$c\x7e", ENT_QUOTES, 'Shift_JIS'))); ++ var_dump(_bin2hex(htmlspecialchars("$c\x7f", ENT_QUOTES, 'Shift_JIS'))); ++ var_dump(_bin2hex(htmlspecialchars("$c\x80", ENT_QUOTES, 'Shift_JIS'))); ++ var_dump(_bin2hex(htmlspecialchars("$c\xfc", ENT_QUOTES, 'Shift_JIS'))); ++ var_dump(_bin2hex(htmlspecialchars("$c\xfd", ENT_QUOTES, 'Shift_JIS'))); ++ var_dump(_bin2hex(htmlspecialchars("$c\xfe", ENT_QUOTES, 'Shift_JIS'))); ++ var_dump(_bin2hex(htmlspecialchars("$c\xff", ENT_QUOTES, 'Shift_JIS'))); ++} ++ ++echo "--\n"; ++// EUC-JP: non-lead byte >= 0x80 ++foreach (array_map('chr', array_merge(range(0x80, 0x8d), range(0x90, 0x9f))) as $c) { ++ var_dump(_bin2hex(htmlspecialchars($c, ENT_QUOTES, 'EUC-JP'))); ++} ++var_dump(_bin2hex(htmlspecialchars("\xff", ENT_QUOTES, 'EUC-JP'))); ++ ++// EUC-JP: control codes that are virtually lead bytes ++var_dump(_bin2hex(htmlspecialchars("\x8e", ENT_QUOTES, 'EUC-JP'))); ++var_dump(_bin2hex(htmlspecialchars("\x8f", ENT_QUOTES, 'EUC-JP'))); ++var_dump(_bin2hex(htmlspecialchars("\x8e\xa1", ENT_QUOTES, 'EUC-JP'))); ++var_dump(_bin2hex(htmlspecialchars("\x8f\xa1", ENT_QUOTES, 'EUC-JP'))); ++var_dump(_bin2hex(htmlspecialchars("\x8e\xa1\xa3", ENT_QUOTES, 'EUC-JP'))); ++var_dump(_bin2hex(htmlspecialchars("\x8f\xa1\xa3", ENT_QUOTES, 'EUC-JP'))); ++ ++echo "--\n"; ++// EUC-JP: incomplete / invalid multibyte sequences ++foreach (array_map('chr', array_merge(range(0xa1, 0xfe))) as $c) { ++ var_dump(_bin2hex(htmlspecialchars("$c", ENT_QUOTES, 'EUC-JP'))); ++ var_dump(_bin2hex(htmlspecialchars("$c\x26", ENT_QUOTES, 'EUC-JP'))); ++ var_dump(_bin2hex(htmlspecialchars("$c\x80", ENT_QUOTES, 'EUC-JP'))); ++ var_dump(_bin2hex(htmlspecialchars("$c\xa0", ENT_QUOTES, 'EUC-JP'))); ++ var_dump(_bin2hex(htmlspecialchars("$c\xa1", ENT_QUOTES, 'EUC-JP'))); ++ var_dump(_bin2hex(htmlspecialchars("$c\xfe", ENT_QUOTES, 'EUC-JP'))); ++ var_dump(_bin2hex(htmlspecialchars("$c\xff", ENT_QUOTES, 'EUC-JP'))); ++ var_dump(_bin2hex(htmlspecialchars("\x8e$c", ENT_QUOTES, 'EUC-JP'))); ++ var_dump(_bin2hex(htmlspecialchars("\x8e$c\x26", ENT_QUOTES, 'EUC-JP'))); ++ var_dump(_bin2hex(htmlspecialchars("\x8e$c\x80", ENT_QUOTES, 'EUC-JP'))); ++ var_dump(_bin2hex(htmlspecialchars("\x8e$c\xa0", ENT_QUOTES, 'EUC-JP'))); ++ var_dump(_bin2hex(htmlspecialchars("\x8e$c\xa1", ENT_QUOTES, 'EUC-JP'))); ++ var_dump(_bin2hex(htmlspecialchars("\x8e$c\xfe", ENT_QUOTES, 'EUC-JP'))); ++ var_dump(_bin2hex(htmlspecialchars("\x8e$c\xff", ENT_QUOTES, 'EUC-JP'))); ++ var_dump(_bin2hex(htmlspecialchars("\x8f$c", ENT_QUOTES, 'EUC-JP'))); ++ var_dump(_bin2hex(htmlspecialchars("\x8f$c\x26", ENT_QUOTES, 'EUC-JP'))); ++ var_dump(_bin2hex(htmlspecialchars("\x8f$c\x80", ENT_QUOTES, 'EUC-JP'))); ++ var_dump(_bin2hex(htmlspecialchars("\x8f$c\xa0", ENT_QUOTES, 'EUC-JP'))); ++ var_dump(_bin2hex(htmlspecialchars("\x8f$c\xa1", ENT_QUOTES, 'EUC-JP'))); ++ var_dump(_bin2hex(htmlspecialchars("\x8f$c\xfe", ENT_QUOTES, 'EUC-JP'))); ++ var_dump(_bin2hex(htmlspecialchars("\x8f$c\xff", ENT_QUOTES, 'EUC-JP'))); ++} ++ ++echo "--\n"; ++// BIG5: non-lead byte >= 0x80 ++var_dump(_bin2hex(htmlspecialchars("\x80", ENT_QUOTES, 'BIG5'))); ++var_dump(_bin2hex(htmlspecialchars("\xff", ENT_QUOTES, 'BIG5'))); ++ ++echo "--\n"; ++// BIG5: incomplete / invalid multibyte sequences ++foreach (array_map('chr', range(0x81, 0xfe)) as $c) { ++ var_dump(_bin2hex(htmlspecialchars("$c", ENT_QUOTES, 'BIG5'))); ++ var_dump(_bin2hex(htmlspecialchars("$c\x3f", ENT_QUOTES, 'BIG5'))); ++ var_dump(_bin2hex(htmlspecialchars("$c\x40", ENT_QUOTES, 'BIG5'))); ++ var_dump(_bin2hex(htmlspecialchars("$c\x7e", ENT_QUOTES, 'BIG5'))); ++ var_dump(_bin2hex(htmlspecialchars("$c\x7f", ENT_QUOTES, 'BIG5'))); ++ var_dump(_bin2hex(htmlspecialchars("$c\x80", ENT_QUOTES, 'BIG5'))); ++ var_dump(_bin2hex(htmlspecialchars("$c\xa0", ENT_QUOTES, 'BIG5'))); ++ var_dump(_bin2hex(htmlspecialchars("$c\xa1", ENT_QUOTES, 'BIG5'))); ++ var_dump(_bin2hex(htmlspecialchars("$c\xfe", ENT_QUOTES, 'BIG5'))); ++ var_dump(_bin2hex(htmlspecialchars("$c\xff", ENT_QUOTES, 'BIG5'))); ++} ++?> ++--EXPECT-- ++string(0) "" ++string(4) "c280" ++string(0) "" ++string(0) "" ++string(14) "26416c7068613b" ++string(14) "26616c7068613b" ++string(4) "dfbf" ++string(6) "e0a080" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(16) "266865617274733b" ++string(6) "efbfbf" ++string(0) "" ++string(0) "" ++string(0) "" ++string(8) "f0908080" ++string(8) "f7bfbfbf" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++-- ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "ecbfbf" ++string(0) "" ++string(0) "" ++string(6) "ee8080" ++string(2) "80" ++string(2) "a0" ++string(2) "a1" ++string(2) "a2" ++string(2) "a3" ++string(2) "a4" ++string(2) "a5" ++string(2) "a6" ++string(2) "a7" ++string(2) "a8" ++string(2) "a9" ++string(2) "aa" ++string(2) "ab" ++string(2) "ac" ++string(2) "ad" ++string(2) "ae" ++string(2) "af" ++string(2) "b0" ++string(2) "b1" ++string(2) "b2" ++string(2) "b3" ++string(2) "b4" ++string(2) "b5" ++string(2) "b6" ++string(2) "b7" ++string(2) "b8" ++string(2) "b9" ++string(2) "ba" ++string(2) "bb" ++string(2) "bc" ++string(2) "bd" ++string(2) "be" ++string(2) "bf" ++string(2) "c0" ++string(2) "c1" ++string(2) "c2" ++string(2) "c3" ++string(2) "c4" ++string(2) "c5" ++string(2) "c6" ++string(2) "c7" ++string(2) "c8" ++string(2) "c9" ++string(2) "ca" ++string(2) "cb" ++string(2) "cc" ++string(2) "cd" ++string(2) "ce" ++string(2) "cf" ++string(2) "d0" ++string(2) "d1" ++string(2) "d2" ++string(2) "d3" ++string(2) "d4" ++string(2) "d5" ++string(2) "d6" ++string(2) "d7" ++string(2) "d8" ++string(2) "d9" ++string(2) "da" ++string(2) "db" ++string(2) "dc" ++string(2) "dd" ++string(2) "de" ++string(2) "df" ++string(2) "fd" ++string(2) "fe" ++string(2) "ff" ++-- ++string(0) "" ++string(0) "" ++string(4) "8140" ++string(4) "817e" ++string(0) "" ++string(4) "8180" ++string(4) "81fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8240" ++string(4) "827e" ++string(0) "" ++string(4) "8280" ++string(4) "82fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8340" ++string(4) "837e" ++string(0) "" ++string(4) "8380" ++string(4) "83fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8440" ++string(4) "847e" ++string(0) "" ++string(4) "8480" ++string(4) "84fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8540" ++string(4) "857e" ++string(0) "" ++string(4) "8580" ++string(4) "85fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8640" ++string(4) "867e" ++string(0) "" ++string(4) "8680" ++string(4) "86fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8740" ++string(4) "877e" ++string(0) "" ++string(4) "8780" ++string(4) "87fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8840" ++string(4) "887e" ++string(0) "" ++string(4) "8880" ++string(4) "88fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8940" ++string(4) "897e" ++string(0) "" ++string(4) "8980" ++string(4) "89fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8a40" ++string(4) "8a7e" ++string(0) "" ++string(4) "8a80" ++string(4) "8afc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8b40" ++string(4) "8b7e" ++string(0) "" ++string(4) "8b80" ++string(4) "8bfc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8c40" ++string(4) "8c7e" ++string(0) "" ++string(4) "8c80" ++string(4) "8cfc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8d40" ++string(4) "8d7e" ++string(0) "" ++string(4) "8d80" ++string(4) "8dfc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8e40" ++string(4) "8e7e" ++string(0) "" ++string(4) "8e80" ++string(4) "8efc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8f40" ++string(4) "8f7e" ++string(0) "" ++string(4) "8f80" ++string(4) "8ffc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9040" ++string(4) "907e" ++string(0) "" ++string(4) "9080" ++string(4) "90fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9140" ++string(4) "917e" ++string(0) "" ++string(4) "9180" ++string(4) "91fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9240" ++string(4) "927e" ++string(0) "" ++string(4) "9280" ++string(4) "92fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9340" ++string(4) "937e" ++string(0) "" ++string(4) "9380" ++string(4) "93fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9440" ++string(4) "947e" ++string(0) "" ++string(4) "9480" ++string(4) "94fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9540" ++string(4) "957e" ++string(0) "" ++string(4) "9580" ++string(4) "95fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9640" ++string(4) "967e" ++string(0) "" ++string(4) "9680" ++string(4) "96fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9740" ++string(4) "977e" ++string(0) "" ++string(4) "9780" ++string(4) "97fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9840" ++string(4) "987e" ++string(0) "" ++string(4) "9880" ++string(4) "98fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9940" ++string(4) "997e" ++string(0) "" ++string(4) "9980" ++string(4) "99fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9a40" ++string(4) "9a7e" ++string(0) "" ++string(4) "9a80" ++string(4) "9afc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9b40" ++string(4) "9b7e" ++string(0) "" ++string(4) "9b80" ++string(4) "9bfc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9c40" ++string(4) "9c7e" ++string(0) "" ++string(4) "9c80" ++string(4) "9cfc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9d40" ++string(4) "9d7e" ++string(0) "" ++string(4) "9d80" ++string(4) "9dfc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9e40" ++string(4) "9e7e" ++string(0) "" ++string(4) "9e80" ++string(4) "9efc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9f40" ++string(4) "9f7e" ++string(0) "" ++string(4) "9f80" ++string(4) "9ffc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e040" ++string(4) "e07e" ++string(0) "" ++string(4) "e080" ++string(4) "e0fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e140" ++string(4) "e17e" ++string(0) "" ++string(4) "e180" ++string(4) "e1fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e240" ++string(4) "e27e" ++string(0) "" ++string(4) "e280" ++string(4) "e2fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e340" ++string(4) "e37e" ++string(0) "" ++string(4) "e380" ++string(4) "e3fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e440" ++string(4) "e47e" ++string(0) "" ++string(4) "e480" ++string(4) "e4fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e540" ++string(4) "e57e" ++string(0) "" ++string(4) "e580" ++string(4) "e5fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e640" ++string(4) "e67e" ++string(0) "" ++string(4) "e680" ++string(4) "e6fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e740" ++string(4) "e77e" ++string(0) "" ++string(4) "e780" ++string(4) "e7fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e840" ++string(4) "e87e" ++string(0) "" ++string(4) "e880" ++string(4) "e8fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e940" ++string(4) "e97e" ++string(0) "" ++string(4) "e980" ++string(4) "e9fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "ea40" ++string(4) "ea7e" ++string(0) "" ++string(4) "ea80" ++string(4) "eafc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "eb40" ++string(4) "eb7e" ++string(0) "" ++string(4) "eb80" ++string(4) "ebfc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "ec40" ++string(4) "ec7e" ++string(0) "" ++string(4) "ec80" ++string(4) "ecfc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "ed40" ++string(4) "ed7e" ++string(0) "" ++string(4) "ed80" ++string(4) "edfc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "ee40" ++string(4) "ee7e" ++string(0) "" ++string(4) "ee80" ++string(4) "eefc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "ef40" ++string(4) "ef7e" ++string(0) "" ++string(4) "ef80" ++string(4) "effc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f040" ++string(4) "f07e" ++string(0) "" ++string(4) "f080" ++string(4) "f0fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f140" ++string(4) "f17e" ++string(0) "" ++string(4) "f180" ++string(4) "f1fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f240" ++string(4) "f27e" ++string(0) "" ++string(4) "f280" ++string(4) "f2fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f340" ++string(4) "f37e" ++string(0) "" ++string(4) "f380" ++string(4) "f3fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f440" ++string(4) "f47e" ++string(0) "" ++string(4) "f480" ++string(4) "f4fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f540" ++string(4) "f57e" ++string(0) "" ++string(4) "f580" ++string(4) "f5fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f640" ++string(4) "f67e" ++string(0) "" ++string(4) "f680" ++string(4) "f6fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f740" ++string(4) "f77e" ++string(0) "" ++string(4) "f780" ++string(4) "f7fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f840" ++string(4) "f87e" ++string(0) "" ++string(4) "f880" ++string(4) "f8fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f940" ++string(4) "f97e" ++string(0) "" ++string(4) "f980" ++string(4) "f9fc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "fa40" ++string(4) "fa7e" ++string(0) "" ++string(4) "fa80" ++string(4) "fafc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "fb40" ++string(4) "fb7e" ++string(0) "" ++string(4) "fb80" ++string(4) "fbfc" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "fc40" ++string(4) "fc7e" ++string(0) "" ++string(4) "fc80" ++string(4) "fcfc" ++string(0) "" ++string(0) "" ++string(0) "" ++-- ++string(2) "80" ++string(2) "81" ++string(2) "82" ++string(2) "83" ++string(2) "84" ++string(2) "85" ++string(2) "86" ++string(2) "87" ++string(2) "88" ++string(2) "89" ++string(2) "8a" ++string(2) "8b" ++string(2) "8c" ++string(2) "8d" ++string(2) "90" ++string(2) "91" ++string(2) "92" ++string(2) "93" ++string(2) "94" ++string(2) "95" ++string(2) "96" ++string(2) "97" ++string(2) "98" ++string(2) "99" ++string(2) "9a" ++string(2) "9b" ++string(2) "9c" ++string(2) "9d" ++string(2) "9e" ++string(2) "9f" ++string(2) "ff" ++string(0) "" ++string(0) "" ++string(4) "8ea1" ++string(0) "" ++string(0) "" ++string(6) "8fa1a3" ++-- ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "a1a1" ++string(4) "a1fe" ++string(0) "" ++string(4) "8ea1" ++string(14) "8ea126616d703b" ++string(6) "8ea180" ++string(6) "8ea1a0" ++string(0) "" ++string(0) "" ++string(6) "8ea1ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fa1a1" ++string(6) "8fa1fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "a2a1" ++string(4) "a2fe" ++string(0) "" ++string(4) "8ea2" ++string(14) "8ea226616d703b" ++string(6) "8ea280" ++string(6) "8ea2a0" ++string(0) "" ++string(0) "" ++string(6) "8ea2ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fa2a1" ++string(6) "8fa2fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "a3a1" ++string(4) "a3fe" ++string(0) "" ++string(4) "8ea3" ++string(14) "8ea326616d703b" ++string(6) "8ea380" ++string(6) "8ea3a0" ++string(0) "" ++string(0) "" ++string(6) "8ea3ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fa3a1" ++string(6) "8fa3fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "a4a1" ++string(4) "a4fe" ++string(0) "" ++string(4) "8ea4" ++string(14) "8ea426616d703b" ++string(6) "8ea480" ++string(6) "8ea4a0" ++string(0) "" ++string(0) "" ++string(6) "8ea4ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fa4a1" ++string(6) "8fa4fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "a5a1" ++string(4) "a5fe" ++string(0) "" ++string(4) "8ea5" ++string(14) "8ea526616d703b" ++string(6) "8ea580" ++string(6) "8ea5a0" ++string(0) "" ++string(0) "" ++string(6) "8ea5ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fa5a1" ++string(6) "8fa5fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "a6a1" ++string(4) "a6fe" ++string(0) "" ++string(4) "8ea6" ++string(14) "8ea626616d703b" ++string(6) "8ea680" ++string(6) "8ea6a0" ++string(0) "" ++string(0) "" ++string(6) "8ea6ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fa6a1" ++string(6) "8fa6fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "a7a1" ++string(4) "a7fe" ++string(0) "" ++string(4) "8ea7" ++string(14) "8ea726616d703b" ++string(6) "8ea780" ++string(6) "8ea7a0" ++string(0) "" ++string(0) "" ++string(6) "8ea7ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fa7a1" ++string(6) "8fa7fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "a8a1" ++string(4) "a8fe" ++string(0) "" ++string(4) "8ea8" ++string(14) "8ea826616d703b" ++string(6) "8ea880" ++string(6) "8ea8a0" ++string(0) "" ++string(0) "" ++string(6) "8ea8ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fa8a1" ++string(6) "8fa8fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "a9a1" ++string(4) "a9fe" ++string(0) "" ++string(4) "8ea9" ++string(14) "8ea926616d703b" ++string(6) "8ea980" ++string(6) "8ea9a0" ++string(0) "" ++string(0) "" ++string(6) "8ea9ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fa9a1" ++string(6) "8fa9fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "aaa1" ++string(4) "aafe" ++string(0) "" ++string(4) "8eaa" ++string(14) "8eaa26616d703b" ++string(6) "8eaa80" ++string(6) "8eaaa0" ++string(0) "" ++string(0) "" ++string(6) "8eaaff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8faaa1" ++string(6) "8faafe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "aba1" ++string(4) "abfe" ++string(0) "" ++string(4) "8eab" ++string(14) "8eab26616d703b" ++string(6) "8eab80" ++string(6) "8eaba0" ++string(0) "" ++string(0) "" ++string(6) "8eabff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8faba1" ++string(6) "8fabfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "aca1" ++string(4) "acfe" ++string(0) "" ++string(4) "8eac" ++string(14) "8eac26616d703b" ++string(6) "8eac80" ++string(6) "8eaca0" ++string(0) "" ++string(0) "" ++string(6) "8eacff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8faca1" ++string(6) "8facfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "ada1" ++string(4) "adfe" ++string(0) "" ++string(4) "8ead" ++string(14) "8ead26616d703b" ++string(6) "8ead80" ++string(6) "8eada0" ++string(0) "" ++string(0) "" ++string(6) "8eadff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fada1" ++string(6) "8fadfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "aea1" ++string(4) "aefe" ++string(0) "" ++string(4) "8eae" ++string(14) "8eae26616d703b" ++string(6) "8eae80" ++string(6) "8eaea0" ++string(0) "" ++string(0) "" ++string(6) "8eaeff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8faea1" ++string(6) "8faefe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "afa1" ++string(4) "affe" ++string(0) "" ++string(4) "8eaf" ++string(14) "8eaf26616d703b" ++string(6) "8eaf80" ++string(6) "8eafa0" ++string(0) "" ++string(0) "" ++string(6) "8eafff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fafa1" ++string(6) "8faffe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "b0a1" ++string(4) "b0fe" ++string(0) "" ++string(4) "8eb0" ++string(14) "8eb026616d703b" ++string(6) "8eb080" ++string(6) "8eb0a0" ++string(0) "" ++string(0) "" ++string(6) "8eb0ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fb0a1" ++string(6) "8fb0fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "b1a1" ++string(4) "b1fe" ++string(0) "" ++string(4) "8eb1" ++string(14) "8eb126616d703b" ++string(6) "8eb180" ++string(6) "8eb1a0" ++string(0) "" ++string(0) "" ++string(6) "8eb1ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fb1a1" ++string(6) "8fb1fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "b2a1" ++string(4) "b2fe" ++string(0) "" ++string(4) "8eb2" ++string(14) "8eb226616d703b" ++string(6) "8eb280" ++string(6) "8eb2a0" ++string(0) "" ++string(0) "" ++string(6) "8eb2ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fb2a1" ++string(6) "8fb2fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "b3a1" ++string(4) "b3fe" ++string(0) "" ++string(4) "8eb3" ++string(14) "8eb326616d703b" ++string(6) "8eb380" ++string(6) "8eb3a0" ++string(0) "" ++string(0) "" ++string(6) "8eb3ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fb3a1" ++string(6) "8fb3fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "b4a1" ++string(4) "b4fe" ++string(0) "" ++string(4) "8eb4" ++string(14) "8eb426616d703b" ++string(6) "8eb480" ++string(6) "8eb4a0" ++string(0) "" ++string(0) "" ++string(6) "8eb4ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fb4a1" ++string(6) "8fb4fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "b5a1" ++string(4) "b5fe" ++string(0) "" ++string(4) "8eb5" ++string(14) "8eb526616d703b" ++string(6) "8eb580" ++string(6) "8eb5a0" ++string(0) "" ++string(0) "" ++string(6) "8eb5ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fb5a1" ++string(6) "8fb5fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "b6a1" ++string(4) "b6fe" ++string(0) "" ++string(4) "8eb6" ++string(14) "8eb626616d703b" ++string(6) "8eb680" ++string(6) "8eb6a0" ++string(0) "" ++string(0) "" ++string(6) "8eb6ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fb6a1" ++string(6) "8fb6fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "b7a1" ++string(4) "b7fe" ++string(0) "" ++string(4) "8eb7" ++string(14) "8eb726616d703b" ++string(6) "8eb780" ++string(6) "8eb7a0" ++string(0) "" ++string(0) "" ++string(6) "8eb7ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fb7a1" ++string(6) "8fb7fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "b8a1" ++string(4) "b8fe" ++string(0) "" ++string(4) "8eb8" ++string(14) "8eb826616d703b" ++string(6) "8eb880" ++string(6) "8eb8a0" ++string(0) "" ++string(0) "" ++string(6) "8eb8ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fb8a1" ++string(6) "8fb8fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "b9a1" ++string(4) "b9fe" ++string(0) "" ++string(4) "8eb9" ++string(14) "8eb926616d703b" ++string(6) "8eb980" ++string(6) "8eb9a0" ++string(0) "" ++string(0) "" ++string(6) "8eb9ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fb9a1" ++string(6) "8fb9fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "baa1" ++string(4) "bafe" ++string(0) "" ++string(4) "8eba" ++string(14) "8eba26616d703b" ++string(6) "8eba80" ++string(6) "8ebaa0" ++string(0) "" ++string(0) "" ++string(6) "8ebaff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fbaa1" ++string(6) "8fbafe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "bba1" ++string(4) "bbfe" ++string(0) "" ++string(4) "8ebb" ++string(14) "8ebb26616d703b" ++string(6) "8ebb80" ++string(6) "8ebba0" ++string(0) "" ++string(0) "" ++string(6) "8ebbff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fbba1" ++string(6) "8fbbfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "bca1" ++string(4) "bcfe" ++string(0) "" ++string(4) "8ebc" ++string(14) "8ebc26616d703b" ++string(6) "8ebc80" ++string(6) "8ebca0" ++string(0) "" ++string(0) "" ++string(6) "8ebcff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fbca1" ++string(6) "8fbcfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "bda1" ++string(4) "bdfe" ++string(0) "" ++string(4) "8ebd" ++string(14) "8ebd26616d703b" ++string(6) "8ebd80" ++string(6) "8ebda0" ++string(0) "" ++string(0) "" ++string(6) "8ebdff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fbda1" ++string(6) "8fbdfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "bea1" ++string(4) "befe" ++string(0) "" ++string(4) "8ebe" ++string(14) "8ebe26616d703b" ++string(6) "8ebe80" ++string(6) "8ebea0" ++string(0) "" ++string(0) "" ++string(6) "8ebeff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fbea1" ++string(6) "8fbefe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "bfa1" ++string(4) "bffe" ++string(0) "" ++string(4) "8ebf" ++string(14) "8ebf26616d703b" ++string(6) "8ebf80" ++string(6) "8ebfa0" ++string(0) "" ++string(0) "" ++string(6) "8ebfff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fbfa1" ++string(6) "8fbffe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "c0a1" ++string(4) "c0fe" ++string(0) "" ++string(4) "8ec0" ++string(14) "8ec026616d703b" ++string(6) "8ec080" ++string(6) "8ec0a0" ++string(0) "" ++string(0) "" ++string(6) "8ec0ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fc0a1" ++string(6) "8fc0fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "c1a1" ++string(4) "c1fe" ++string(0) "" ++string(4) "8ec1" ++string(14) "8ec126616d703b" ++string(6) "8ec180" ++string(6) "8ec1a0" ++string(0) "" ++string(0) "" ++string(6) "8ec1ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fc1a1" ++string(6) "8fc1fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "c2a1" ++string(4) "c2fe" ++string(0) "" ++string(4) "8ec2" ++string(14) "8ec226616d703b" ++string(6) "8ec280" ++string(6) "8ec2a0" ++string(0) "" ++string(0) "" ++string(6) "8ec2ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fc2a1" ++string(6) "8fc2fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "c3a1" ++string(4) "c3fe" ++string(0) "" ++string(4) "8ec3" ++string(14) "8ec326616d703b" ++string(6) "8ec380" ++string(6) "8ec3a0" ++string(0) "" ++string(0) "" ++string(6) "8ec3ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fc3a1" ++string(6) "8fc3fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "c4a1" ++string(4) "c4fe" ++string(0) "" ++string(4) "8ec4" ++string(14) "8ec426616d703b" ++string(6) "8ec480" ++string(6) "8ec4a0" ++string(0) "" ++string(0) "" ++string(6) "8ec4ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fc4a1" ++string(6) "8fc4fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "c5a1" ++string(4) "c5fe" ++string(0) "" ++string(4) "8ec5" ++string(14) "8ec526616d703b" ++string(6) "8ec580" ++string(6) "8ec5a0" ++string(0) "" ++string(0) "" ++string(6) "8ec5ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fc5a1" ++string(6) "8fc5fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "c6a1" ++string(4) "c6fe" ++string(0) "" ++string(4) "8ec6" ++string(14) "8ec626616d703b" ++string(6) "8ec680" ++string(6) "8ec6a0" ++string(0) "" ++string(0) "" ++string(6) "8ec6ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fc6a1" ++string(6) "8fc6fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "c7a1" ++string(4) "c7fe" ++string(0) "" ++string(4) "8ec7" ++string(14) "8ec726616d703b" ++string(6) "8ec780" ++string(6) "8ec7a0" ++string(0) "" ++string(0) "" ++string(6) "8ec7ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fc7a1" ++string(6) "8fc7fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "c8a1" ++string(4) "c8fe" ++string(0) "" ++string(4) "8ec8" ++string(14) "8ec826616d703b" ++string(6) "8ec880" ++string(6) "8ec8a0" ++string(0) "" ++string(0) "" ++string(6) "8ec8ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fc8a1" ++string(6) "8fc8fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "c9a1" ++string(4) "c9fe" ++string(0) "" ++string(4) "8ec9" ++string(14) "8ec926616d703b" ++string(6) "8ec980" ++string(6) "8ec9a0" ++string(0) "" ++string(0) "" ++string(6) "8ec9ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fc9a1" ++string(6) "8fc9fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "caa1" ++string(4) "cafe" ++string(0) "" ++string(4) "8eca" ++string(14) "8eca26616d703b" ++string(6) "8eca80" ++string(6) "8ecaa0" ++string(0) "" ++string(0) "" ++string(6) "8ecaff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fcaa1" ++string(6) "8fcafe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "cba1" ++string(4) "cbfe" ++string(0) "" ++string(4) "8ecb" ++string(14) "8ecb26616d703b" ++string(6) "8ecb80" ++string(6) "8ecba0" ++string(0) "" ++string(0) "" ++string(6) "8ecbff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fcba1" ++string(6) "8fcbfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "cca1" ++string(4) "ccfe" ++string(0) "" ++string(4) "8ecc" ++string(14) "8ecc26616d703b" ++string(6) "8ecc80" ++string(6) "8ecca0" ++string(0) "" ++string(0) "" ++string(6) "8eccff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fcca1" ++string(6) "8fccfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "cda1" ++string(4) "cdfe" ++string(0) "" ++string(4) "8ecd" ++string(14) "8ecd26616d703b" ++string(6) "8ecd80" ++string(6) "8ecda0" ++string(0) "" ++string(0) "" ++string(6) "8ecdff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fcda1" ++string(6) "8fcdfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "cea1" ++string(4) "cefe" ++string(0) "" ++string(4) "8ece" ++string(14) "8ece26616d703b" ++string(6) "8ece80" ++string(6) "8ecea0" ++string(0) "" ++string(0) "" ++string(6) "8eceff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fcea1" ++string(6) "8fcefe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "cfa1" ++string(4) "cffe" ++string(0) "" ++string(4) "8ecf" ++string(14) "8ecf26616d703b" ++string(6) "8ecf80" ++string(6) "8ecfa0" ++string(0) "" ++string(0) "" ++string(6) "8ecfff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fcfa1" ++string(6) "8fcffe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "d0a1" ++string(4) "d0fe" ++string(0) "" ++string(4) "8ed0" ++string(14) "8ed026616d703b" ++string(6) "8ed080" ++string(6) "8ed0a0" ++string(0) "" ++string(0) "" ++string(6) "8ed0ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fd0a1" ++string(6) "8fd0fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "d1a1" ++string(4) "d1fe" ++string(0) "" ++string(4) "8ed1" ++string(14) "8ed126616d703b" ++string(6) "8ed180" ++string(6) "8ed1a0" ++string(0) "" ++string(0) "" ++string(6) "8ed1ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fd1a1" ++string(6) "8fd1fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "d2a1" ++string(4) "d2fe" ++string(0) "" ++string(4) "8ed2" ++string(14) "8ed226616d703b" ++string(6) "8ed280" ++string(6) "8ed2a0" ++string(0) "" ++string(0) "" ++string(6) "8ed2ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fd2a1" ++string(6) "8fd2fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "d3a1" ++string(4) "d3fe" ++string(0) "" ++string(4) "8ed3" ++string(14) "8ed326616d703b" ++string(6) "8ed380" ++string(6) "8ed3a0" ++string(0) "" ++string(0) "" ++string(6) "8ed3ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fd3a1" ++string(6) "8fd3fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "d4a1" ++string(4) "d4fe" ++string(0) "" ++string(4) "8ed4" ++string(14) "8ed426616d703b" ++string(6) "8ed480" ++string(6) "8ed4a0" ++string(0) "" ++string(0) "" ++string(6) "8ed4ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fd4a1" ++string(6) "8fd4fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "d5a1" ++string(4) "d5fe" ++string(0) "" ++string(4) "8ed5" ++string(14) "8ed526616d703b" ++string(6) "8ed580" ++string(6) "8ed5a0" ++string(0) "" ++string(0) "" ++string(6) "8ed5ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fd5a1" ++string(6) "8fd5fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "d6a1" ++string(4) "d6fe" ++string(0) "" ++string(4) "8ed6" ++string(14) "8ed626616d703b" ++string(6) "8ed680" ++string(6) "8ed6a0" ++string(0) "" ++string(0) "" ++string(6) "8ed6ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fd6a1" ++string(6) "8fd6fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "d7a1" ++string(4) "d7fe" ++string(0) "" ++string(4) "8ed7" ++string(14) "8ed726616d703b" ++string(6) "8ed780" ++string(6) "8ed7a0" ++string(0) "" ++string(0) "" ++string(6) "8ed7ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fd7a1" ++string(6) "8fd7fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "d8a1" ++string(4) "d8fe" ++string(0) "" ++string(4) "8ed8" ++string(14) "8ed826616d703b" ++string(6) "8ed880" ++string(6) "8ed8a0" ++string(0) "" ++string(0) "" ++string(6) "8ed8ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fd8a1" ++string(6) "8fd8fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "d9a1" ++string(4) "d9fe" ++string(0) "" ++string(4) "8ed9" ++string(14) "8ed926616d703b" ++string(6) "8ed980" ++string(6) "8ed9a0" ++string(0) "" ++string(0) "" ++string(6) "8ed9ff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fd9a1" ++string(6) "8fd9fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "daa1" ++string(4) "dafe" ++string(0) "" ++string(4) "8eda" ++string(14) "8eda26616d703b" ++string(6) "8eda80" ++string(6) "8edaa0" ++string(0) "" ++string(0) "" ++string(6) "8edaff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fdaa1" ++string(6) "8fdafe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "dba1" ++string(4) "dbfe" ++string(0) "" ++string(4) "8edb" ++string(14) "8edb26616d703b" ++string(6) "8edb80" ++string(6) "8edba0" ++string(0) "" ++string(0) "" ++string(6) "8edbff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fdba1" ++string(6) "8fdbfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "dca1" ++string(4) "dcfe" ++string(0) "" ++string(4) "8edc" ++string(14) "8edc26616d703b" ++string(6) "8edc80" ++string(6) "8edca0" ++string(0) "" ++string(0) "" ++string(6) "8edcff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fdca1" ++string(6) "8fdcfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "dda1" ++string(4) "ddfe" ++string(0) "" ++string(4) "8edd" ++string(14) "8edd26616d703b" ++string(6) "8edd80" ++string(6) "8edda0" ++string(0) "" ++string(0) "" ++string(6) "8eddff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fdda1" ++string(6) "8fddfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "dea1" ++string(4) "defe" ++string(0) "" ++string(4) "8ede" ++string(14) "8ede26616d703b" ++string(6) "8ede80" ++string(6) "8edea0" ++string(0) "" ++string(0) "" ++string(6) "8edeff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fdea1" ++string(6) "8fdefe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "dfa1" ++string(4) "dffe" ++string(0) "" ++string(4) "8edf" ++string(14) "8edf26616d703b" ++string(6) "8edf80" ++string(6) "8edfa0" ++string(0) "" ++string(0) "" ++string(6) "8edfff" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fdfa1" ++string(6) "8fdffe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e0a1" ++string(4) "e0fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fe0a1" ++string(6) "8fe0fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e1a1" ++string(4) "e1fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fe1a1" ++string(6) "8fe1fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e2a1" ++string(4) "e2fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fe2a1" ++string(6) "8fe2fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e3a1" ++string(4) "e3fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fe3a1" ++string(6) "8fe3fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e4a1" ++string(4) "e4fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fe4a1" ++string(6) "8fe4fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e5a1" ++string(4) "e5fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fe5a1" ++string(6) "8fe5fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e6a1" ++string(4) "e6fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fe6a1" ++string(6) "8fe6fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e7a1" ++string(4) "e7fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fe7a1" ++string(6) "8fe7fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e8a1" ++string(4) "e8fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fe8a1" ++string(6) "8fe8fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e9a1" ++string(4) "e9fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fe9a1" ++string(6) "8fe9fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "eaa1" ++string(4) "eafe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8feaa1" ++string(6) "8feafe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "eba1" ++string(4) "ebfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8feba1" ++string(6) "8febfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "eca1" ++string(4) "ecfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8feca1" ++string(6) "8fecfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "eda1" ++string(4) "edfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8feda1" ++string(6) "8fedfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "eea1" ++string(4) "eefe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8feea1" ++string(6) "8feefe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "efa1" ++string(4) "effe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8fefa1" ++string(6) "8feffe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f0a1" ++string(4) "f0fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8ff0a1" ++string(6) "8ff0fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f1a1" ++string(4) "f1fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8ff1a1" ++string(6) "8ff1fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f2a1" ++string(4) "f2fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8ff2a1" ++string(6) "8ff2fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f3a1" ++string(4) "f3fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8ff3a1" ++string(6) "8ff3fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f4a1" ++string(4) "f4fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8ff4a1" ++string(6) "8ff4fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f5a1" ++string(4) "f5fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8ff5a1" ++string(6) "8ff5fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f6a1" ++string(4) "f6fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8ff6a1" ++string(6) "8ff6fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f7a1" ++string(4) "f7fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8ff7a1" ++string(6) "8ff7fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f8a1" ++string(4) "f8fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8ff8a1" ++string(6) "8ff8fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f9a1" ++string(4) "f9fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8ff9a1" ++string(6) "8ff9fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "faa1" ++string(4) "fafe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8ffaa1" ++string(6) "8ffafe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "fba1" ++string(4) "fbfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8ffba1" ++string(6) "8ffbfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "fca1" ++string(4) "fcfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8ffca1" ++string(6) "8ffcfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "fda1" ++string(4) "fdfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8ffda1" ++string(6) "8ffdfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "fea1" ++string(4) "fefe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(0) "" ++string(6) "8ffea1" ++string(6) "8ffefe" ++string(0) "" ++-- ++string(2) "80" ++string(2) "ff" ++-- ++string(0) "" ++string(0) "" ++string(4) "8140" ++string(4) "817e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "81a1" ++string(4) "81fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8240" ++string(4) "827e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "82a1" ++string(4) "82fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8340" ++string(4) "837e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "83a1" ++string(4) "83fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8440" ++string(4) "847e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "84a1" ++string(4) "84fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8540" ++string(4) "857e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "85a1" ++string(4) "85fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8640" ++string(4) "867e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "86a1" ++string(4) "86fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8740" ++string(4) "877e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "87a1" ++string(4) "87fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8840" ++string(4) "887e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "88a1" ++string(4) "88fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8940" ++string(4) "897e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "89a1" ++string(4) "89fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8a40" ++string(4) "8a7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8aa1" ++string(4) "8afe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8b40" ++string(4) "8b7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8ba1" ++string(4) "8bfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8c40" ++string(4) "8c7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8ca1" ++string(4) "8cfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8d40" ++string(4) "8d7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8da1" ++string(4) "8dfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8e40" ++string(4) "8e7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8ea1" ++string(4) "8efe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8f40" ++string(4) "8f7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "8fa1" ++string(4) "8ffe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9040" ++string(4) "907e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "90a1" ++string(4) "90fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9140" ++string(4) "917e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "91a1" ++string(4) "91fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9240" ++string(4) "927e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "92a1" ++string(4) "92fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9340" ++string(4) "937e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "93a1" ++string(4) "93fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9440" ++string(4) "947e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "94a1" ++string(4) "94fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9540" ++string(4) "957e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "95a1" ++string(4) "95fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9640" ++string(4) "967e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "96a1" ++string(4) "96fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9740" ++string(4) "977e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "97a1" ++string(4) "97fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9840" ++string(4) "987e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "98a1" ++string(4) "98fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9940" ++string(4) "997e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "99a1" ++string(4) "99fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9a40" ++string(4) "9a7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9aa1" ++string(4) "9afe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9b40" ++string(4) "9b7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9ba1" ++string(4) "9bfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9c40" ++string(4) "9c7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9ca1" ++string(4) "9cfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9d40" ++string(4) "9d7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9da1" ++string(4) "9dfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9e40" ++string(4) "9e7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9ea1" ++string(4) "9efe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9f40" ++string(4) "9f7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "9fa1" ++string(4) "9ffe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "a040" ++string(4) "a07e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "a0a1" ++string(4) "a0fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "a140" ++string(4) "a17e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "a1a1" ++string(4) "a1fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "a240" ++string(4) "a27e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "a2a1" ++string(4) "a2fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "a340" ++string(4) "a37e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "a3a1" ++string(4) "a3fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "a440" ++string(4) "a47e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "a4a1" ++string(4) "a4fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "a540" ++string(4) "a57e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "a5a1" ++string(4) "a5fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "a640" ++string(4) "a67e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "a6a1" ++string(4) "a6fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "a740" ++string(4) "a77e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "a7a1" ++string(4) "a7fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "a840" ++string(4) "a87e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "a8a1" ++string(4) "a8fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "a940" ++string(4) "a97e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "a9a1" ++string(4) "a9fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "aa40" ++string(4) "aa7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "aaa1" ++string(4) "aafe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "ab40" ++string(4) "ab7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "aba1" ++string(4) "abfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "ac40" ++string(4) "ac7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "aca1" ++string(4) "acfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "ad40" ++string(4) "ad7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "ada1" ++string(4) "adfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "ae40" ++string(4) "ae7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "aea1" ++string(4) "aefe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "af40" ++string(4) "af7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "afa1" ++string(4) "affe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "b040" ++string(4) "b07e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "b0a1" ++string(4) "b0fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "b140" ++string(4) "b17e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "b1a1" ++string(4) "b1fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "b240" ++string(4) "b27e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "b2a1" ++string(4) "b2fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "b340" ++string(4) "b37e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "b3a1" ++string(4) "b3fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "b440" ++string(4) "b47e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "b4a1" ++string(4) "b4fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "b540" ++string(4) "b57e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "b5a1" ++string(4) "b5fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "b640" ++string(4) "b67e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "b6a1" ++string(4) "b6fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "b740" ++string(4) "b77e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "b7a1" ++string(4) "b7fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "b840" ++string(4) "b87e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "b8a1" ++string(4) "b8fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "b940" ++string(4) "b97e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "b9a1" ++string(4) "b9fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "ba40" ++string(4) "ba7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "baa1" ++string(4) "bafe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "bb40" ++string(4) "bb7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "bba1" ++string(4) "bbfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "bc40" ++string(4) "bc7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "bca1" ++string(4) "bcfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "bd40" ++string(4) "bd7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "bda1" ++string(4) "bdfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "be40" ++string(4) "be7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "bea1" ++string(4) "befe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "bf40" ++string(4) "bf7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "bfa1" ++string(4) "bffe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "c040" ++string(4) "c07e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "c0a1" ++string(4) "c0fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "c140" ++string(4) "c17e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "c1a1" ++string(4) "c1fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "c240" ++string(4) "c27e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "c2a1" ++string(4) "c2fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "c340" ++string(4) "c37e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "c3a1" ++string(4) "c3fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "c440" ++string(4) "c47e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "c4a1" ++string(4) "c4fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "c540" ++string(4) "c57e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "c5a1" ++string(4) "c5fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "c640" ++string(4) "c67e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "c6a1" ++string(4) "c6fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "c740" ++string(4) "c77e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "c7a1" ++string(4) "c7fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "c840" ++string(4) "c87e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "c8a1" ++string(4) "c8fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "c940" ++string(4) "c97e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "c9a1" ++string(4) "c9fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "ca40" ++string(4) "ca7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "caa1" ++string(4) "cafe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "cb40" ++string(4) "cb7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "cba1" ++string(4) "cbfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "cc40" ++string(4) "cc7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "cca1" ++string(4) "ccfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "cd40" ++string(4) "cd7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "cda1" ++string(4) "cdfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "ce40" ++string(4) "ce7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "cea1" ++string(4) "cefe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "cf40" ++string(4) "cf7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "cfa1" ++string(4) "cffe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "d040" ++string(4) "d07e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "d0a1" ++string(4) "d0fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "d140" ++string(4) "d17e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "d1a1" ++string(4) "d1fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "d240" ++string(4) "d27e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "d2a1" ++string(4) "d2fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "d340" ++string(4) "d37e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "d3a1" ++string(4) "d3fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "d440" ++string(4) "d47e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "d4a1" ++string(4) "d4fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "d540" ++string(4) "d57e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "d5a1" ++string(4) "d5fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "d640" ++string(4) "d67e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "d6a1" ++string(4) "d6fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "d740" ++string(4) "d77e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "d7a1" ++string(4) "d7fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "d840" ++string(4) "d87e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "d8a1" ++string(4) "d8fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "d940" ++string(4) "d97e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "d9a1" ++string(4) "d9fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "da40" ++string(4) "da7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "daa1" ++string(4) "dafe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "db40" ++string(4) "db7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "dba1" ++string(4) "dbfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "dc40" ++string(4) "dc7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "dca1" ++string(4) "dcfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "dd40" ++string(4) "dd7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "dda1" ++string(4) "ddfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "de40" ++string(4) "de7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "dea1" ++string(4) "defe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "df40" ++string(4) "df7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "dfa1" ++string(4) "dffe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e040" ++string(4) "e07e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e0a1" ++string(4) "e0fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e140" ++string(4) "e17e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e1a1" ++string(4) "e1fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e240" ++string(4) "e27e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e2a1" ++string(4) "e2fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e340" ++string(4) "e37e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e3a1" ++string(4) "e3fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e440" ++string(4) "e47e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e4a1" ++string(4) "e4fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e540" ++string(4) "e57e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e5a1" ++string(4) "e5fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e640" ++string(4) "e67e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e6a1" ++string(4) "e6fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e740" ++string(4) "e77e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e7a1" ++string(4) "e7fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e840" ++string(4) "e87e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e8a1" ++string(4) "e8fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e940" ++string(4) "e97e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "e9a1" ++string(4) "e9fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "ea40" ++string(4) "ea7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "eaa1" ++string(4) "eafe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "eb40" ++string(4) "eb7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "eba1" ++string(4) "ebfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "ec40" ++string(4) "ec7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "eca1" ++string(4) "ecfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "ed40" ++string(4) "ed7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "eda1" ++string(4) "edfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "ee40" ++string(4) "ee7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "eea1" ++string(4) "eefe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "ef40" ++string(4) "ef7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "efa1" ++string(4) "effe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f040" ++string(4) "f07e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f0a1" ++string(4) "f0fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f140" ++string(4) "f17e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f1a1" ++string(4) "f1fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f240" ++string(4) "f27e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f2a1" ++string(4) "f2fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f340" ++string(4) "f37e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f3a1" ++string(4) "f3fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f440" ++string(4) "f47e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f4a1" ++string(4) "f4fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f540" ++string(4) "f57e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f5a1" ++string(4) "f5fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f640" ++string(4) "f67e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f6a1" ++string(4) "f6fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f740" ++string(4) "f77e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f7a1" ++string(4) "f7fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f840" ++string(4) "f87e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f8a1" ++string(4) "f8fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f940" ++string(4) "f97e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "f9a1" ++string(4) "f9fe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "fa40" ++string(4) "fa7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "faa1" ++string(4) "fafe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "fb40" ++string(4) "fb7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "fba1" ++string(4) "fbfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "fc40" ++string(4) "fc7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "fca1" ++string(4) "fcfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "fd40" ++string(4) "fd7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "fda1" ++string(4) "fdfe" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "fe40" ++string(4) "fe7e" ++string(0) "" ++string(0) "" ++string(0) "" ++string(4) "fea1" ++string(4) "fefe" ++string(0) "" +diff -Nur php5-5.2.10.dfsg.1/ext/standard/tests/strings/htmlentities-utf.phpt php5-5.2.10.dfsg.1.new/ext/standard/tests/strings/htmlentities-utf.phpt +--- php5-5.2.10.dfsg.1/ext/standard/tests/strings/htmlentities-utf.phpt 2007-10-03 00:58:40.000000000 -0400 ++++ php5-5.2.10.dfsg.1.new/ext/standard/tests/strings/htmlentities-utf.phpt 2010-01-05 13:13:18.000000000 -0500 +@@ -4,8 +4,12 @@ + output_handler= + --FILE-- + +---EXPECT-- +-string(8) "266c743b" +-string(8) "266c743b" +-string(0) "" +-string(0) "" +-string(4) "d090" +-string(4) "d090" +-string(0) "" +-string(0) "" +-string(8) "d090d0b0" +-string(8) "d090d0b0" +-string(0) "" +-string(0) "" +-string(0) "" +-string(0) "" +-string(0) "" +-string(0) "" +-string(8) "2667743b" +-string(8) "2667743b" +\ No newline at end of file ++--EXPECTF-- ++%unicode|string%(8) "266c743b" ++%unicode|string%(8) "266c743b" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(4) "d090" ++%unicode|string%(4) "d090" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(8) "d090d0b0" ++%unicode|string%(8) "d090d0b0" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(4) "c3a9" ++%unicode|string%(16) "266561637574653b" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(8) "f7bfbfbf" ++%unicode|string%(8) "f7bfbfbf" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(0) "" ++%unicode|string%(0) "" --- php5-5.2.10.dfsg.1.orig/debian/patches/php5-CVE-2011-1148.patch +++ php5-5.2.10.dfsg.1/debian/patches/php5-CVE-2011-1148.patch @@ -0,0 +1,199 @@ +Subject: fix bug #54238 (use-after-free in substr_replace()) +Origin: http://svn.php.net/viewvc?view=revision&revision=310194 + +CVE-2011-1148 + +Patch differs from upstream commit in that added entry in NEWS file has +been removed to reduce patch conflicts. + +Index: ext/standard/string.c +=================================================================== +--- ext/standard/string.c (revision 310193) ++++ ext/standard/string.c (revision 310194) +@@ -2352,20 +2352,35 @@ + + zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(str), &pos_str); + while (zend_hash_get_current_data_ex(Z_ARRVAL_PP(str), (void **) &tmp_str, &pos_str) == SUCCESS) { +- convert_to_string_ex(tmp_str); ++ zval *orig_str; ++ zval dummy; ++ if(Z_TYPE_PP(tmp_str) != IS_STRING) { ++ dummy = **tmp_str; ++ orig_str = &dummy; ++ zval_copy_ctor(orig_str); ++ convert_to_string(orig_str); ++ } else { ++ orig_str = *tmp_str; ++ } + + if (Z_TYPE_PP(from) == IS_ARRAY) { + if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(from), (void **) &tmp_from, &pos_from)) { +- convert_to_long_ex(tmp_from); ++ if(Z_TYPE_PP(tmp_from) != IS_LONG) { ++ zval dummy = **tmp_from; ++ zval_copy_ctor(&dummy); ++ convert_to_long(&dummy); ++ f = Z_LVAL(dummy); ++ } else { ++ f = Z_LVAL_PP(tmp_from); ++ } + +- f = Z_LVAL_PP(tmp_from); + if (f < 0) { +- f = Z_STRLEN_PP(tmp_str) + f; ++ f = Z_STRLEN_P(orig_str) + f; + if (f < 0) { + f = 0; + } +- } else if (f > Z_STRLEN_PP(tmp_str)) { +- f = Z_STRLEN_PP(tmp_str); ++ } else if (f > Z_STRLEN_P(orig_str)) { ++ f = Z_STRLEN_P(orig_str); + } + zend_hash_move_forward_ex(Z_ARRVAL_PP(from), &pos_from); + } else { +@@ -2374,72 +2389,94 @@ + } else { + f = Z_LVAL_PP(from); + if (f < 0) { +- f = Z_STRLEN_PP(tmp_str) + f; ++ f = Z_STRLEN_P(orig_str) + f; + if (f < 0) { + f = 0; + } +- } else if (f > Z_STRLEN_PP(tmp_str)) { +- f = Z_STRLEN_PP(tmp_str); ++ } else if (f > Z_STRLEN_P(orig_str)) { ++ f = Z_STRLEN_P(orig_str); + } + } + + if (argc > 3 && Z_TYPE_PP(len) == IS_ARRAY) { + if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(len), (void **) &tmp_len, &pos_len)) { +- convert_to_long_ex(tmp_len); ++ if(Z_TYPE_PP(tmp_len) != IS_LONG) { ++ zval dummy = **tmp_len; ++ zval_copy_ctor(&dummy); ++ convert_to_long(&dummy); ++ l = Z_LVAL(dummy); ++ } else { ++ l = Z_LVAL_PP(tmp_len); ++ } + + l = Z_LVAL_PP(tmp_len); + zend_hash_move_forward_ex(Z_ARRVAL_PP(len), &pos_len); + } else { +- l = Z_STRLEN_PP(tmp_str); ++ l = Z_STRLEN_P(orig_str); + } + } else if (argc > 3) { + l = Z_LVAL_PP(len); + } else { +- l = Z_STRLEN_PP(tmp_str); ++ l = Z_STRLEN_P(orig_str); + } + + if (l < 0) { +- l = (Z_STRLEN_PP(tmp_str) - f) + l; ++ l = (Z_STRLEN_P(orig_str) - f) + l; + if (l < 0) { + l = 0; + } + } + +- if ((f + l) > Z_STRLEN_PP(tmp_str)) { +- l = Z_STRLEN_PP(tmp_str) - f; ++ if ((f + l) > Z_STRLEN_P(orig_str)) { ++ l = Z_STRLEN_P(orig_str) - f; + } + +- result_len = Z_STRLEN_PP(tmp_str) - l; ++ result_len = Z_STRLEN_P(orig_str) - l; + + if (Z_TYPE_PP(repl) == IS_ARRAY) { + if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(repl), (void **) &tmp_repl, &pos_repl)) { +- convert_to_string_ex(tmp_repl); +- result_len += Z_STRLEN_PP(tmp_repl); ++ zval *repl_str; ++ zval zrepl; ++ if(Z_TYPE_PP(tmp_repl) != IS_STRING) { ++ zrepl = **tmp_repl; ++ repl_str = &zrepl; ++ zval_copy_ctor(repl_str); ++ convert_to_string(repl_str); ++ } else { ++ repl_str = *tmp_repl; ++ } ++ ++ result_len += Z_STRLEN_P(repl_str); + zend_hash_move_forward_ex(Z_ARRVAL_PP(repl), &pos_repl); + result = emalloc(result_len + 1); + +- memcpy(result, Z_STRVAL_PP(tmp_str), f); +- memcpy((result + f), Z_STRVAL_PP(tmp_repl), Z_STRLEN_PP(tmp_repl)); +- memcpy((result + f + Z_STRLEN_PP(tmp_repl)), Z_STRVAL_PP(tmp_str) + f + l, Z_STRLEN_PP(tmp_str) - f - l); ++ memcpy(result, Z_STRVAL_P(orig_str), f); ++ memcpy((result + f), Z_STRVAL_P(repl_str), Z_STRLEN_P(repl_str)); ++ memcpy((result + f + Z_STRLEN_P(repl_str)), Z_STRVAL_P(orig_str) + f + l, Z_STRLEN_P(orig_str) - f - l); ++ if(Z_TYPE_PP(tmp_repl) != IS_STRING) { ++ zval_dtor(repl_str); ++ } + } else { + result = emalloc(result_len + 1); + +- memcpy(result, Z_STRVAL_PP(tmp_str), f); +- memcpy((result + f), Z_STRVAL_PP(tmp_str) + f + l, Z_STRLEN_PP(tmp_str) - f - l); ++ memcpy(result, Z_STRVAL_P(orig_str), f); ++ memcpy((result + f), Z_STRVAL_P(orig_str) + f + l, Z_STRLEN_P(orig_str) - f - l); + } + } else { + result_len += Z_STRLEN_PP(repl); + + result = emalloc(result_len + 1); + +- memcpy(result, Z_STRVAL_PP(tmp_str), f); ++ memcpy(result, Z_STRVAL_P(orig_str), f); + memcpy((result + f), Z_STRVAL_PP(repl), Z_STRLEN_PP(repl)); +- memcpy((result + f + Z_STRLEN_PP(repl)), Z_STRVAL_PP(tmp_str) + f + l, Z_STRLEN_PP(tmp_str) - f - l); ++ memcpy((result + f + Z_STRLEN_PP(repl)), Z_STRVAL_P(orig_str) + f + l, Z_STRLEN_P(orig_str) - f - l); + } + + result[result_len] = '\0'; + add_next_index_stringl(return_value, result, result_len, 0); +- ++ if(Z_TYPE_PP(tmp_str) != IS_STRING) { ++ zval_dtor(orig_str); ++ } + zend_hash_move_forward_ex(Z_ARRVAL_PP(str), &pos_str); + } /*while*/ + } /* if */ +Index: ext/standard/tests/strings/bug54238.phpt +=================================================================== +--- ext/standard/tests/strings/bug54238.phpt (revision 0) ++++ ext/standard/tests/strings/bug54238.phpt (revision 310194) +@@ -0,0 +1,25 @@ ++--TEST-- ++Bug #54238 (use-after-free in substr_replace()) ++--INI-- ++error_reporting=E_ALL&~E_NOTICE ++--FILE-- ++ ++--EXPECT-- ++array(1) { ++ [0]=> ++ string(9) "AArrayray" ++} ++array(1) { ++ [0]=> ++ array(2) { ++ [0]=> ++ string(1) "A" ++ [1]=> ++ string(1) "A" ++ } ++} --- php5-5.2.10.dfsg.1.orig/debian/patches/006-debian_quirks.patch +++ php5-5.2.10.dfsg.1/debian/patches/006-debian_quirks.patch @@ -0,0 +1,360 @@ +--- php.orig/configure.in ++++ php/configure.in +@@ -991,7 +991,7 @@ if test "$PHP_CLI" = "no"; then + fi + + PHP_ARG_WITH(pear, [whether to install PEAR], +-[ --with-pear=DIR Install PEAR in DIR [PREFIX/lib/php] ++[ --with-pear=DIR Install PEAR in DIR [PREFIX/lib/php5] + --without-pear Do not install PEAR], DEFAULT, yes) + + if test "$PHP_PEAR" != "no"; then +@@ -1025,7 +1025,7 @@ dnl + if test "$PHP_PEAR" = "DEFAULT" || test "$PHP_PEAR" = "yes"; then + case $PHP_LAYOUT in + GNU) PEAR_INSTALLDIR=$datadir/pear;; +- *) PEAR_INSTALLDIR=$libdir/php;; ++ *) PEAR_INSTALLDIR=$libdir/php5;; + esac + fi + +@@ -1080,12 +1080,12 @@ test "$program_suffix" = "NONE" && progr + + case $libdir in + '${exec_prefix}/lib') +- libdir=$libdir/php ++ libdir=$libdir/php5 + ;; + esac + case $datadir in + '${prefix}/share') +- datadir=$datadir/php ++ datadir=$datadir/php5 + ;; + esac + +@@ -1150,7 +1150,7 @@ EXPANDED_SYSCONFDIR=`eval echo $sysconfd + EXPANDED_DATADIR=$datadir + EXPANDED_PHP_CONFIG_FILE_PATH=`eval echo "$PHP_CONFIG_FILE_PATH"` + EXPANDED_PHP_CONFIG_FILE_SCAN_DIR=`eval echo "$PHP_CONFIG_FILE_SCAN_DIR"` +-INCLUDE_PATH=.:$EXPANDED_PEAR_INSTALLDIR ++INCLUDE_PATH=.:$EXPANDED_PEAR_INSTALLDIR:/usr/share/pear + + exec_prefix=$old_exec_prefix + libdir=$old_libdir +--- php.orig/ext/ext_skel ++++ php/ext/ext_skel +@@ -70,7 +70,7 @@ if test -d "$extname" ; then + fi + + if test -z "$skel_dir"; then +- skel_dir="skeleton" ++ skel_dir="/usr/lib/php5/skeleton" + fi + + ## convert skel_dir to full path +--- php.orig/ext/session/session.c ++++ php/ext/session/session.c +@@ -684,11 +684,11 @@ static PHP_INI_MH(OnUpdateSaveDir) /* {{ + PHP_INI_BEGIN() + STD_PHP_INI_BOOLEAN("session.bug_compat_42", "1", PHP_INI_ALL, OnUpdateBool, bug_compat, php_ps_globals, ps_globals) + STD_PHP_INI_BOOLEAN("session.bug_compat_warn", "1", PHP_INI_ALL, OnUpdateBool, bug_compat_warn, php_ps_globals, ps_globals) +- STD_PHP_INI_ENTRY("session.save_path", "", PHP_INI_ALL, OnUpdateSaveDir,save_path, php_ps_globals, ps_globals) ++ STD_PHP_INI_ENTRY("session.save_path", "/var/lib/php5", PHP_INI_ALL, OnUpdateString, save_path, php_ps_globals, ps_globals) + STD_PHP_INI_ENTRY("session.name", "PHPSESSID", PHP_INI_ALL, OnUpdateString, session_name, php_ps_globals, ps_globals) + PHP_INI_ENTRY("session.save_handler", "files", PHP_INI_ALL, OnUpdateSaveHandler) + STD_PHP_INI_BOOLEAN("session.auto_start", "0", PHP_INI_ALL, OnUpdateBool, auto_start, php_ps_globals, ps_globals) +- STD_PHP_INI_ENTRY("session.gc_probability", "1", PHP_INI_ALL, OnUpdateLong, gc_probability, php_ps_globals, ps_globals) ++ STD_PHP_INI_ENTRY("session.gc_probability", "0", PHP_INI_ALL, OnUpdateLong, gc_probability, php_ps_globals, ps_globals) + STD_PHP_INI_ENTRY("session.gc_divisor", "100", PHP_INI_ALL, OnUpdateLong, gc_divisor, php_ps_globals, ps_globals) + STD_PHP_INI_ENTRY("session.gc_maxlifetime", "1440", PHP_INI_ALL, OnUpdateLong, gc_maxlifetime, php_ps_globals, ps_globals) + PHP_INI_ENTRY("session.serialize_handler", "php", PHP_INI_ALL, OnUpdateSerializer) +--- php.orig/php.ini-dist ++++ php/php.ini-dist +@@ -471,7 +471,7 @@ default_mimetype = "text/html" + ;;;;;;;;;;;;;;;;;;;;;;;;; + + ; UNIX: "/path1:/path2" +-;include_path = ".:/php/includes" ++;include_path = ".:/usr/share/php" + ; + ; Windows: "\path1;\path2" + ;include_path = ".;c:\php\includes" +@@ -488,7 +488,7 @@ doc_root = + user_dir = + + ; Directory in which the loadable extensions (modules) reside. +-extension_dir = "./" ++; extension_dir = "./" + + ; Whether or not to enable the dl() function. The dl() function does NOT work + ; properly in multithreaded servers, such as IIS or Zeus, and is automatically +@@ -601,58 +601,6 @@ default_socket_timeout = 60 + ; extension_dir directive above. + + +-; Windows Extensions +-; Note that ODBC support is built in, so no dll is needed for it. +-; Note that many DLL files are located in the extensions/ (PHP 4) ext/ (PHP 5) +-; extension folders as well as the separate PECL DLL download (PHP 5). +-; Be sure to appropriately set the extension_dir directive. +- +-;extension=php_bz2.dll +-;extension=php_curl.dll +-;extension=php_dba.dll +-;extension=php_dbase.dll +-;extension=php_exif.dll +-;extension=php_fdf.dll +-;extension=php_gd2.dll +-;extension=php_gettext.dll +-;extension=php_gmp.dll +-;extension=php_ifx.dll +-;extension=php_imap.dll +-;extension=php_interbase.dll +-;extension=php_ldap.dll +-;extension=php_mbstring.dll +-;extension=php_mcrypt.dll +-;extension=php_mhash.dll +-;extension=php_mime_magic.dll +-;extension=php_ming.dll +-;extension=php_msql.dll +-;extension=php_mssql.dll +-;extension=php_mysql.dll +-;extension=php_mysqli.dll +-;extension=php_oci8.dll +-;extension=php_openssl.dll +-;extension=php_pdo.dll +-;extension=php_pdo_firebird.dll +-;extension=php_pdo_mssql.dll +-;extension=php_pdo_mysql.dll +-;extension=php_pdo_oci.dll +-;extension=php_pdo_oci8.dll +-;extension=php_pdo_odbc.dll +-;extension=php_pdo_pgsql.dll +-;extension=php_pdo_sqlite.dll +-;extension=php_pgsql.dll +-;extension=php_pspell.dll +-;extension=php_shmop.dll +-;extension=php_snmp.dll +-;extension=php_soap.dll +-;extension=php_sockets.dll +-;extension=php_sqlite.dll +-;extension=php_sybase_ct.dll +-;extension=php_tidy.dll +-;extension=php_xmlrpc.dll +-;extension=php_xsl.dll +-;extension=php_zip.dll +- + ;;;;;;;;;;;;;;;;;;; + ; Module Settings ; + ;;;;;;;;;;;;;;;;;;; +@@ -989,7 +937,7 @@ session.save_handler = files + ; + ; where MODE is the octal representation of the mode. Note that this + ; does not overwrite the process's umask. +-;session.save_path = "/tmp" ++;session.save_path = /var/lib/php5 + + ; Whether to use cookies. + session.use_cookies = 1 +@@ -1027,7 +975,12 @@ session.serialize_handler = php + ; e.g. 1/100 means there is a 1% chance that the GC process starts + ; on each request. + +-session.gc_probability = 1 ++; This is disabled in the Debian packages, due to the strict permissions ++; on /var/lib/php5. Instead of setting this here, see the cronjob at ++; /etc/cron.d/php5, which uses the session.gc_maxlifetime setting below. ++; php scripts using their own session.save_path should make sure garbage ++; collection is enabled by setting session.gc_probability ++;session.gc_probability = 0 + session.gc_divisor = 100 + + ; After this number of seconds, stored data will be seen as 'garbage' and +--- php.orig/php.ini-recommended ++++ php/php.ini-recommended +@@ -522,7 +522,7 @@ default_mimetype = "text/html" + ;;;;;;;;;;;;;;;;;;;;;;;;; + + ; UNIX: "/path1:/path2" +-;include_path = ".:/php/includes" ++;include_path = ".:/usr/share/php" + ; + ; Windows: "\path1;\path2" + ;include_path = ".;c:\php\includes" +@@ -539,7 +539,7 @@ doc_root = + user_dir = + + ; Directory in which the loadable extensions (modules) reside. +-extension_dir = "./" ++;extension_dir = "./" + + ; Whether or not to enable the dl() function. The dl() function does NOT work + ; properly in multithreaded servers, such as IIS or Zeus, and is automatically +@@ -652,58 +652,6 @@ default_socket_timeout = 60 + ; extension_dir directive above. + + +-; Windows Extensions +-; Note that ODBC support is built in, so no dll is needed for it. +-; Note that many DLL files are located in the extensions/ (PHP 4) ext/ (PHP 5) +-; extension folders as well as the separate PECL DLL download (PHP 5). +-; Be sure to appropriately set the extension_dir directive. +- +-;extension=php_bz2.dll +-;extension=php_curl.dll +-;extension=php_dba.dll +-;extension=php_dbase.dll +-;extension=php_exif.dll +-;extension=php_fdf.dll +-;extension=php_gd2.dll +-;extension=php_gettext.dll +-;extension=php_gmp.dll +-;extension=php_ifx.dll +-;extension=php_imap.dll +-;extension=php_interbase.dll +-;extension=php_ldap.dll +-;extension=php_mbstring.dll +-;extension=php_mcrypt.dll +-;extension=php_mhash.dll +-;extension=php_mime_magic.dll +-;extension=php_ming.dll +-;extension=php_msql.dll +-;extension=php_mssql.dll +-;extension=php_mysql.dll +-;extension=php_mysqli.dll +-;extension=php_oci8.dll +-;extension=php_openssl.dll +-;extension=php_pdo.dll +-;extension=php_pdo_firebird.dll +-;extension=php_pdo_mssql.dll +-;extension=php_pdo_mysql.dll +-;extension=php_pdo_oci.dll +-;extension=php_pdo_oci8.dll +-;extension=php_pdo_odbc.dll +-;extension=php_pdo_pgsql.dll +-;extension=php_pdo_sqlite.dll +-;extension=php_pgsql.dll +-;extension=php_pspell.dll +-;extension=php_shmop.dll +-;extension=php_snmp.dll +-;extension=php_soap.dll +-;extension=php_sockets.dll +-;extension=php_sqlite.dll +-;extension=php_sybase_ct.dll +-;extension=php_tidy.dll +-;extension=php_xmlrpc.dll +-;extension=php_xsl.dll +-;extension=php_zip.dll +- + ;;;;;;;;;;;;;;;;;;; + ; Module Settings ; + ;;;;;;;;;;;;;;;;;;; +@@ -1040,7 +988,7 @@ session.save_handler = files + ; + ; where MODE is the octal representation of the mode. Note that this + ; does not overwrite the process's umask. +-;session.save_path = "/tmp" ++;session.save_path = /var/lib/php5 + + ; Whether to use cookies. + session.use_cookies = 1 +@@ -1078,7 +1026,12 @@ session.serialize_handler = php + ; e.g. 1/100 means there is a 1% chance that the GC process starts + ; on each request. + +-session.gc_probability = 1 ++; This is disabled in the Debian packages, due to the strict permissions ++; on /var/lib/php5. Instead of setting this here, see the cronjob at ++; /etc/cron.d/php5, which uses the session.gc_maxlifetime setting below. ++; php scripts using their own session.save_path should make sure garbage ++; collection is enabled by setting session.gc_probability ++;session.gc_probability = 0 + session.gc_divisor = 1000 + + ; After this number of seconds, stored data will be seen as 'garbage' and +--- php.orig/sapi/caudium/config.m4 ++++ php/sapi/caudium/config.m4 +@@ -26,8 +26,8 @@ if test "$PHP_CAUDIUM" != "no"; then + AC_MSG_ERROR([Could not find a pike in $PHP_CAUDIUM/bin/]) + fi + if $PIKE -e 'float v; int rel;sscanf(version(), "Pike v%f release %d", v, rel);v += rel/10000.0; if(v < 7.0268) exit(1); exit(0);'; then +- PIKE_MODULE_DIR=`$PIKE --show-paths 2>&1| grep '^Module' | sed -e 's/.*: //'` +- PIKE_INCLUDE_DIR=`echo $PIKE_MODULE_DIR | sed -e 's,lib/pike/modules,include/pike,' -e 's,lib/modules,include/pike,' ` ++ PIKE_MODULE_DIR=`$PIKE --show-paths 2>&1| grep '^Master file' | sed -e 's/.*: //' -e 's/master.pike/modules/'` ++ PIKE_INCLUDE_DIR=`echo $PIKE_MODULE_DIR | sed -e 's,lib/modules,,' -e 's,modules,include,' ` + if test -z "$PIKE_INCLUDE_DIR" || test -z "$PIKE_MODULE_DIR"; then + AC_MSG_ERROR(Failed to figure out Pike module and include directories) + fi +@@ -84,7 +84,9 @@ if test "$PHP_CAUDIUM" != "no"; then + PIKE_VERSION=`$PIKE -e 'string v; int rel;sscanf(version(), "Pike v%s release %d", v, rel); write(v+"."+rel);'` + AC_DEFINE(HAVE_CAUDIUM,1,[Whether to compile with Caudium support]) + PHP_SELECT_SAPI(caudium, shared, caudium.c) +- INSTALL_IT="\$(INSTALL) -m 0755 $SAPI_SHARED $PHP_CAUDIUM/lib/$PIKE_VERSION/PHP5.so" ++ dnl FIXME: This is the ugliest hack in the world! ++ dnl INSTALL_IT="\$(mkinstalldirs) \$(INSTALL_ROOT)$PHP_CAUDIUM/lib/$PIKE_VERSION/ && \$(INSTALL) -m 0755 $SAPI_SHARED \$(INSTALL_ROOT)$PHP_CAUDIUM/lib/$PIKE_VERSION/php5.so" ++ INSTALL_IT="\$(mkinstalldirs) \$(INSTALL_ROOT)$PHP_CAUDIUM/lib/$PIKE_VERSION/ && \$(INSTALL) -m 0755 .$SAPI_SHARED \$(INSTALL_ROOT)$PHP_CAUDIUM/lib/$PIKE_VERSION/PHP5.so" + RESULT=" *** Pike binary used: $PIKE + *** Pike include dir(s) used: $PIKE_INCLUDE_DIR + *** Pike version: $PIKE_VERSION" +--- php.orig/sapi/cli/php.1.in ++++ php/sapi/cli/php.1.in +@@ -306,13 +306,14 @@ Shows configuration for extension + .B name + .SH FILES + .TP 15 +-.B php\-cli.ini ++.B /etc/php5/cli/php.ini + The configuration file for the CLI version of PHP. + .TP +-.B php.ini +-The standard configuration file will only be used when +-.B php\-cli.ini +-cannot be found. ++.B /etc/php5/cgi/php.ini ++The configuration file for the CGI version of PHP. ++.TP ++.B /etc/php5/apache2/php.ini ++The configuration file for the version of PHP that apache2 uses. + .SH EXAMPLES + .TP 5 + \fIphp -r 'echo "Hello World\\n";'\fP +--- php.orig/scripts/Makefile.frag ++++ php/scripts/Makefile.frag +@@ -3,8 +3,8 @@ + # Build environment install + # + +-phpincludedir = $(includedir)/php +-phpbuilddir = $(libdir)/build ++phpincludedir = $(includedir)/php5 ++phpbuilddir = $(prefix)/lib/php5/build + + BUILD_FILES = \ + scripts/phpize.m4 \ +--- php.orig/scripts/php-config.in ++++ php/scripts/php-config.in +@@ -5,8 +5,8 @@ prefix="@prefix@" + exec_prefix="@exec_prefix@" + version="@PHP_VERSION@" + vernum="@PHP_VERSION_ID@" +-include_dir="@includedir@/php" +-includes="-I$include_dir -I$include_dir/main -I$include_dir/TSRM -I$include_dir/Zend -I$include_dir/ext -I$include_dir/ext/date/lib" ++include_dir="@includedir@/php5" ++includes="-I$include_dir -I$include_dir/main -I$include_dir/TSRM -I$include_dir/Zend -I$include_dir/ext -I$include_dir/ext/date/lib $(getconf LFS_CFLAGS)" + ldflags="@PHP_LDFLAGS@" + libs="@EXTRA_LIBS@" + extension_dir='@EXTENSION_DIR@' +--- php.orig/scripts/phpize.in ++++ php/scripts/phpize.in +@@ -3,8 +3,8 @@ + # Variable declaration + prefix='@prefix@' + exec_prefix="`eval echo @exec_prefix@`" +-phpdir="`eval echo @libdir@`/build" +-includedir="`eval echo @includedir@`/php" ++phpdir="$prefix/lib/php5/build" ++includedir="$prefix/include/php5" + builddir="`pwd`" + SED="@SED@" + --- php5-5.2.10.dfsg.1.orig/debian/patches/001-libtool_fixes.patch +++ php5-5.2.10.dfsg.1/debian/patches/001-libtool_fixes.patch @@ -0,0 +1,24 @@ +--- php.orig/TSRM/configure.in ++++ php/TSRM/configure.in +@@ -13,9 +13,6 @@ TSRM_BASIC_CHECKS + TSRM_THREADS_CHECKS + + AM_PROG_LIBTOOL +-if test "$enable_debug" != "yes"; then +- AM_SET_LIBTOOL_VARIABLE([--silent]) +-fi + + dnl TSRM_PTHREAD + +--- php.orig/configure.in ++++ php/configure.in +@@ -1328,9 +1328,6 @@ AC_PROVIDE_IFELSE([PHP_REQUIRE_CXX], [], + ]) + AC_PROG_LIBTOOL + +-if test "$enable_debug" != "yes"; then +- PHP_SET_LIBTOOL_VARIABLE([--silent]) +-fi + + dnl libtool 1.4.3 needs this. + PHP_SET_LIBTOOL_VARIABLE([--preserve-dup-deps]) --- php5-5.2.10.dfsg.1.orig/debian/patches/gentoo/006_ext-curl-set_opt-crash.patch +++ php5-5.2.10.dfsg.1/debian/patches/gentoo/006_ext-curl-set_opt-crash.patch @@ -0,0 +1,15 @@ +006_ext-curl-set_opt-crash.patch +PHP_5_2 +http://cvs.php.net/viewvc.cgi/php-src/ext/curl/interface.c?r1=1.62.2.14.2.42&r2=1.62.2.14.2.43&diff_format=u +http://bugs.php.net/bug.php?id=47616 +Fixed bug #47616 (curl keeps crashing) +--- php.orig/ext/curl/interface.c ++++ php/ext/curl/interface.c +@@ -1626,6 +1626,7 @@ static int _php_curl_setopt(php_curl *ch + #if LIBCURL_VERSION_NUM >= 0x071101 + convert_to_string_ex(zvalue); + /* with curl 7.17.0 and later, we can use COPYPOSTFIELDS, but we have to provide size before */ ++ convert_to_string_ex(zvalue); + error = curl_easy_setopt(ch->cp, CURLOPT_POSTFIELDSIZE, Z_STRLEN_PP(zvalue)); + error = curl_easy_setopt(ch->cp, CURLOPT_COPYPOSTFIELDS, Z_STRVAL_PP(zvalue)); + #else --- php5-5.2.10.dfsg.1.orig/debian/patches/gentoo/009_ob-memory-leaks.patch +++ php5-5.2.10.dfsg.1/debian/patches/gentoo/009_ob-memory-leaks.patch @@ -0,0 +1,33 @@ +009_ob-memory-leaks.patch +PHP_5_2 +http://cvs.php.net/viewvc.cgi/php-src/main/output.c?r1=1.167.2.3.2.8&r2=1.167.2.3.2.9&diff_format=u +Fixed memory leak in ob_get_clean/ob_get_flush. + +--- php.orig/main/output.c ++++ php/main/output.c +@@ -806,10 +806,12 @@ PHP_FUNCTION(ob_end_flush) + + if (!OG(ob_nesting_level)) { + php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete and flush buffer. No buffer to delete or flush."); ++ zval_dtor(return_value); + RETURN_FALSE; + } + if (OG(ob_nesting_level) && !OG(active_ob_buffer).status && !OG(active_ob_buffer).erase) { + php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer %s.", OG(active_ob_buffer).handler_name); ++ zval_dtor(return_value); + RETURN_FALSE; + } + +@@ -828,10 +830,12 @@ PHP_FUNCTION(ob_end_clean) + + if (!OG(ob_nesting_level)) { + php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer. No buffer to delete."); ++ zval_dtor(return_value); + RETURN_FALSE; + } + if (OG(ob_nesting_level) && !OG(active_ob_buffer).status && !OG(active_ob_buffer).erase) { + php_error_docref("ref.outcontrol" TSRMLS_CC, E_NOTICE, "failed to delete buffer %s.", OG(active_ob_buffer).handler_name); ++ zval_dtor(return_value); + RETURN_FALSE; + } + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/general_functions/proc_open02.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/general_functions/proc_open02.diff @@ -0,0 +1,12 @@ +008+ bool(false) +009+ ["signaled"]=> +009- ["signaled"]=> +010- bool(false) +016+ int(1) +016- int(0) +020+ bool(false) +020- bool(true) +029+ bool(false) +029- bool(true) +035+ int(0) +035- int(15) \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/general_functions/bug44394_2.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/general_functions/bug44394_2.php @@ -0,0 +1,19 @@ +asd"; + +output_add_rewrite_var('a', 'b'); + +echo $string; + +ob_flush(); + +ob_end_clean(); + +?> --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/general_functions/proc_open02.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/general_functions/proc_open02.log @@ -0,0 +1,82 @@ + +---- EXPECTED OUTPUT +bool(true) +array(8) { + ["command"]=> + string(28) "/usr/bin/nohup /bin/sleep 50" + ["pid"]=> + int(%d) + ["running"]=> + bool(true) + ["signaled"]=> + bool(false) + ["stopped"]=> + bool(false) + ["exitcode"]=> + int(-1) + ["termsig"]=> + int(0) + ["stopsig"]=> + int(0) +} +bool(true) +array(8) { + ["command"]=> + string(28) "/usr/bin/nohup /bin/sleep 50" + ["pid"]=> + int(%d) + ["running"]=> + bool(false) + ["signaled"]=> + bool(true) + ["stopped"]=> + bool(false) + ["exitcode"]=> + int(-1) + ["termsig"]=> + int(15) + ["stopsig"]=> + int(0) +} +Done! +---- ACTUAL OUTPUT +bool(true) +array(8) { + ["command"]=> + string(28) "/usr/bin/nohup /bin/sleep 50" + ["pid"]=> + int(794) + ["running"]=> + bool(false) + ["signaled"]=> + bool(true) + ["stopped"]=> + bool(false) + ["exitcode"]=> + int(-1) + ["termsig"]=> + int(1) + ["stopsig"]=> + int(0) +} +bool(false) +array(8) { + ["command"]=> + string(28) "/usr/bin/nohup /bin/sleep 50" + ["pid"]=> + int(794) + ["running"]=> + bool(false) + ["signaled"]=> + bool(false) + ["stopped"]=> + bool(false) + ["exitcode"]=> + int(-1) + ["termsig"]=> + int(0) + ["stopsig"]=> + int(0) +} +Done! +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/general_functions/bug44394_2.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/general_functions/bug44394_2.out @@ -0,0 +1,9 @@ +Warning: session_start(): open(/var/lib/php5/sess_ed332c23481376020abb3184a1596f17, O_RDWR) failed: No such file or directory (2) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/general_functions/bug44394_2.php on line 5 + +Warning: session_start(): Cannot send session cookie - headers already sent by (output started at /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/general_functions/bug44394_2.php:5) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/general_functions/bug44394_2.php on line 5 + +Warning: session_start(): Cannot send session cache limiter - headers already sent (output started at /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/general_functions/bug44394_2.php:5) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/general_functions/bug44394_2.php on line 5 +asd +Warning: Unknown: open(/var/lib/php5/sess_ed332c23481376020abb3184a1596f17, O_RDWR) failed: No such file or directory (2) in Unknown on line 0 + +Warning: Unknown: Failed to write session data (files). Please verify that the current setting of session.save_path is correct (/var/lib/php5) in Unknown on line 0 \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/general_functions/proc_open02.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/general_functions/proc_open02.out @@ -0,0 +1,39 @@ +bool(true) +array(8) { + ["command"]=> + string(28) "/usr/bin/nohup /bin/sleep 50" + ["pid"]=> + int(794) + ["running"]=> + bool(false) + ["signaled"]=> + bool(true) + ["stopped"]=> + bool(false) + ["exitcode"]=> + int(-1) + ["termsig"]=> + int(1) + ["stopsig"]=> + int(0) +} +bool(false) +array(8) { + ["command"]=> + string(28) "/usr/bin/nohup /bin/sleep 50" + ["pid"]=> + int(794) + ["running"]=> + bool(false) + ["signaled"]=> + bool(false) + ["stopped"]=> + bool(false) + ["exitcode"]=> + int(-1) + ["termsig"]=> + int(0) + ["stopsig"]=> + int(0) +} +Done! \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/general_functions/bug44394_2.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/general_functions/bug44394_2.diff @@ -0,0 +1,8 @@ +001+ Warning: session_start(): open(/var/lib/php5/sess_ed332c23481376020abb3184a1596f17, O_RDWR) failed: No such file or directory (2) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/general_functions/bug44394_2.php on line 5 +002+ +003+ Warning: session_start(): Cannot send session cookie - headers already sent by (output started at /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/general_functions/bug44394_2.php:5) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/general_functions/bug44394_2.php on line 5 +004+ +005+ Warning: session_start(): Cannot send session cache limiter - headers already sent (output started at /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/general_functions/bug44394_2.php:5) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/general_functions/bug44394_2.php on line 5 +007+ Warning: Unknown: open(/var/lib/php5/sess_ed332c23481376020abb3184a1596f17, O_RDWR) failed: No such file or directory (2) in Unknown on line 0 +008+ +009+ Warning: Unknown: Failed to write session data (files). Please verify that the current setting of session.save_path is correct (/var/lib/php5) in Unknown on line 0 \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/general_functions/bug44394_2.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/general_functions/bug44394_2.exp @@ -0,0 +1 @@ +asd \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/general_functions/bug44394_2.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/general_functions/bug44394_2.log @@ -0,0 +1,14 @@ + +---- EXPECTED OUTPUT +asd +---- ACTUAL OUTPUT +Warning: session_start(): open(/var/lib/php5/sess_ed332c23481376020abb3184a1596f17, O_RDWR) failed: No such file or directory (2) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/general_functions/bug44394_2.php on line 5 + +Warning: session_start(): Cannot send session cookie - headers already sent by (output started at /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/general_functions/bug44394_2.php:5) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/general_functions/bug44394_2.php on line 5 + +Warning: session_start(): Cannot send session cache limiter - headers already sent (output started at /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/general_functions/bug44394_2.php:5) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/general_functions/bug44394_2.php on line 5 +asd +Warning: Unknown: open(/var/lib/php5/sess_ed332c23481376020abb3184a1596f17, O_RDWR) failed: No such file or directory (2) in Unknown on line 0 + +Warning: Unknown: Failed to write session data (files). Please verify that the current setting of session.save_path is correct (/var/lib/php5) in Unknown on line 0 +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/general_functions/proc_open02.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/general_functions/proc_open02.exp @@ -0,0 +1,39 @@ +bool(true) +array(8) { + ["command"]=> + string(28) "/usr/bin/nohup /bin/sleep 50" + ["pid"]=> + int(%d) + ["running"]=> + bool(true) + ["signaled"]=> + bool(false) + ["stopped"]=> + bool(false) + ["exitcode"]=> + int(-1) + ["termsig"]=> + int(0) + ["stopsig"]=> + int(0) +} +bool(true) +array(8) { + ["command"]=> + string(28) "/usr/bin/nohup /bin/sleep 50" + ["pid"]=> + int(%d) + ["running"]=> + bool(false) + ["signaled"]=> + bool(true) + ["stopped"]=> + bool(false) + ["exitcode"]=> + int(-1) + ["termsig"]=> + int(15) + ["stopsig"]=> + int(0) +} +Done! \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/general_functions/proc_open02.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/general_functions/proc_open02.php @@ -0,0 +1,24 @@ + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/dir/readdir_variation7.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/dir/readdir_variation7.exp @@ -0,0 +1,6 @@ +*** Testing readdir() : usage variations *** +resource(%d) of type (stream) + +Warning: readdir(): %d is not a valid Directory resource in %s on line %d +bool(false) +===DONE=== \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/dir/closedir_variation3.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/dir/closedir_variation3.diff @@ -0,0 +1,8 @@ +007+ NULL +008- Warning: closedir(): %d is not a valid Directory resource in %s on line %d +009- bool(false) +010- +011- -- Check file pointer: -- +012- resource(%d) of type (stream) +009+ -- Check file pointer: -- +010+ resource(5) of type (Unknown) \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/dir/rewinddir_variation3.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/dir/rewinddir_variation3.exp @@ -0,0 +1,11 @@ +*** Testing rewinddir() : usage variations *** + +-- Open a file using fopen -- +resource(%d) of type (stream) + +Warning: rewinddir(): %d is not a valid Directory resource in %s on line %d +bool(false) + +-- Check if rewinddir() has repositioned the file pointer -- +rewinddir() does not work on file pointers +===DONE=== \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/dir/closedir_variation3.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/dir/closedir_variation3.out @@ -0,0 +1,11 @@ +*** Testing closedir() : usage variations *** + +-- Open a file using fopen() -- +resource(5) of type (stream) + +-- Try to close the file pointer using closedir() -- +NULL + +-- Check file pointer: -- +resource(5) of type (Unknown) +===DONE=== \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/dir/readdir_variation7.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/dir/readdir_variation7.php @@ -0,0 +1,26 @@ + +===DONE=== --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/dir/rewinddir_variation3.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/dir/rewinddir_variation3.diff @@ -0,0 +1,8 @@ +005+ NULL +006- Warning: rewinddir(): %d is not a valid Directory resource in %s on line %d +007- bool(false) +008- +009- -- Check if rewinddir() has repositioned the file pointer -- +010- rewinddir() does not work on file pointers +007+ -- Check if rewinddir() has repositioned the file pointer -- +008+ rewinddir() works on file pointers \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/dir/rewinddir_variation3.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/dir/rewinddir_variation3.out @@ -0,0 +1,9 @@ +*** Testing rewinddir() : usage variations *** + +-- Open a file using fopen -- +resource(5) of type (stream) +NULL + +-- Check if rewinddir() has repositioned the file pointer -- +rewinddir() works on file pointers +===DONE=== \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/dir/closedir_variation3.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/dir/closedir_variation3.exp @@ -0,0 +1,13 @@ +*** Testing closedir() : usage variations *** + +-- Open a file using fopen() -- +resource(%d) of type (stream) + +-- Try to close the file pointer using closedir() -- + +Warning: closedir(): %d is not a valid Directory resource in %s on line %d +bool(false) + +-- Check file pointer: -- +resource(%d) of type (stream) +===DONE=== \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/dir/readdir_variation7.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/dir/readdir_variation7.diff @@ -0,0 +1,2 @@ +003- +004- Warning: readdir(): %d is not a valid Directory resource in %s on line %d \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/dir/closedir_variation3.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/dir/closedir_variation3.log @@ -0,0 +1,28 @@ + +---- EXPECTED OUTPUT +*** Testing closedir() : usage variations *** + +-- Open a file using fopen() -- +resource(%d) of type (stream) + +-- Try to close the file pointer using closedir() -- + +Warning: closedir(): %d is not a valid Directory resource in %s on line %d +bool(false) + +-- Check file pointer: -- +resource(%d) of type (stream) +===DONE=== +---- ACTUAL OUTPUT +*** Testing closedir() : usage variations *** + +-- Open a file using fopen() -- +resource(5) of type (stream) + +-- Try to close the file pointer using closedir() -- +NULL + +-- Check file pointer: -- +resource(5) of type (Unknown) +===DONE=== +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/dir/readdir_variation7.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/dir/readdir_variation7.out @@ -0,0 +1,4 @@ +*** Testing readdir() : usage variations *** +resource(5) of type (stream) +bool(false) +===DONE=== \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/dir/readdir_variation7.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/dir/readdir_variation7.log @@ -0,0 +1,14 @@ + +---- EXPECTED OUTPUT +*** Testing readdir() : usage variations *** +resource(%d) of type (stream) + +Warning: readdir(): %d is not a valid Directory resource in %s on line %d +bool(false) +===DONE=== +---- ACTUAL OUTPUT +*** Testing readdir() : usage variations *** +resource(5) of type (stream) +bool(false) +===DONE=== +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/dir/rewinddir_variation3.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/dir/rewinddir_variation3.log @@ -0,0 +1,24 @@ + +---- EXPECTED OUTPUT +*** Testing rewinddir() : usage variations *** + +-- Open a file using fopen -- +resource(%d) of type (stream) + +Warning: rewinddir(): %d is not a valid Directory resource in %s on line %d +bool(false) + +-- Check if rewinddir() has repositioned the file pointer -- +rewinddir() does not work on file pointers +===DONE=== +---- ACTUAL OUTPUT +*** Testing rewinddir() : usage variations *** + +-- Open a file using fopen -- +resource(5) of type (stream) +NULL + +-- Check if rewinddir() has repositioned the file pointer -- +rewinddir() works on file pointers +===DONE=== +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/dir/rewinddir_variation3.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/dir/rewinddir_variation3.php @@ -0,0 +1,28 @@ + +===DONE=== --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/dir/closedir_variation3.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/dir/closedir_variation3.php @@ -0,0 +1,27 @@ + +===DONE=== --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/array/array_slice_variation3.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/array/array_slice_variation3.out @@ -0,0 +1,128 @@ +*** Testing array_slice() : usage variations *** + +-- Iteration 1 -- +array(0) { +} + +-- Iteration 2 -- +array(1) { + ["three"]=> + int(3) +} + +-- Iteration 3 -- +array(2) { + ["three"]=> + int(3) + [0]=> + int(4) +} + +-- Iteration 4 -- +array(0) { +} + +-- Iteration 5 -- +array(2) { + ["three"]=> + int(3) + [0]=> + int(4) +} + +-- Iteration 6 -- +array(0) { +} + +-- Iteration 7 -- +array(2) { + ["three"]=> + int(3) + [0]=> + int(4) +} + +-- Iteration 8 -- +array(0) { +} + +-- Iteration 9 -- +array(0) { +} + +-- Iteration 10 -- +array(2) { + ["three"]=> + int(3) + [0]=> + int(4) +} + +-- Iteration 11 -- +array(2) { + ["three"]=> + int(3) + [0]=> + int(4) +} + +-- Iteration 12 -- +array(1) { + ["three"]=> + int(3) +} + +-- Iteration 13 -- +array(0) { +} + +-- Iteration 14 -- +array(1) { + ["three"]=> + int(3) +} + +-- Iteration 15 -- +array(0) { +} + +-- Iteration 16 -- +array(0) { +} + +-- Iteration 17 -- +array(0) { +} + +-- Iteration 18 -- +array(0) { +} + +-- Iteration 19 -- +array(0) { +} + +-- Iteration 20 -- +array(0) { +} + +-- Iteration 21 -- +array(0) { +} + +-- Iteration 22 -- +array(2) { + ["three"]=> + int(3) + [0]=> + int(4) +} + +-- Iteration 23 -- +array(2) { + ["three"]=> + int(3) + [0]=> + int(4) +} +Done \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/array/array_slice_variation6.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/array/array_slice_variation6.out @@ -0,0 +1,110 @@ +*** Testing array_slice() : usage variations *** + +-- $length is -6 -- +array(0) { +} + +-- $length is -5 -- +array(0) { +} + +-- $length is -4 -- +array(0) { +} + +-- $length is -3 -- +array(1) { + [0]=> + string(3) "two" +} + +-- $length is -2 -- +array(2) { + [0]=> + string(3) "two" + [1]=> + string(5) "three" +} + +-- $length is -1 -- +array(3) { + [0]=> + string(3) "two" + [1]=> + string(5) "three" + [2]=> + string(4) "nine" +} + +-- $length is 0 -- +array(0) { +} + +-- $length is 1 -- +array(1) { + [0]=> + string(3) "two" +} + +-- $length is 2 -- +array(2) { + [0]=> + string(3) "two" + [1]=> + string(5) "three" +} + +-- $length is 3 -- +array(3) { + [0]=> + string(3) "two" + [1]=> + string(5) "three" + [2]=> + string(4) "nine" +} + +-- $length is 4 -- +array(4) { + [0]=> + string(3) "two" + [1]=> + string(5) "three" + [2]=> + string(4) "nine" + ["ten"]=> + int(10) +} + +-- $length is 5 -- +array(4) { + [0]=> + string(3) "two" + [1]=> + string(5) "three" + [2]=> + string(4) "nine" + ["ten"]=> + int(10) +} + +-- $length is 6 -- +array(4) { + [0]=> + string(3) "two" + [1]=> + string(5) "three" + [2]=> + string(4) "nine" + ["ten"]=> + int(10) +} + +-- $length is maximum integer value -- +array(0) { +} + +-- $length is minimum integer value -- +array(0) { +} +Done \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/array/array_slice_variation6.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/array/array_slice_variation6.php @@ -0,0 +1,28 @@ + 1, 2 => 'two', 'three', 9 => 'nine', 'ten' => 10); +$offset = 1; + +for ($i = -6; $i <= 6; $i++) { + echo "\n-- \$length is $i --\n"; + var_dump(array_slice($input, $offset, $i)); +} +echo "\n-- \$length is maximum integer value --\n"; +var_dump(array_slice($input, $offset, PHP_INT_MAX)); + +echo "\n-- \$length is minimum integer value --\n"; +var_dump(array_slice($input, $offset, -PHP_INT_MAX)); + +echo "Done"; +?> + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/array/array_slice_variation6.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/array/array_slice_variation6.exp @@ -0,0 +1,118 @@ +*** Testing array_slice() : usage variations *** + +-- $length is -6 -- +array(0) { +} + +-- $length is -5 -- +array(0) { +} + +-- $length is -4 -- +array(0) { +} + +-- $length is -3 -- +array(1) { + [0]=> + string(3) "two" +} + +-- $length is -2 -- +array(2) { + [0]=> + string(3) "two" + [1]=> + string(5) "three" +} + +-- $length is -1 -- +array(3) { + [0]=> + string(3) "two" + [1]=> + string(5) "three" + [2]=> + string(4) "nine" +} + +-- $length is 0 -- +array(0) { +} + +-- $length is 1 -- +array(1) { + [0]=> + string(3) "two" +} + +-- $length is 2 -- +array(2) { + [0]=> + string(3) "two" + [1]=> + string(5) "three" +} + +-- $length is 3 -- +array(3) { + [0]=> + string(3) "two" + [1]=> + string(5) "three" + [2]=> + string(4) "nine" +} + +-- $length is 4 -- +array(4) { + [0]=> + string(3) "two" + [1]=> + string(5) "three" + [2]=> + string(4) "nine" + ["ten"]=> + int(10) +} + +-- $length is 5 -- +array(4) { + [0]=> + string(3) "two" + [1]=> + string(5) "three" + [2]=> + string(4) "nine" + ["ten"]=> + int(10) +} + +-- $length is 6 -- +array(4) { + [0]=> + string(3) "two" + [1]=> + string(5) "three" + [2]=> + string(4) "nine" + ["ten"]=> + int(10) +} + +-- $length is maximum integer value -- +array(4) { + [0]=> + string(3) "two" + [1]=> + string(5) "three" + [2]=> + string(4) "nine" + ["ten"]=> + int(10) +} + +-- $length is minimum integer value -- +array(0) { +} +Done \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/array/array_slice_variation6.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/array/array_slice_variation6.diff @@ -0,0 +1,18 @@ +104+ array(0) { +105+ } +106+ +107+ -- $length is minimum integer value -- +108+ array(0) { +104- array(4) { +105- [0]=> +106- string(3) "two" +107- [1]=> +108- string(5) "three" +109- [2]=> +110- string(4) "nine" +111- ["ten"]=> +112- int(10) +114- +115- -- $length is minimum integer value -- +116- array(0) { +117- } \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/array/array_slice_variation6.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/array/array_slice_variation6.log @@ -0,0 +1,232 @@ + +---- EXPECTED OUTPUT +*** Testing array_slice() : usage variations *** + +-- $length is -6 -- +array(0) { +} + +-- $length is -5 -- +array(0) { +} + +-- $length is -4 -- +array(0) { +} + +-- $length is -3 -- +array(1) { + [0]=> + string(3) "two" +} + +-- $length is -2 -- +array(2) { + [0]=> + string(3) "two" + [1]=> + string(5) "three" +} + +-- $length is -1 -- +array(3) { + [0]=> + string(3) "two" + [1]=> + string(5) "three" + [2]=> + string(4) "nine" +} + +-- $length is 0 -- +array(0) { +} + +-- $length is 1 -- +array(1) { + [0]=> + string(3) "two" +} + +-- $length is 2 -- +array(2) { + [0]=> + string(3) "two" + [1]=> + string(5) "three" +} + +-- $length is 3 -- +array(3) { + [0]=> + string(3) "two" + [1]=> + string(5) "three" + [2]=> + string(4) "nine" +} + +-- $length is 4 -- +array(4) { + [0]=> + string(3) "two" + [1]=> + string(5) "three" + [2]=> + string(4) "nine" + ["ten"]=> + int(10) +} + +-- $length is 5 -- +array(4) { + [0]=> + string(3) "two" + [1]=> + string(5) "three" + [2]=> + string(4) "nine" + ["ten"]=> + int(10) +} + +-- $length is 6 -- +array(4) { + [0]=> + string(3) "two" + [1]=> + string(5) "three" + [2]=> + string(4) "nine" + ["ten"]=> + int(10) +} + +-- $length is maximum integer value -- +array(4) { + [0]=> + string(3) "two" + [1]=> + string(5) "three" + [2]=> + string(4) "nine" + ["ten"]=> + int(10) +} + +-- $length is minimum integer value -- +array(0) { +} +Done +---- ACTUAL OUTPUT +*** Testing array_slice() : usage variations *** + +-- $length is -6 -- +array(0) { +} + +-- $length is -5 -- +array(0) { +} + +-- $length is -4 -- +array(0) { +} + +-- $length is -3 -- +array(1) { + [0]=> + string(3) "two" +} + +-- $length is -2 -- +array(2) { + [0]=> + string(3) "two" + [1]=> + string(5) "three" +} + +-- $length is -1 -- +array(3) { + [0]=> + string(3) "two" + [1]=> + string(5) "three" + [2]=> + string(4) "nine" +} + +-- $length is 0 -- +array(0) { +} + +-- $length is 1 -- +array(1) { + [0]=> + string(3) "two" +} + +-- $length is 2 -- +array(2) { + [0]=> + string(3) "two" + [1]=> + string(5) "three" +} + +-- $length is 3 -- +array(3) { + [0]=> + string(3) "two" + [1]=> + string(5) "three" + [2]=> + string(4) "nine" +} + +-- $length is 4 -- +array(4) { + [0]=> + string(3) "two" + [1]=> + string(5) "three" + [2]=> + string(4) "nine" + ["ten"]=> + int(10) +} + +-- $length is 5 -- +array(4) { + [0]=> + string(3) "two" + [1]=> + string(5) "three" + [2]=> + string(4) "nine" + ["ten"]=> + int(10) +} + +-- $length is 6 -- +array(4) { + [0]=> + string(3) "two" + [1]=> + string(5) "three" + [2]=> + string(4) "nine" + ["ten"]=> + int(10) +} + +-- $length is maximum integer value -- +array(0) { +} + +-- $length is minimum integer value -- +array(0) { +} +Done +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/array/array_slice_variation3.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/array/array_slice_variation3.diff @@ -0,0 +1,6 @@ +038+ array(2) { +039+ ["three"]=> +040+ int(3) +041+ [0]=> +042+ int(4) +038- array(0) { \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/array/array_slice_variation2.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/array/array_slice_variation2.exp @@ -0,0 +1,214 @@ +*** Testing array_slice() : usage variations *** + +-- Iteration 1 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 2 -- +array(3) { + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 3 -- +array(0) { +} + +-- Iteration 4 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 5 -- +array(0) { +} + +-- Iteration 6 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 7 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 8 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 9 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 10 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 11 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 12 -- +array(3) { + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 13 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 14 -- +array(3) { + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 15 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 16 -- + +Warning: array_slice() expects parameter 2 to be long, string given in %s on line %d +NULL + +-- Iteration 17 -- + +Warning: array_slice() expects parameter 2 to be long, string given in %s on line %d +NULL + +-- Iteration 18 -- + +Warning: array_slice() expects parameter 2 to be long, array given in %s on line %d +NULL + +-- Iteration 19 -- + +Warning: array_slice() expects parameter 2 to be long, string given in %s on line %d +NULL + +-- Iteration 20 -- + +Warning: array_slice() expects parameter 2 to be long, string given in %s on line %d +NULL + +-- Iteration 21 -- + +Warning: array_slice() expects parameter 2 to be long, string given in %s on line %d +NULL + +-- Iteration 22 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 23 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} +Done \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/array/array_slice_variation3.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/array/array_slice_variation3.exp @@ -0,0 +1,124 @@ +*** Testing array_slice() : usage variations *** + +-- Iteration 1 -- +array(0) { +} + +-- Iteration 2 -- +array(1) { + ["three"]=> + int(3) +} + +-- Iteration 3 -- +array(2) { + ["three"]=> + int(3) + [0]=> + int(4) +} + +-- Iteration 4 -- +array(0) { +} + +-- Iteration 5 -- +array(2) { + ["three"]=> + int(3) + [0]=> + int(4) +} + +-- Iteration 6 -- +array(0) { +} + +-- Iteration 7 -- +array(0) { +} + +-- Iteration 8 -- +array(0) { +} + +-- Iteration 9 -- +array(0) { +} + +-- Iteration 10 -- +array(2) { + ["three"]=> + int(3) + [0]=> + int(4) +} + +-- Iteration 11 -- +array(2) { + ["three"]=> + int(3) + [0]=> + int(4) +} + +-- Iteration 12 -- +array(1) { + ["three"]=> + int(3) +} + +-- Iteration 13 -- +array(0) { +} + +-- Iteration 14 -- +array(1) { + ["three"]=> + int(3) +} + +-- Iteration 15 -- +array(0) { +} + +-- Iteration 16 -- +array(0) { +} + +-- Iteration 17 -- +array(0) { +} + +-- Iteration 18 -- +array(0) { +} + +-- Iteration 19 -- +array(0) { +} + +-- Iteration 20 -- +array(0) { +} + +-- Iteration 21 -- +array(0) { +} + +-- Iteration 22 -- +array(2) { + ["three"]=> + int(3) + [0]=> + int(4) +} + +-- Iteration 23 -- +array(2) { + ["three"]=> + int(3) + [0]=> + int(4) +} +Done \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/array/array_slice_variation3.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/array/array_slice_variation3.log @@ -0,0 +1,256 @@ + +---- EXPECTED OUTPUT +*** Testing array_slice() : usage variations *** + +-- Iteration 1 -- +array(0) { +} + +-- Iteration 2 -- +array(1) { + ["three"]=> + int(3) +} + +-- Iteration 3 -- +array(2) { + ["three"]=> + int(3) + [0]=> + int(4) +} + +-- Iteration 4 -- +array(0) { +} + +-- Iteration 5 -- +array(2) { + ["three"]=> + int(3) + [0]=> + int(4) +} + +-- Iteration 6 -- +array(0) { +} + +-- Iteration 7 -- +array(0) { +} + +-- Iteration 8 -- +array(0) { +} + +-- Iteration 9 -- +array(0) { +} + +-- Iteration 10 -- +array(2) { + ["three"]=> + int(3) + [0]=> + int(4) +} + +-- Iteration 11 -- +array(2) { + ["three"]=> + int(3) + [0]=> + int(4) +} + +-- Iteration 12 -- +array(1) { + ["three"]=> + int(3) +} + +-- Iteration 13 -- +array(0) { +} + +-- Iteration 14 -- +array(1) { + ["three"]=> + int(3) +} + +-- Iteration 15 -- +array(0) { +} + +-- Iteration 16 -- +array(0) { +} + +-- Iteration 17 -- +array(0) { +} + +-- Iteration 18 -- +array(0) { +} + +-- Iteration 19 -- +array(0) { +} + +-- Iteration 20 -- +array(0) { +} + +-- Iteration 21 -- +array(0) { +} + +-- Iteration 22 -- +array(2) { + ["three"]=> + int(3) + [0]=> + int(4) +} + +-- Iteration 23 -- +array(2) { + ["three"]=> + int(3) + [0]=> + int(4) +} +Done +---- ACTUAL OUTPUT +*** Testing array_slice() : usage variations *** + +-- Iteration 1 -- +array(0) { +} + +-- Iteration 2 -- +array(1) { + ["three"]=> + int(3) +} + +-- Iteration 3 -- +array(2) { + ["three"]=> + int(3) + [0]=> + int(4) +} + +-- Iteration 4 -- +array(0) { +} + +-- Iteration 5 -- +array(2) { + ["three"]=> + int(3) + [0]=> + int(4) +} + +-- Iteration 6 -- +array(0) { +} + +-- Iteration 7 -- +array(2) { + ["three"]=> + int(3) + [0]=> + int(4) +} + +-- Iteration 8 -- +array(0) { +} + +-- Iteration 9 -- +array(0) { +} + +-- Iteration 10 -- +array(2) { + ["three"]=> + int(3) + [0]=> + int(4) +} + +-- Iteration 11 -- +array(2) { + ["three"]=> + int(3) + [0]=> + int(4) +} + +-- Iteration 12 -- +array(1) { + ["three"]=> + int(3) +} + +-- Iteration 13 -- +array(0) { +} + +-- Iteration 14 -- +array(1) { + ["three"]=> + int(3) +} + +-- Iteration 15 -- +array(0) { +} + +-- Iteration 16 -- +array(0) { +} + +-- Iteration 17 -- +array(0) { +} + +-- Iteration 18 -- +array(0) { +} + +-- Iteration 19 -- +array(0) { +} + +-- Iteration 20 -- +array(0) { +} + +-- Iteration 21 -- +array(0) { +} + +-- Iteration 22 -- +array(2) { + ["three"]=> + int(3) + [0]=> + int(4) +} + +-- Iteration 23 -- +array(2) { + ["three"]=> + int(3) + [0]=> + int(4) +} +Done +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/array/array_slice_variation2.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/array/array_slice_variation2.php @@ -0,0 +1,91 @@ + 1, 2, 'three' => 3, 4); + +//get an unset variable +$unset_var = 10; +unset ($unset_var); + +// get a class +class classA +{ + public function __toString() { + return "Class A object"; + } +} + +// heredoc string +$heredoc = << + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/array/array_slice_variation2.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/array/array_slice_variation2.out @@ -0,0 +1,206 @@ +*** Testing array_slice() : usage variations *** + +-- Iteration 1 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 2 -- +array(3) { + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 3 -- +array(0) { +} + +-- Iteration 4 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 5 -- +array(0) { +} + +-- Iteration 6 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 7 -- +array(0) { +} + +-- Iteration 8 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 9 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 10 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 11 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 12 -- +array(3) { + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 13 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 14 -- +array(3) { + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 15 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 16 -- + +Warning: array_slice() expects parameter 2 to be long, string given in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/array/array_slice_variation2.php on line 83 +NULL + +-- Iteration 17 -- + +Warning: array_slice() expects parameter 2 to be long, string given in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/array/array_slice_variation2.php on line 83 +NULL + +-- Iteration 18 -- + +Warning: array_slice() expects parameter 2 to be long, array given in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/array/array_slice_variation2.php on line 83 +NULL + +-- Iteration 19 -- + +Warning: array_slice() expects parameter 2 to be long, string given in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/array/array_slice_variation2.php on line 83 +NULL + +-- Iteration 20 -- + +Warning: array_slice() expects parameter 2 to be long, string given in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/array/array_slice_variation2.php on line 83 +NULL + +-- Iteration 21 -- + +Warning: array_slice() expects parameter 2 to be long, string given in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/array/array_slice_variation2.php on line 83 +NULL + +-- Iteration 22 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 23 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} +Done \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/array/array_slice_variation2.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/array/array_slice_variation2.diff @@ -0,0 +1,134 @@ +058+ array(0) { +059+ } +060+ +061+ -- Iteration 8 -- +069- -- Iteration 8 -- +073+ -- Iteration 9 -- +081- -- Iteration 9 -- +085+ -- Iteration 10 -- +093- -- Iteration 10 -- +097+ -- Iteration 11 -- +105- -- Iteration 11 -- +109+ -- Iteration 12 -- +110+ array(3) { +111+ [0]=> +112+ int(2) +113+ ["three"]=> +114+ int(3) +115+ [1]=> +116+ int(4) +117+ } +118+ +119+ -- Iteration 13 -- +117- -- Iteration 12 -- +127- -- Iteration 13 -- +131+ -- Iteration 14 -- +139- -- Iteration 14 -- +140- array(3) { +141- [0]=> +142- int(2) +143- ["three"]=> +144- int(3) +145- [1]=> +146- int(4) +147- } +148- +149- -- Iteration 15 -- +141+ -- Iteration 15 -- +153+ -- Iteration 16 -- +154+ +155+ Warning: array_slice() expects parameter 2 to be long, string given in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/array/array_slice_variation2.php on line 83 +156+ NULL +157+ +158+ -- Iteration 17 -- +159+ +160+ Warning: array_slice() expects parameter 2 to be long, string given in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/array/array_slice_variation2.php on line 83 +161+ NULL +162+ +163+ -- Iteration 18 -- +164+ +165+ Warning: array_slice() expects parameter 2 to be long, array given in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/array/array_slice_variation2.php on line 83 +166+ NULL +167+ +168+ -- Iteration 19 -- +169+ +170+ Warning: array_slice() expects parameter 2 to be long, string given in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/array/array_slice_variation2.php on line 83 +171+ NULL +172+ +173+ -- Iteration 20 -- +174+ +175+ Warning: array_slice() expects parameter 2 to be long, string given in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/array/array_slice_variation2.php on line 83 +176+ NULL +177+ +178+ -- Iteration 21 -- +179+ +180+ Warning: array_slice() expects parameter 2 to be long, string given in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/array/array_slice_variation2.php on line 83 +181+ NULL +182+ +183+ -- Iteration 22 -- +161- -- Iteration 16 -- +162- +163- Warning: array_slice() expects parameter 2 to be long, string given in %s on line %d +164- NULL +165- +166- -- Iteration 17 -- +167- +168- Warning: array_slice() expects parameter 2 to be long, string given in %s on line %d +169- NULL +170- +171- -- Iteration 18 -- +172- +195+ -- Iteration 23 -- +196+ array(4) { +197+ ["one"]=> +198+ int(1) +199+ [0]=> +200+ int(2) +201+ ["three"]=> +202+ int(3) +203+ [1]=> +204+ int(4) +205+ } +206+ Done +173- Warning: array_slice() expects parameter 2 to be long, array given in %s on line %d +174- NULL +175- +176- -- Iteration 19 -- +177- +178- Warning: array_slice() expects parameter 2 to be long, string given in %s on line %d +179- NULL +180- +181- -- Iteration 20 -- +182- +183- Warning: array_slice() expects parameter 2 to be long, string given in %s on line %d +184- NULL +185- +186- -- Iteration 21 -- +187- +188- Warning: array_slice() expects parameter 2 to be long, string given in %s on line %d +189- NULL +190- +191- -- Iteration 22 -- +192- array(4) { +193- ["one"]=> +194- int(1) +195- [0]=> +196- int(2) +197- ["three"]=> +198- int(3) +199- [1]=> +200- int(4) +201- } +202- +203- -- Iteration 23 -- +204- array(4) { +205- ["one"]=> +206- int(1) +207- [0]=> +208- int(2) +209- ["three"]=> +210- int(3) +211- [1]=> +212- int(4) +213- } +214- Done \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/array/array_slice_variation3.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/array/array_slice_variation3.php @@ -0,0 +1,79 @@ + 1, 2, 'three' => 3, 4); +$offset = 2; + +//get an unset variable +$unset_var = 10; +unset ($unset_var); + +// heredoc string +$heredoc = << + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/array/array_slice_variation2.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/array/array_slice_variation2.log @@ -0,0 +1,424 @@ + +---- EXPECTED OUTPUT +*** Testing array_slice() : usage variations *** + +-- Iteration 1 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 2 -- +array(3) { + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 3 -- +array(0) { +} + +-- Iteration 4 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 5 -- +array(0) { +} + +-- Iteration 6 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 7 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 8 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 9 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 10 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 11 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 12 -- +array(3) { + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 13 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 14 -- +array(3) { + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 15 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 16 -- + +Warning: array_slice() expects parameter 2 to be long, string given in %s on line %d +NULL + +-- Iteration 17 -- + +Warning: array_slice() expects parameter 2 to be long, string given in %s on line %d +NULL + +-- Iteration 18 -- + +Warning: array_slice() expects parameter 2 to be long, array given in %s on line %d +NULL + +-- Iteration 19 -- + +Warning: array_slice() expects parameter 2 to be long, string given in %s on line %d +NULL + +-- Iteration 20 -- + +Warning: array_slice() expects parameter 2 to be long, string given in %s on line %d +NULL + +-- Iteration 21 -- + +Warning: array_slice() expects parameter 2 to be long, string given in %s on line %d +NULL + +-- Iteration 22 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 23 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} +Done +---- ACTUAL OUTPUT +*** Testing array_slice() : usage variations *** + +-- Iteration 1 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 2 -- +array(3) { + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 3 -- +array(0) { +} + +-- Iteration 4 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 5 -- +array(0) { +} + +-- Iteration 6 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 7 -- +array(0) { +} + +-- Iteration 8 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 9 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 10 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 11 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 12 -- +array(3) { + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 13 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 14 -- +array(3) { + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 15 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 16 -- + +Warning: array_slice() expects parameter 2 to be long, string given in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/array/array_slice_variation2.php on line 83 +NULL + +-- Iteration 17 -- + +Warning: array_slice() expects parameter 2 to be long, string given in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/array/array_slice_variation2.php on line 83 +NULL + +-- Iteration 18 -- + +Warning: array_slice() expects parameter 2 to be long, array given in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/array/array_slice_variation2.php on line 83 +NULL + +-- Iteration 19 -- + +Warning: array_slice() expects parameter 2 to be long, string given in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/array/array_slice_variation2.php on line 83 +NULL + +-- Iteration 20 -- + +Warning: array_slice() expects parameter 2 to be long, string given in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/array/array_slice_variation2.php on line 83 +NULL + +-- Iteration 21 -- + +Warning: array_slice() expects parameter 2 to be long, string given in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/array/array_slice_variation2.php on line 83 +NULL + +-- Iteration 22 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} + +-- Iteration 23 -- +array(4) { + ["one"]=> + int(1) + [0]=> + int(2) + ["three"]=> + int(3) + [1]=> + int(4) +} +Done +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_fopen.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_fopen.exp @@ -0,0 +1,52 @@ +*** Testing open_basedir configuration [fopen] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: fopen(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d + +Warning: fopen(../bad): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: fopen(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d + +Warning: fopen(../bad/bad.txt): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: fopen(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d + +Warning: fopen(..): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: fopen(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d + +Warning: fopen(../): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: fopen(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d + +Warning: fopen(/): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: fopen(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d + +Warning: fopen(../bad/.): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: fopen(): open_basedir restriction in effect. File(../bad/./bad.txt) is not within the allowed path(s): (.) in %s on line %d + +Warning: fopen(../bad/./bad.txt): failed to open stream: Operation not permitted in %s on line 12 +bool(false) + +Warning: fopen(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d + +Warning: fopen(./../.): failed to open stream: Operation not permitted in %s on line %d +bool(false) +resource(%d) of type (stream) +resource(%d) of type (stream) +resource(%d) of type (stream) +resource(%d) of type (stream) +resource(%d) of type (stream) +*** Finished testing open_basedir configuration [fopen] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_is_link.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_is_link.log @@ -0,0 +1,82 @@ + +---- EXPECTED OUTPUT +*** Testing open_basedir configuration [is_link] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: is_link(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_link(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_link(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_link(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_link(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_link(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_link(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_link(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_link(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +*** Finished testing open_basedir configuration [is_link] *** +---- ACTUAL OUTPUT +*** Testing open_basedir configuration [is_link] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: is_link(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: is_link(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: is_link(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: is_link(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: is_link(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: is_link(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: is_link(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: is_link(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: is_link(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 122 +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +*** Finished testing open_basedir configuration [is_link] *** +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_chdir.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_chdir.diff @@ -0,0 +1,2 @@ +014+ Warning: chdir(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_chdir.php on line 8 +014- Warning: chdir(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_fileperms.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_fileperms.php @@ -0,0 +1,4 @@ + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_file_exists.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_file_exists.out @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [file_exists] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: file_exists(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: file_exists(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: file_exists(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: file_exists(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: file_exists(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: file_exists(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: file_exists(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: file_exists(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: file_exists(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 122 +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [file_exists] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_is_file.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_is_file.out @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [is_file] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: is_file(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: is_file(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: is_file(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: is_file(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: is_file(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: is_file(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: is_file(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: is_file(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: is_file(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 122 +bool(false) +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [is_file] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_fileatime.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_fileatime.exp @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [fileatime] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: fileatime(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileatime(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileatime(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileatime(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileatime(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileatime(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileatime(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileatime(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileatime(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +int(%d) +int(%d) +int(%d) +int(%d) +int(%d) +*** Finished testing open_basedir configuration [fileatime] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_fopen.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_fopen.php @@ -0,0 +1,22 @@ + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_stat.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_stat.diff @@ -0,0 +1,2 @@ +017+ Warning: stat(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +017- Warning: stat(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_filesize.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_filesize.diff @@ -0,0 +1,2 @@ +017+ Warning: filesize(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +017- Warning: filesize(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_fileowner.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_fileowner.diff @@ -0,0 +1,2 @@ +017+ Warning: fileowner(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +017- Warning: fileowner(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_fileinode.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_fileinode.diff @@ -0,0 +1,2 @@ +017+ Warning: fileinode(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +017- Warning: fileinode(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_filetype.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_filetype.php @@ -0,0 +1,4 @@ + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_disk_free_space.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_disk_free_space.out @@ -0,0 +1,32 @@ +*** Testing open_basedir configuration [disk_free_space] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: disk_free_space(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: disk_free_space(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: disk_free_space(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: disk_free_space(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: disk_free_space(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: disk_free_space(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: disk_free_space(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: disk_free_space(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) +float(21544681472) +*** Finished testing open_basedir configuration [disk_free_space] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_is_readable.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_is_readable.log @@ -0,0 +1,82 @@ + +---- EXPECTED OUTPUT +*** Testing open_basedir configuration [is_readable] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: is_readable(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_readable(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_readable(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_readable(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_readable(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_readable(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_readable(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_readable(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_readable(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [is_readable] *** +---- ACTUAL OUTPUT +*** Testing open_basedir configuration [is_readable] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: is_readable(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: is_readable(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: is_readable(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: is_readable(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: is_readable(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: is_readable(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: is_readable(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: is_readable(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: is_readable(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 122 +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [is_readable] *** +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_fileinode.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_fileinode.php @@ -0,0 +1,4 @@ + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_is_file.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_is_file.log @@ -0,0 +1,82 @@ + +---- EXPECTED OUTPUT +*** Testing open_basedir configuration [is_file] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: is_file(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_file(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_file(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_file(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_file(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_file(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_file(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_file(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_file(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [is_file] *** +---- ACTUAL OUTPUT +*** Testing open_basedir configuration [is_file] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: is_file(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: is_file(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: is_file(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: is_file(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: is_file(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: is_file(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: is_file(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: is_file(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: is_file(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 122 +bool(false) +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [is_file] *** +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_filemtime.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_filemtime.php @@ -0,0 +1,4 @@ + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_lstat.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_lstat.log @@ -0,0 +1,82 @@ + +---- EXPECTED OUTPUT +*** Testing open_basedir configuration [lstat] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: lstat(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: lstat(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: lstat(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: lstat(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: lstat(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: lstat(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: lstat(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: lstat(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: lstat(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [lstat] *** +---- ACTUAL OUTPUT +*** Testing open_basedir configuration [lstat] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: lstat(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: lstat(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: lstat(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: lstat(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: lstat(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: lstat(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: lstat(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: lstat(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: lstat(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 109 +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [lstat] *** +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_file.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_file.php @@ -0,0 +1,13 @@ + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_filectime.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_filectime.php @@ -0,0 +1,4 @@ + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_file.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_file.log @@ -0,0 +1,130 @@ + +---- EXPECTED OUTPUT +*** Testing open_basedir configuration [file] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: file(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d + +Warning: file(../bad): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: file(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d + +Warning: file(../bad/bad.txt): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: file(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d + +Warning: file(..): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: file(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d + +Warning: file(../): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: file(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d + +Warning: file(/): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: file(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d + +Warning: file(../bad/.): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: file(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d + +Warning: file(%s/test/bad/bad.txt): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: file(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d + +Warning: file(%s/test/bad/../bad/bad.txt): failed to open stream: Operation not permitted in %s on line %d +bool(false) +array(1) { + [0]=> + string(12) "Hello World!" +} +array(1) { + [0]=> + string(12) "Hello World!" +} +array(1) { + [0]=> + string(12) "Hello World!" +} +array(1) { + [0]=> + string(12) "Hello World!" +} +*** Finished testing open_basedir configuration [file] *** +---- ACTUAL OUTPUT +*** Testing open_basedir configuration [file] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: file(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 + +Warning: file(../bad): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: file(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 + +Warning: file(../bad/bad.txt): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: file(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 + +Warning: file(..): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: file(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 + +Warning: file(../): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: file(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 + +Warning: file(/): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: file(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 + +Warning: file(../bad/.): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: file(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 + +Warning: file(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: file(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 + +Warning: file(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) +array(1) { + [0]=> + string(12) "Hello World!" +} +array(1) { + [0]=> + string(12) "Hello World!" +} +array(1) { + [0]=> + string(12) "Hello World!" +} +array(1) { + [0]=> + string(12) "Hello World!" +} +*** Finished testing open_basedir configuration [file] *** +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_copy.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_copy.php @@ -0,0 +1,18 @@ + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_is_file.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_is_file.exp @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [is_file] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: is_file(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_file(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_file(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_file(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_file(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_file(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_file(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_file(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_file(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [is_file] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_filemtime.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_filemtime.exp @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [filemtime] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: filemtime(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filemtime(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filemtime(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filemtime(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filemtime(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filemtime(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filemtime(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filemtime(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filemtime(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +int(%d) +int(%d) +int(%d) +int(%d) +int(%d) +*** Finished testing open_basedir configuration [filemtime] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_file_get_contents.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_file_get_contents.out @@ -0,0 +1,51 @@ +*** Testing open_basedir configuration [file_get_contents] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: file_get_contents(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 + +Warning: file_get_contents(../bad): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: file_get_contents(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 + +Warning: file_get_contents(../bad/bad.txt): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: file_get_contents(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 + +Warning: file_get_contents(..): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: file_get_contents(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 + +Warning: file_get_contents(../): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: file_get_contents(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 + +Warning: file_get_contents(/): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: file_get_contents(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 + +Warning: file_get_contents(../bad/.): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: file_get_contents(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 + +Warning: file_get_contents(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: file_get_contents(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 + +Warning: file_get_contents(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) +string(12) "Hello World!" +string(12) "Hello World!" +string(12) "Hello World!" +string(12) "Hello World!" +*** Finished testing open_basedir configuration [file_get_contents] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_copy.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_copy.diff @@ -0,0 +1,2 @@ +023+ Warning: copy(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 9 +023- Warning: copy(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_is_link.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_is_link.php @@ -0,0 +1,4 @@ + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_tempnam.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_tempnam.php @@ -0,0 +1,18 @@ + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_parse_ini_file.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_parse_ini_file.out @@ -0,0 +1,47 @@ +*** Testing open_basedir configuration [parse_ini_file] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: parse_ini_file(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_parse_ini_file.php on line 6 + +Warning: parse_ini_file(../bad): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_parse_ini_file.php on line 6 +array(0) { +} + +Warning: parse_ini_file(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_parse_ini_file.php on line 7 + +Warning: parse_ini_file(../bad/bad.txt): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_parse_ini_file.php on line 7 +array(0) { +} + +Warning: parse_ini_file(..): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_parse_ini_file.php on line 8 +array(0) { +} + +Warning: parse_ini_file(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_parse_ini_file.php on line 9 + +Warning: parse_ini_file(../): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_parse_ini_file.php on line 9 +array(0) { +} + +Warning: parse_ini_file(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_parse_ini_file.php on line 10 + +Warning: parse_ini_file(../bad/.): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_parse_ini_file.php on line 10 +array(0) { +} + +Warning: parse_ini_file(): open_basedir restriction in effect. File(../bad/./bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_parse_ini_file.php on line 11 + +Warning: parse_ini_file(../bad/./bad.txt): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_parse_ini_file.php on line 11 +array(0) { +} + +Warning: parse_ini_file(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_parse_ini_file.php on line 12 + +Warning: parse_ini_file(./../.): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_parse_ini_file.php on line 12 +array(0) { +} +*** Finished testing open_basedir configuration [parse_ini_file] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_is_link.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_is_link.out @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [is_link] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: is_link(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: is_link(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: is_link(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: is_link(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: is_link(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: is_link(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: is_link(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: is_link(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: is_link(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 122 +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +*** Finished testing open_basedir configuration [is_link] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_chdir.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_chdir.php @@ -0,0 +1,14 @@ + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_chmod.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_chmod.log @@ -0,0 +1,76 @@ + +---- EXPECTED OUTPUT +*** Testing open_basedir configuration [chmod] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: chmod(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: chmod(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: chmod(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: chmod(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: chmod(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: chmod(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: chmod(): open_basedir restriction in effect. File(../bad/./bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: chmod(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [chmod] *** +---- ACTUAL OUTPUT +*** Testing open_basedir configuration [chmod] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: chmod(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_chmod.php on line 6 +bool(false) + +Warning: chmod(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_chmod.php on line 7 +bool(false) + +Warning: chmod(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_chmod.php on line 8 +bool(false) + +Warning: chmod(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_chmod.php on line 9 +bool(false) + +Warning: chmod(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_chmod.php on line 10 +bool(false) + +Warning: chmod(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_chmod.php on line 11 +bool(false) + +Warning: chmod(): open_basedir restriction in effect. File(../bad/./bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_chmod.php on line 12 +bool(false) + +Warning: chmod(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_chmod.php on line 13 +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [chmod] *** +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_file.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_file.out @@ -0,0 +1,63 @@ +*** Testing open_basedir configuration [file] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: file(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 + +Warning: file(../bad): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: file(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 + +Warning: file(../bad/bad.txt): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: file(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 + +Warning: file(..): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: file(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 + +Warning: file(../): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: file(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 + +Warning: file(/): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: file(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 + +Warning: file(../bad/.): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: file(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 + +Warning: file(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: file(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 + +Warning: file(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) +array(1) { + [0]=> + string(12) "Hello World!" +} +array(1) { + [0]=> + string(12) "Hello World!" +} +array(1) { + [0]=> + string(12) "Hello World!" +} +array(1) { + [0]=> + string(12) "Hello World!" +} +*** Finished testing open_basedir configuration [file] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_is_executable.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_is_executable.diff @@ -0,0 +1,2 @@ +017+ Warning: is_executable(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +017- Warning: is_executable(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_fileowner.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_fileowner.exp @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [fileowner] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: fileowner(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileowner(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileowner(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileowner(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileowner(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileowner(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileowner(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileowner(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileowner(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +int(%d) +int(%d) +int(%d) +int(%d) +int(%d) +*** Finished testing open_basedir configuration [fileowner] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_filetype.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_filetype.diff @@ -0,0 +1,2 @@ +017+ Warning: filetype(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +017- Warning: filetype(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_file_exists.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_file_exists.diff @@ -0,0 +1,2 @@ +017+ Warning: file_exists(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +017- Warning: file_exists(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_touch.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_touch.php @@ -0,0 +1,22 @@ + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_file.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_file.exp @@ -0,0 +1,63 @@ +*** Testing open_basedir configuration [file] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: file(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d + +Warning: file(../bad): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: file(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d + +Warning: file(../bad/bad.txt): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: file(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d + +Warning: file(..): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: file(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d + +Warning: file(../): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: file(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d + +Warning: file(/): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: file(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d + +Warning: file(../bad/.): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: file(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d + +Warning: file(%s/test/bad/bad.txt): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: file(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d + +Warning: file(%s/test/bad/../bad/bad.txt): failed to open stream: Operation not permitted in %s on line %d +bool(false) +array(1) { + [0]=> + string(12) "Hello World!" +} +array(1) { + [0]=> + string(12) "Hello World!" +} +array(1) { + [0]=> + string(12) "Hello World!" +} +array(1) { + [0]=> + string(12) "Hello World!" +} +*** Finished testing open_basedir configuration [file] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_filegroup.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_filegroup.exp @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [filegroup] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: filegroup(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filegroup(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filegroup(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filegroup(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filegroup(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filegroup(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filegroup(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filegroup(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filegroup(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +int(%d) +int(%d) +int(%d) +int(%d) +int(%d) +*** Finished testing open_basedir configuration [filegroup] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_fileinode.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_fileinode.exp @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [fileinode] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: fileinode(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileinode(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileinode(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileinode(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileinode(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileinode(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileinode(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileinode(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileinode(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +int(%d) +int(%d) +int(%d) +int(%d) +int(%d) +*** Finished testing open_basedir configuration [fileinode] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_disk_free_space.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_disk_free_space.log @@ -0,0 +1,68 @@ + +---- EXPECTED OUTPUT +*** Testing open_basedir configuration [disk_free_space] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: disk_free_space(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: disk_free_space(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: disk_free_space(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: disk_free_space(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: disk_free_space(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: disk_free_space(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: disk_free_space(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: disk_free_space(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) +float(%s) +*** Finished testing open_basedir configuration [disk_free_space] *** +---- ACTUAL OUTPUT +*** Testing open_basedir configuration [disk_free_space] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: disk_free_space(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: disk_free_space(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: disk_free_space(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: disk_free_space(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: disk_free_space(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: disk_free_space(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: disk_free_space(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: disk_free_space(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) +float(21544681472) +*** Finished testing open_basedir configuration [disk_free_space] *** +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_is_dir.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_is_dir.out @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [is_dir] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: is_dir(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: is_dir(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: is_dir(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: is_dir(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: is_dir(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: is_dir(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: is_dir(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: is_dir(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: is_dir(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 122 +bool(false) +bool(true) +bool(false) +bool(false) +bool(false) +bool(false) +*** Finished testing open_basedir configuration [is_dir] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_parse_ini_file.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_parse_ini_file.php @@ -0,0 +1,15 @@ + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_is_link.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_is_link.exp @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [is_link] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: is_link(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_link(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_link(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_link(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_link(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_link(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_link(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_link(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_link(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +*** Finished testing open_basedir configuration [is_link] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_copy.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_copy.exp @@ -0,0 +1,49 @@ +*** Testing open_basedir configuration [copy] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: copy(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d + +Warning: copy(../bad): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: copy(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d + +Warning: copy(../bad/bad.txt): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: copy(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d + +Warning: copy(..): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: copy(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d + +Warning: copy(../): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: copy(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d + +Warning: copy(/): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: copy(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d + +Warning: copy(../bad/.): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: copy(): open_basedir restriction in effect. File(../bad/./bad.txt) is not within the allowed path(s): (.) in %s on line %d + +Warning: copy(../bad/./bad.txt): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: copy(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d + +Warning: copy(./../.): failed to open stream: Operation not permitted in %s on line %d +bool(false) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [copy] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_tempnam.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_tempnam.out @@ -0,0 +1,27 @@ +*** Testing open_basedir configuration [tempnam] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: tempnam(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_tempnam.php on line 6 +bool(false) + +Warning: tempnam(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_tempnam.php on line 7 +bool(false) + +Warning: tempnam(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_tempnam.php on line 8 +bool(false) + +Warning: tempnam(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_tempnam.php on line 9 +bool(false) + +Warning: tempnam(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_tempnam.php on line 10 +bool(false) + +Warning: tempnam(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_tempnam.php on line 11 +bool(false) +string(92) "/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/ok/testF8lAXM" +bool(true) +*** Finished testing open_basedir configuration [tempnam] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_parse_ini_file.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_parse_ini_file.log @@ -0,0 +1,98 @@ + +---- EXPECTED OUTPUT +*** Testing open_basedir configuration [parse_ini_file] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: parse_ini_file(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d + +Warning: parse_ini_file(../bad): failed to open stream: Operation not permitted in %s on line %d +array(0) { +} + +Warning: parse_ini_file(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d + +Warning: parse_ini_file(../bad/bad.txt): failed to open stream: Operation not permitted in %s on line %d +array(0) { +} + +Warning: parse_ini_file(..): failed to open stream: Operation not permitted in %s on line %d +array(0) { +} + +Warning: parse_ini_file(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d + +Warning: parse_ini_file(../): failed to open stream: Operation not permitted in %s on line %d +array(0) { +} + +Warning: parse_ini_file(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d + +Warning: parse_ini_file(../bad/.): failed to open stream: Operation not permitted in %s on line %d +array(0) { +} + +Warning: parse_ini_file(): open_basedir restriction in effect. File(../bad/./bad.txt) is not within the allowed path(s): (.) in %s on line %d + +Warning: parse_ini_file(../bad/./bad.txt): failed to open stream: Operation not permitted in %s on line %d +array(0) { +} + +Warning: parse_ini_file(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d + +Warning: parse_ini_file(./../.): failed to open stream: Operation not permitted in %s on line %d +array(0) { +} +*** Finished testing open_basedir configuration [parse_ini_file] *** +---- ACTUAL OUTPUT +*** Testing open_basedir configuration [parse_ini_file] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: parse_ini_file(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_parse_ini_file.php on line 6 + +Warning: parse_ini_file(../bad): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_parse_ini_file.php on line 6 +array(0) { +} + +Warning: parse_ini_file(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_parse_ini_file.php on line 7 + +Warning: parse_ini_file(../bad/bad.txt): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_parse_ini_file.php on line 7 +array(0) { +} + +Warning: parse_ini_file(..): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_parse_ini_file.php on line 8 +array(0) { +} + +Warning: parse_ini_file(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_parse_ini_file.php on line 9 + +Warning: parse_ini_file(../): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_parse_ini_file.php on line 9 +array(0) { +} + +Warning: parse_ini_file(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_parse_ini_file.php on line 10 + +Warning: parse_ini_file(../bad/.): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_parse_ini_file.php on line 10 +array(0) { +} + +Warning: parse_ini_file(): open_basedir restriction in effect. File(../bad/./bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_parse_ini_file.php on line 11 + +Warning: parse_ini_file(../bad/./bad.txt): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_parse_ini_file.php on line 11 +array(0) { +} + +Warning: parse_ini_file(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_parse_ini_file.php on line 12 + +Warning: parse_ini_file(./../.): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_parse_ini_file.php on line 12 +array(0) { +} +*** Finished testing open_basedir configuration [parse_ini_file] *** +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_is_writable.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_is_writable.php @@ -0,0 +1,4 @@ + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_filectime.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_filectime.exp @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [filectime] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: filectime(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filectime(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filectime(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filectime(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filectime(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filectime(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filectime(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filectime(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filectime(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +int(%d) +int(%d) +int(%d) +int(%d) +int(%d) +*** Finished testing open_basedir configuration [filectime] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_is_file.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_is_file.php @@ -0,0 +1,4 @@ + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_touch.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_touch.log @@ -0,0 +1,76 @@ + +---- EXPECTED OUTPUT +*** Testing open_basedir configuration [touch] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: touch(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: touch(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: touch(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: touch(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: touch(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: touch(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: touch(): open_basedir restriction in effect. File(../bad/./bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: touch(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [touch] *** +---- ACTUAL OUTPUT +*** Testing open_basedir configuration [touch] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: touch(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_touch.php on line 6 +bool(false) + +Warning: touch(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_touch.php on line 7 +bool(false) + +Warning: touch(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_touch.php on line 8 +bool(false) + +Warning: touch(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_touch.php on line 9 +bool(false) + +Warning: touch(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_touch.php on line 10 +bool(false) + +Warning: touch(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_touch.php on line 11 +bool(false) + +Warning: touch(): open_basedir restriction in effect. File(../bad/./bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_touch.php on line 12 +bool(false) + +Warning: touch(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_touch.php on line 13 +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [touch] *** +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_filetype.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_filetype.out @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [filetype] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: filetype(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: filetype(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: filetype(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: filetype(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: filetype(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: filetype(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: filetype(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: filetype(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: filetype(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 122 +bool(false) +string(3) "dir" +string(4) "file" +string(4) "file" +string(4) "file" +string(4) "file" +*** Finished testing open_basedir configuration [filetype] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_chmod.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_chmod.out @@ -0,0 +1,36 @@ +*** Testing open_basedir configuration [chmod] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: chmod(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_chmod.php on line 6 +bool(false) + +Warning: chmod(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_chmod.php on line 7 +bool(false) + +Warning: chmod(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_chmod.php on line 8 +bool(false) + +Warning: chmod(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_chmod.php on line 9 +bool(false) + +Warning: chmod(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_chmod.php on line 10 +bool(false) + +Warning: chmod(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_chmod.php on line 11 +bool(false) + +Warning: chmod(): open_basedir restriction in effect. File(../bad/./bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_chmod.php on line 12 +bool(false) + +Warning: chmod(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_chmod.php on line 13 +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [chmod] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_tempnam.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_tempnam.exp @@ -0,0 +1,27 @@ +*** Testing open_basedir configuration [tempnam] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: tempnam(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: tempnam(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: tempnam(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: tempnam(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: tempnam(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: tempnam(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +string(%d) "%s" +bool(true) +*** Finished testing open_basedir configuration [tempnam] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_fileowner.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_fileowner.php @@ -0,0 +1,4 @@ + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_is_readable.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_is_readable.diff @@ -0,0 +1,2 @@ +017+ Warning: is_readable(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +017- Warning: is_readable(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_is_writable.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_is_writable.out @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [is_writable] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: is_writable(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: is_writable(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: is_writable(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: is_writable(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: is_writable(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: is_writable(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: is_writable(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: is_writable(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: is_writable(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 122 +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [is_writable] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_is_executable.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_is_executable.log @@ -0,0 +1,74 @@ + +---- EXPECTED OUTPUT +*** Testing open_basedir configuration [is_executable] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: is_executable(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_executable(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_executable(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_executable(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_executable(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_executable(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_executable(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_executable(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +*** Finished testing open_basedir configuration [is_executable] *** +---- ACTUAL OUTPUT +*** Testing open_basedir configuration [is_executable] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: is_executable(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: is_executable(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: is_executable(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: is_executable(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: is_executable(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: is_executable(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: is_executable(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: is_executable(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +*** Finished testing open_basedir configuration [is_executable] *** +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_tempnam.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_tempnam.log @@ -0,0 +1,58 @@ + +---- EXPECTED OUTPUT +*** Testing open_basedir configuration [tempnam] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: tempnam(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: tempnam(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: tempnam(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: tempnam(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: tempnam(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: tempnam(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +string(%d) "%s" +bool(true) +*** Finished testing open_basedir configuration [tempnam] *** +---- ACTUAL OUTPUT +*** Testing open_basedir configuration [tempnam] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: tempnam(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_tempnam.php on line 6 +bool(false) + +Warning: tempnam(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_tempnam.php on line 7 +bool(false) + +Warning: tempnam(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_tempnam.php on line 8 +bool(false) + +Warning: tempnam(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_tempnam.php on line 9 +bool(false) + +Warning: tempnam(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_tempnam.php on line 10 +bool(false) + +Warning: tempnam(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_tempnam.php on line 11 +bool(false) +string(92) "/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/ok/testF8lAXM" +bool(true) +*** Finished testing open_basedir configuration [tempnam] *** +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_fileatime.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_fileatime.out @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [fileatime] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: fileatime(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: fileatime(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: fileatime(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: fileatime(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: fileatime(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: fileatime(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: fileatime(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: fileatime(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: fileatime(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 122 +bool(false) +int(1211899473) +int(1211899473) +int(1211899473) +int(1211899473) +int(1211899473) +*** Finished testing open_basedir configuration [fileatime] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_filesize.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_filesize.out @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [filesize] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: filesize(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: filesize(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: filesize(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: filesize(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: filesize(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: filesize(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: filesize(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: filesize(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: filesize(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 122 +bool(false) +int(19) +int(12) +int(12) +int(12) +int(12) +*** Finished testing open_basedir configuration [filesize] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_fileowner.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_fileowner.out @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [fileowner] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: fileowner(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: fileowner(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: fileowner(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: fileowner(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: fileowner(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: fileowner(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: fileowner(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: fileowner(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: fileowner(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 122 +bool(false) +int(1000) +int(1000) +int(1000) +int(1000) +int(1000) +*** Finished testing open_basedir configuration [fileowner] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_fileperms.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_fileperms.log @@ -0,0 +1,82 @@ + +---- EXPECTED OUTPUT +*** Testing open_basedir configuration [fileperms] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: fileperms(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileperms(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileperms(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileperms(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileperms(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileperms(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileperms(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileperms(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileperms(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +int(%d) +int(%d) +int(%d) +int(%d) +int(%d) +*** Finished testing open_basedir configuration [fileperms] *** +---- ACTUAL OUTPUT +*** Testing open_basedir configuration [fileperms] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: fileperms(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: fileperms(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: fileperms(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: fileperms(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: fileperms(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: fileperms(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: fileperms(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: fileperms(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: fileperms(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 122 +bool(false) +int(16877) +int(33188) +int(33188) +int(33188) +int(33188) +*** Finished testing open_basedir configuration [fileperms] *** +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_parse_ini_file.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_parse_ini_file.diff @@ -0,0 +1,2 @@ +024+ Warning: parse_ini_file(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_parse_ini_file.php on line 9 +024- Warning: parse_ini_file(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_filesize.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_filesize.php @@ -0,0 +1,4 @@ + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_stat.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_stat.exp @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [stat] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: stat(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: stat(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: stat(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: stat(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: stat(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: stat(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: stat(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: stat(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: stat(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [stat] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_chdir.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_chdir.out @@ -0,0 +1,25 @@ +*** Testing open_basedir configuration [chdir] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: chdir(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_chdir.php on line 6 +bool(false) + +Warning: chdir(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_chdir.php on line 7 +bool(false) + +Warning: chdir(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_chdir.php on line 8 +bool(false) + +Warning: chdir(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_chdir.php on line 9 +bool(false) + +Warning: chdir(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_chdir.php on line 10 +bool(false) + +Warning: chdir(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_chdir.php on line 11 +bool(false) +*** Finished testing open_basedir configuration [chdir] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_fopen.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_fopen.diff @@ -0,0 +1,2 @@ +023+ Warning: fopen(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 9 +023- Warning: fopen(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_disk_free_space.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_disk_free_space.diff @@ -0,0 +1,2 @@ +017+ Warning: disk_free_space(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +017- Warning: disk_free_space(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_parse_ini_file.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_parse_ini_file.exp @@ -0,0 +1,47 @@ +*** Testing open_basedir configuration [parse_ini_file] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: parse_ini_file(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d + +Warning: parse_ini_file(../bad): failed to open stream: Operation not permitted in %s on line %d +array(0) { +} + +Warning: parse_ini_file(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d + +Warning: parse_ini_file(../bad/bad.txt): failed to open stream: Operation not permitted in %s on line %d +array(0) { +} + +Warning: parse_ini_file(..): failed to open stream: Operation not permitted in %s on line %d +array(0) { +} + +Warning: parse_ini_file(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d + +Warning: parse_ini_file(../): failed to open stream: Operation not permitted in %s on line %d +array(0) { +} + +Warning: parse_ini_file(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d + +Warning: parse_ini_file(../bad/.): failed to open stream: Operation not permitted in %s on line %d +array(0) { +} + +Warning: parse_ini_file(): open_basedir restriction in effect. File(../bad/./bad.txt) is not within the allowed path(s): (.) in %s on line %d + +Warning: parse_ini_file(../bad/./bad.txt): failed to open stream: Operation not permitted in %s on line %d +array(0) { +} + +Warning: parse_ini_file(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d + +Warning: parse_ini_file(./../.): failed to open stream: Operation not permitted in %s on line %d +array(0) { +} +*** Finished testing open_basedir configuration [parse_ini_file] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_filemtime.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_filemtime.log @@ -0,0 +1,82 @@ + +---- EXPECTED OUTPUT +*** Testing open_basedir configuration [filemtime] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: filemtime(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filemtime(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filemtime(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filemtime(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filemtime(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filemtime(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filemtime(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filemtime(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filemtime(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +int(%d) +int(%d) +int(%d) +int(%d) +int(%d) +*** Finished testing open_basedir configuration [filemtime] *** +---- ACTUAL OUTPUT +*** Testing open_basedir configuration [filemtime] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: filemtime(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: filemtime(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: filemtime(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: filemtime(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: filemtime(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: filemtime(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: filemtime(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: filemtime(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: filemtime(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 122 +bool(false) +int(1211899473) +int(1211899473) +int(1211899473) +int(1211899473) +int(1211899473) +*** Finished testing open_basedir configuration [filemtime] *** +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_file_get_contents.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_file_get_contents.diff @@ -0,0 +1,2 @@ +023+ Warning: file_get_contents(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +023- Warning: file_get_contents(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_filesize.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_filesize.log @@ -0,0 +1,82 @@ + +---- EXPECTED OUTPUT +*** Testing open_basedir configuration [filesize] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: filesize(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filesize(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filesize(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filesize(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filesize(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filesize(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filesize(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filesize(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filesize(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +int(%d) +int(%d) +int(%d) +int(%d) +int(%d) +*** Finished testing open_basedir configuration [filesize] *** +---- ACTUAL OUTPUT +*** Testing open_basedir configuration [filesize] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: filesize(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: filesize(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: filesize(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: filesize(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: filesize(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: filesize(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: filesize(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: filesize(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: filesize(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 122 +bool(false) +int(19) +int(12) +int(12) +int(12) +int(12) +*** Finished testing open_basedir configuration [filesize] *** +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_file_get_contents.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_file_get_contents.exp @@ -0,0 +1,51 @@ +*** Testing open_basedir configuration [file_get_contents] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: file_get_contents(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d + +Warning: file_get_contents(../bad): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: file_get_contents(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d + +Warning: file_get_contents(../bad/bad.txt): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: file_get_contents(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d + +Warning: file_get_contents(..): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: file_get_contents(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d + +Warning: file_get_contents(../): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: file_get_contents(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d + +Warning: file_get_contents(/): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: file_get_contents(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d + +Warning: file_get_contents(../bad/.): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: file_get_contents(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d + +Warning: file_get_contents(%s/test/bad/bad.txt): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: file_get_contents(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d + +Warning: file_get_contents(%s/test/bad/../bad/bad.txt): failed to open stream: Operation not permitted in %s on line %d +bool(false) +string(12) "Hello World!" +string(12) "Hello World!" +string(12) "Hello World!" +string(12) "Hello World!" +*** Finished testing open_basedir configuration [file_get_contents] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_file.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_file.diff @@ -0,0 +1,2 @@ +023+ Warning: file(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +023- Warning: file(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_filemtime.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_filemtime.out @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [filemtime] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: filemtime(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: filemtime(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: filemtime(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: filemtime(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: filemtime(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: filemtime(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: filemtime(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: filemtime(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: filemtime(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 122 +bool(false) +int(1211899473) +int(1211899473) +int(1211899473) +int(1211899473) +int(1211899473) +*** Finished testing open_basedir configuration [filemtime] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_chmod.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_chmod.php @@ -0,0 +1,23 @@ + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_fileinode.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_fileinode.out @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [fileinode] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: fileinode(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: fileinode(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: fileinode(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: fileinode(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: fileinode(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: fileinode(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: fileinode(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: fileinode(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: fileinode(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 122 +bool(false) +int(135317218) +int(135317219) +int(135317219) +int(135317219) +int(135317219) +*** Finished testing open_basedir configuration [fileinode] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_is_executable.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_is_executable.php @@ -0,0 +1,13 @@ + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_is_writable.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_is_writable.exp @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [is_writable] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: is_writable(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_writable(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_writable(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_writable(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_writable(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_writable(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_writable(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_writable(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_writable(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [is_writable] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_fileowner.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_fileowner.log @@ -0,0 +1,82 @@ + +---- EXPECTED OUTPUT +*** Testing open_basedir configuration [fileowner] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: fileowner(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileowner(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileowner(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileowner(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileowner(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileowner(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileowner(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileowner(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileowner(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +int(%d) +int(%d) +int(%d) +int(%d) +int(%d) +*** Finished testing open_basedir configuration [fileowner] *** +---- ACTUAL OUTPUT +*** Testing open_basedir configuration [fileowner] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: fileowner(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: fileowner(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: fileowner(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: fileowner(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: fileowner(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: fileowner(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: fileowner(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: fileowner(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: fileowner(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 122 +bool(false) +int(1000) +int(1000) +int(1000) +int(1000) +int(1000) +*** Finished testing open_basedir configuration [fileowner] *** +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_fileatime.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_fileatime.diff @@ -0,0 +1,2 @@ +017+ Warning: fileatime(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +017- Warning: fileatime(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_copy.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_copy.log @@ -0,0 +1,102 @@ + +---- EXPECTED OUTPUT +*** Testing open_basedir configuration [copy] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: copy(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d + +Warning: copy(../bad): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: copy(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d + +Warning: copy(../bad/bad.txt): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: copy(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d + +Warning: copy(..): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: copy(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d + +Warning: copy(../): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: copy(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d + +Warning: copy(/): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: copy(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d + +Warning: copy(../bad/.): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: copy(): open_basedir restriction in effect. File(../bad/./bad.txt) is not within the allowed path(s): (.) in %s on line %d + +Warning: copy(../bad/./bad.txt): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: copy(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d + +Warning: copy(./../.): failed to open stream: Operation not permitted in %s on line %d +bool(false) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [copy] *** +---- ACTUAL OUTPUT +*** Testing open_basedir configuration [copy] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: copy(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 6 + +Warning: copy(../bad): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 6 +bool(false) + +Warning: copy(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 7 + +Warning: copy(../bad/bad.txt): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 7 +bool(false) + +Warning: copy(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 8 + +Warning: copy(..): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 8 +bool(false) + +Warning: copy(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 9 + +Warning: copy(../): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 9 +bool(false) + +Warning: copy(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 10 + +Warning: copy(/): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 10 +bool(false) + +Warning: copy(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 11 + +Warning: copy(../bad/.): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 11 +bool(false) + +Warning: copy(): open_basedir restriction in effect. File(../bad/./bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 12 + +Warning: copy(../bad/./bad.txt): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 12 +bool(false) + +Warning: copy(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 13 + +Warning: copy(./../.): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 13 +bool(false) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [copy] *** +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_chmod.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_chmod.diff @@ -0,0 +1,2 @@ +017+ Warning: chmod(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_chmod.php on line 9 +017- Warning: chmod(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_is_readable.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_is_readable.php @@ -0,0 +1,4 @@ + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_fileinode.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_fileinode.log @@ -0,0 +1,82 @@ + +---- EXPECTED OUTPUT +*** Testing open_basedir configuration [fileinode] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: fileinode(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileinode(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileinode(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileinode(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileinode(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileinode(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileinode(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileinode(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileinode(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +int(%d) +int(%d) +int(%d) +int(%d) +int(%d) +*** Finished testing open_basedir configuration [fileinode] *** +---- ACTUAL OUTPUT +*** Testing open_basedir configuration [fileinode] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: fileinode(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: fileinode(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: fileinode(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: fileinode(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: fileinode(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: fileinode(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: fileinode(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: fileinode(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: fileinode(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 122 +bool(false) +int(135317218) +int(135317219) +int(135317219) +int(135317219) +int(135317219) +*** Finished testing open_basedir configuration [fileinode] *** +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_filemtime.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_filemtime.diff @@ -0,0 +1,2 @@ +017+ Warning: filemtime(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +017- Warning: filemtime(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_disk_free_space.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_disk_free_space.php @@ -0,0 +1,9 @@ + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_stat.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_stat.log @@ -0,0 +1,82 @@ + +---- EXPECTED OUTPUT +*** Testing open_basedir configuration [stat] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: stat(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: stat(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: stat(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: stat(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: stat(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: stat(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: stat(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: stat(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: stat(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [stat] *** +---- ACTUAL OUTPUT +*** Testing open_basedir configuration [stat] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: stat(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: stat(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: stat(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: stat(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: stat(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: stat(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: stat(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: stat(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: stat(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 109 +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [stat] *** +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_lstat.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_lstat.diff @@ -0,0 +1,2 @@ +017+ Warning: lstat(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +017- Warning: lstat(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_fopen.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_fopen.log @@ -0,0 +1,108 @@ + +---- EXPECTED OUTPUT +*** Testing open_basedir configuration [fopen] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: fopen(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d + +Warning: fopen(../bad): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: fopen(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d + +Warning: fopen(../bad/bad.txt): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: fopen(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d + +Warning: fopen(..): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: fopen(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d + +Warning: fopen(../): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: fopen(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d + +Warning: fopen(/): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: fopen(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d + +Warning: fopen(../bad/.): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: fopen(): open_basedir restriction in effect. File(../bad/./bad.txt) is not within the allowed path(s): (.) in %s on line %d + +Warning: fopen(../bad/./bad.txt): failed to open stream: Operation not permitted in %s on line 12 +bool(false) + +Warning: fopen(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d + +Warning: fopen(./../.): failed to open stream: Operation not permitted in %s on line %d +bool(false) +resource(%d) of type (stream) +resource(%d) of type (stream) +resource(%d) of type (stream) +resource(%d) of type (stream) +resource(%d) of type (stream) +*** Finished testing open_basedir configuration [fopen] *** +---- ACTUAL OUTPUT +*** Testing open_basedir configuration [fopen] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: fopen(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 6 + +Warning: fopen(../bad): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 6 +bool(false) + +Warning: fopen(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 7 + +Warning: fopen(../bad/bad.txt): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 7 +bool(false) + +Warning: fopen(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 8 + +Warning: fopen(..): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 8 +bool(false) + +Warning: fopen(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 9 + +Warning: fopen(../): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 9 +bool(false) + +Warning: fopen(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 10 + +Warning: fopen(/): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 10 +bool(false) + +Warning: fopen(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 11 + +Warning: fopen(../bad/.): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 11 +bool(false) + +Warning: fopen(): open_basedir restriction in effect. File(../bad/./bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 12 + +Warning: fopen(../bad/./bad.txt): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 12 +bool(false) + +Warning: fopen(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 13 + +Warning: fopen(./../.): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 13 +bool(false) +resource(8) of type (stream) +resource(9) of type (stream) +resource(10) of type (stream) +resource(11) of type (stream) +resource(12) of type (stream) +*** Finished testing open_basedir configuration [fopen] *** +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_file_exists.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_file_exists.exp @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [file_exists] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: file_exists(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: file_exists(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: file_exists(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: file_exists(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: file_exists(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: file_exists(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: file_exists(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: file_exists(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: file_exists(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [file_exists] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_filectime.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_filectime.out @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [filectime] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: filectime(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: filectime(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: filectime(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: filectime(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: filectime(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: filectime(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: filectime(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: filectime(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: filectime(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 122 +bool(false) +int(1211899473) +int(1211899473) +int(1211899473) +int(1211899473) +int(1211899473) +*** Finished testing open_basedir configuration [filectime] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_is_writable.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_is_writable.diff @@ -0,0 +1,2 @@ +017+ Warning: is_writable(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +017- Warning: is_writable(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_is_dir.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_is_dir.log @@ -0,0 +1,82 @@ + +---- EXPECTED OUTPUT +*** Testing open_basedir configuration [is_dir] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: is_dir(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_dir(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_dir(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_dir(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_dir(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_dir(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_dir(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_dir(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_dir(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +bool(true) +bool(false) +bool(false) +bool(false) +bool(false) +*** Finished testing open_basedir configuration [is_dir] *** +---- ACTUAL OUTPUT +*** Testing open_basedir configuration [is_dir] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: is_dir(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: is_dir(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: is_dir(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: is_dir(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: is_dir(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: is_dir(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: is_dir(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: is_dir(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: is_dir(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 122 +bool(false) +bool(true) +bool(false) +bool(false) +bool(false) +bool(false) +*** Finished testing open_basedir configuration [is_dir] *** +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_fileperms.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_fileperms.exp @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [fileperms] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: fileperms(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileperms(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileperms(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileperms(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileperms(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileperms(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileperms(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileperms(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileperms(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +int(%d) +int(%d) +int(%d) +int(%d) +int(%d) +*** Finished testing open_basedir configuration [fileperms] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_is_link.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_is_link.diff @@ -0,0 +1,2 @@ +017+ Warning: is_link(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +017- Warning: is_link(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_filegroup.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_filegroup.out @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [filegroup] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: filegroup(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: filegroup(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: filegroup(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: filegroup(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: filegroup(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: filegroup(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: filegroup(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: filegroup(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: filegroup(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 122 +bool(false) +int(1000) +int(1000) +int(1000) +int(1000) +int(1000) +*** Finished testing open_basedir configuration [filegroup] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_touch.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_touch.diff @@ -0,0 +1,2 @@ +017+ Warning: touch(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_touch.php on line 9 +017- Warning: touch(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_file_get_contents.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_file_get_contents.php @@ -0,0 +1,13 @@ + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_is_dir.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_is_dir.php @@ -0,0 +1,4 @@ + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_fileatime.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_fileatime.log @@ -0,0 +1,82 @@ + +---- EXPECTED OUTPUT +*** Testing open_basedir configuration [fileatime] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: fileatime(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileatime(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileatime(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileatime(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileatime(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileatime(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileatime(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileatime(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: fileatime(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +int(%d) +int(%d) +int(%d) +int(%d) +int(%d) +*** Finished testing open_basedir configuration [fileatime] *** +---- ACTUAL OUTPUT +*** Testing open_basedir configuration [fileatime] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: fileatime(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: fileatime(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: fileatime(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: fileatime(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: fileatime(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: fileatime(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: fileatime(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: fileatime(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: fileatime(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 122 +bool(false) +int(1211899473) +int(1211899473) +int(1211899473) +int(1211899473) +int(1211899473) +*** Finished testing open_basedir configuration [fileatime] *** +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_filegroup.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_filegroup.diff @@ -0,0 +1,2 @@ +017+ Warning: filegroup(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +017- Warning: filegroup(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_lstat.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_lstat.out @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [lstat] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: lstat(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: lstat(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: lstat(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: lstat(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: lstat(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: lstat(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: lstat(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: lstat(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: lstat(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 109 +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [lstat] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_file_get_contents.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_file_get_contents.log @@ -0,0 +1,106 @@ + +---- EXPECTED OUTPUT +*** Testing open_basedir configuration [file_get_contents] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: file_get_contents(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d + +Warning: file_get_contents(../bad): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: file_get_contents(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d + +Warning: file_get_contents(../bad/bad.txt): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: file_get_contents(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d + +Warning: file_get_contents(..): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: file_get_contents(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d + +Warning: file_get_contents(../): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: file_get_contents(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d + +Warning: file_get_contents(/): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: file_get_contents(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d + +Warning: file_get_contents(../bad/.): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: file_get_contents(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d + +Warning: file_get_contents(%s/test/bad/bad.txt): failed to open stream: Operation not permitted in %s on line %d +bool(false) + +Warning: file_get_contents(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d + +Warning: file_get_contents(%s/test/bad/../bad/bad.txt): failed to open stream: Operation not permitted in %s on line %d +bool(false) +string(12) "Hello World!" +string(12) "Hello World!" +string(12) "Hello World!" +string(12) "Hello World!" +*** Finished testing open_basedir configuration [file_get_contents] *** +---- ACTUAL OUTPUT +*** Testing open_basedir configuration [file_get_contents] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: file_get_contents(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 + +Warning: file_get_contents(../bad): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: file_get_contents(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 + +Warning: file_get_contents(../bad/bad.txt): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: file_get_contents(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 + +Warning: file_get_contents(..): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: file_get_contents(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 + +Warning: file_get_contents(../): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: file_get_contents(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 + +Warning: file_get_contents(/): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: file_get_contents(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 + +Warning: file_get_contents(../bad/.): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: file_get_contents(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 + +Warning: file_get_contents(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: file_get_contents(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 + +Warning: file_get_contents(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) +string(12) "Hello World!" +string(12) "Hello World!" +string(12) "Hello World!" +string(12) "Hello World!" +*** Finished testing open_basedir configuration [file_get_contents] *** +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_is_dir.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_is_dir.diff @@ -0,0 +1,2 @@ +017+ Warning: is_dir(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +017- Warning: is_dir(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_filectime.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_filectime.log @@ -0,0 +1,82 @@ + +---- EXPECTED OUTPUT +*** Testing open_basedir configuration [filectime] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: filectime(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filectime(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filectime(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filectime(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filectime(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filectime(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filectime(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filectime(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filectime(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +int(%d) +int(%d) +int(%d) +int(%d) +int(%d) +*** Finished testing open_basedir configuration [filectime] *** +---- ACTUAL OUTPUT +*** Testing open_basedir configuration [filectime] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: filectime(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: filectime(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: filectime(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: filectime(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: filectime(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: filectime(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: filectime(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: filectime(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: filectime(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 122 +bool(false) +int(1211899473) +int(1211899473) +int(1211899473) +int(1211899473) +int(1211899473) +*** Finished testing open_basedir configuration [filectime] *** +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_fopen.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_fopen.out @@ -0,0 +1,52 @@ +*** Testing open_basedir configuration [fopen] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: fopen(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 6 + +Warning: fopen(../bad): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 6 +bool(false) + +Warning: fopen(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 7 + +Warning: fopen(../bad/bad.txt): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 7 +bool(false) + +Warning: fopen(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 8 + +Warning: fopen(..): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 8 +bool(false) + +Warning: fopen(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 9 + +Warning: fopen(../): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 9 +bool(false) + +Warning: fopen(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 10 + +Warning: fopen(/): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 10 +bool(false) + +Warning: fopen(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 11 + +Warning: fopen(../bad/.): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 11 +bool(false) + +Warning: fopen(): open_basedir restriction in effect. File(../bad/./bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 12 + +Warning: fopen(../bad/./bad.txt): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 12 +bool(false) + +Warning: fopen(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 13 + +Warning: fopen(./../.): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_fopen.php on line 13 +bool(false) +resource(8) of type (stream) +resource(9) of type (stream) +resource(10) of type (stream) +resource(11) of type (stream) +resource(12) of type (stream) +*** Finished testing open_basedir configuration [fopen] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_chdir.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_chdir.log @@ -0,0 +1,54 @@ + +---- EXPECTED OUTPUT +*** Testing open_basedir configuration [chdir] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: chdir(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: chdir(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: chdir(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: chdir(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: chdir(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: chdir(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +*** Finished testing open_basedir configuration [chdir] *** +---- ACTUAL OUTPUT +*** Testing open_basedir configuration [chdir] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: chdir(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_chdir.php on line 6 +bool(false) + +Warning: chdir(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_chdir.php on line 7 +bool(false) + +Warning: chdir(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_chdir.php on line 8 +bool(false) + +Warning: chdir(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_chdir.php on line 9 +bool(false) + +Warning: chdir(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_chdir.php on line 10 +bool(false) + +Warning: chdir(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_chdir.php on line 11 +bool(false) +*** Finished testing open_basedir configuration [chdir] *** +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_fileperms.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_fileperms.diff @@ -0,0 +1,2 @@ +017+ Warning: fileperms(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +017- Warning: fileperms(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_is_readable.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_is_readable.exp @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [is_readable] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: is_readable(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_readable(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_readable(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_readable(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_readable(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_readable(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_readable(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_readable(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_readable(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [is_readable] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_chmod.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_chmod.exp @@ -0,0 +1,36 @@ +*** Testing open_basedir configuration [chmod] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: chmod(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: chmod(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: chmod(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: chmod(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: chmod(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: chmod(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: chmod(): open_basedir restriction in effect. File(../bad/./bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: chmod(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [chmod] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_filegroup.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_filegroup.php @@ -0,0 +1,4 @@ + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_filetype.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_filetype.exp @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [filetype] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: filetype(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filetype(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filetype(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filetype(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filetype(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filetype(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filetype(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filetype(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filetype(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +string(3) "dir" +string(4) "file" +string(4) "file" +string(4) "file" +string(4) "file" +*** Finished testing open_basedir configuration [filetype] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_is_readable.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_is_readable.out @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [is_readable] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: is_readable(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: is_readable(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: is_readable(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: is_readable(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: is_readable(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: is_readable(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: is_readable(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: is_readable(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: is_readable(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 122 +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [is_readable] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_tempnam.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_tempnam.diff @@ -0,0 +1,2 @@ +014+ Warning: tempnam(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_tempnam.php on line 8 +014- Warning: tempnam(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_is_file.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_is_file.diff @@ -0,0 +1,2 @@ +017+ Warning: is_file(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +017- Warning: is_file(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_filectime.diff +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_filectime.diff @@ -0,0 +1,2 @@ +017+ Warning: filectime(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +017- Warning: filectime(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_disk_free_space.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_disk_free_space.exp @@ -0,0 +1,32 @@ +*** Testing open_basedir configuration [disk_free_space] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: disk_free_space(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: disk_free_space(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: disk_free_space(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: disk_free_space(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: disk_free_space(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: disk_free_space(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: disk_free_space(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: disk_free_space(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) +float(%s) +*** Finished testing open_basedir configuration [disk_free_space] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_is_dir.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_is_dir.exp @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [is_dir] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: is_dir(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_dir(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_dir(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_dir(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_dir(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_dir(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_dir(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_dir(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_dir(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +bool(true) +bool(false) +bool(false) +bool(false) +bool(false) +*** Finished testing open_basedir configuration [is_dir] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_filegroup.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_filegroup.log @@ -0,0 +1,82 @@ + +---- EXPECTED OUTPUT +*** Testing open_basedir configuration [filegroup] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: filegroup(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filegroup(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filegroup(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filegroup(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filegroup(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filegroup(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filegroup(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filegroup(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filegroup(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +int(%d) +int(%d) +int(%d) +int(%d) +int(%d) +*** Finished testing open_basedir configuration [filegroup] *** +---- ACTUAL OUTPUT +*** Testing open_basedir configuration [filegroup] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: filegroup(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: filegroup(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: filegroup(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: filegroup(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: filegroup(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: filegroup(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: filegroup(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: filegroup(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: filegroup(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 122 +bool(false) +int(1000) +int(1000) +int(1000) +int(1000) +int(1000) +*** Finished testing open_basedir configuration [filegroup] *** +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_copy.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_copy.out @@ -0,0 +1,49 @@ +*** Testing open_basedir configuration [copy] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: copy(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 6 + +Warning: copy(../bad): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 6 +bool(false) + +Warning: copy(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 7 + +Warning: copy(../bad/bad.txt): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 7 +bool(false) + +Warning: copy(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 8 + +Warning: copy(..): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 8 +bool(false) + +Warning: copy(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 9 + +Warning: copy(../): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 9 +bool(false) + +Warning: copy(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 10 + +Warning: copy(/): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 10 +bool(false) + +Warning: copy(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 11 + +Warning: copy(../bad/.): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 11 +bool(false) + +Warning: copy(): open_basedir restriction in effect. File(../bad/./bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 12 + +Warning: copy(../bad/./bad.txt): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 12 +bool(false) + +Warning: copy(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 13 + +Warning: copy(./../.): failed to open stream: Operation not permitted in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_copy.php on line 13 +bool(false) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [copy] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_touch.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_touch.exp @@ -0,0 +1,36 @@ +*** Testing open_basedir configuration [touch] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: touch(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: touch(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: touch(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: touch(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: touch(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: touch(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: touch(): open_basedir restriction in effect. File(../bad/./bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: touch(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [touch] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_lstat.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_lstat.exp @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [lstat] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: lstat(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: lstat(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: lstat(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: lstat(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: lstat(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: lstat(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: lstat(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: lstat(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: lstat(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [lstat] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_file_exists.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_file_exists.log @@ -0,0 +1,82 @@ + +---- EXPECTED OUTPUT +*** Testing open_basedir configuration [file_exists] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: file_exists(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: file_exists(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: file_exists(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: file_exists(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: file_exists(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: file_exists(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: file_exists(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: file_exists(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: file_exists(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [file_exists] *** +---- ACTUAL OUTPUT +*** Testing open_basedir configuration [file_exists] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: file_exists(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: file_exists(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: file_exists(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: file_exists(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: file_exists(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: file_exists(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: file_exists(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: file_exists(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: file_exists(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 122 +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [file_exists] *** +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_filesize.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_filesize.exp @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [filesize] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: filesize(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filesize(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filesize(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filesize(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filesize(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filesize(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filesize(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filesize(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filesize(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +int(%d) +int(%d) +int(%d) +int(%d) +int(%d) +*** Finished testing open_basedir configuration [filesize] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_file_exists.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_file_exists.php @@ -0,0 +1,4 @@ + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_filetype.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_filetype.log @@ -0,0 +1,82 @@ + +---- EXPECTED OUTPUT +*** Testing open_basedir configuration [filetype] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: filetype(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filetype(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filetype(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filetype(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filetype(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filetype(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filetype(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filetype(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: filetype(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +string(3) "dir" +string(4) "file" +string(4) "file" +string(4) "file" +string(4) "file" +*** Finished testing open_basedir configuration [filetype] *** +---- ACTUAL OUTPUT +*** Testing open_basedir configuration [filetype] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: filetype(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: filetype(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: filetype(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: filetype(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: filetype(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: filetype(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: filetype(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: filetype(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: filetype(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 122 +bool(false) +string(3) "dir" +string(4) "file" +string(4) "file" +string(4) "file" +string(4) "file" +*** Finished testing open_basedir configuration [filetype] *** +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_fileatime.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_fileatime.php @@ -0,0 +1,4 @@ + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_chdir.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_chdir.exp @@ -0,0 +1,25 @@ +*** Testing open_basedir configuration [chdir] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: chdir(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: chdir(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: chdir(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: chdir(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: chdir(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: chdir(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +*** Finished testing open_basedir configuration [chdir] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_is_executable.exp +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_is_executable.exp @@ -0,0 +1,35 @@ +*** Testing open_basedir configuration [is_executable] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: is_executable(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_executable(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_executable(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_executable(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_executable(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_executable(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_executable(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_executable(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +*** Finished testing open_basedir configuration [is_executable] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_touch.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_touch.out @@ -0,0 +1,36 @@ +*** Testing open_basedir configuration [touch] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: touch(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_touch.php on line 6 +bool(false) + +Warning: touch(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_touch.php on line 7 +bool(false) + +Warning: touch(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_touch.php on line 8 +bool(false) + +Warning: touch(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_touch.php on line 9 +bool(false) + +Warning: touch(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_touch.php on line 10 +bool(false) + +Warning: touch(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_touch.php on line 11 +bool(false) + +Warning: touch(): open_basedir restriction in effect. File(../bad/./bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_touch.php on line 12 +bool(false) + +Warning: touch(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir_touch.php on line 13 +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [touch] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_fileperms.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_fileperms.out @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [fileperms] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: fileperms(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: fileperms(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: fileperms(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: fileperms(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: fileperms(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: fileperms(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: fileperms(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: fileperms(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: fileperms(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 122 +bool(false) +int(16877) +int(33188) +int(33188) +int(33188) +int(33188) +*** Finished testing open_basedir configuration [fileperms] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_stat.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_stat.php @@ -0,0 +1,4 @@ + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_lstat.php +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_lstat.php @@ -0,0 +1,4 @@ + --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_is_executable.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_is_executable.out @@ -0,0 +1,35 @@ +*** Testing open_basedir configuration [is_executable] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: is_executable(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: is_executable(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: is_executable(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: is_executable(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: is_executable(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: is_executable(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: is_executable(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: is_executable(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) +bool(false) +bool(false) +bool(false) +bool(false) +*** Finished testing open_basedir configuration [is_executable] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_stat.out +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_stat.out @@ -0,0 +1,39 @@ +*** Testing open_basedir configuration [stat] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: stat(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: stat(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: stat(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: stat(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: stat(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: stat(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: stat(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: stat(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: stat(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 109 +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [stat] *** \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/standard/tests/file/open_basedir_is_writable.log +++ php5-5.2.10.dfsg.1/ext/standard/tests/file/open_basedir_is_writable.log @@ -0,0 +1,82 @@ + +---- EXPECTED OUTPUT +*** Testing open_basedir configuration [is_writable] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: is_writable(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_writable(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_writable(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_writable(): open_basedir restriction in effect. File(../) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_writable(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_writable(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_writable(): open_basedir restriction in effect. File(%s/test/bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_writable(): open_basedir restriction in effect. File(%s/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in %s on line %d +bool(false) + +Warning: is_writable(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in %s on line %d +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [is_writable] *** +---- ACTUAL OUTPUT +*** Testing open_basedir configuration [is_writable] *** +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) + +Warning: is_writable(): open_basedir restriction in effect. File(../bad) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 77 +bool(false) + +Warning: is_writable(): open_basedir restriction in effect. File(../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 78 +bool(false) + +Warning: is_writable(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 79 +bool(false) + +Warning: is_writable(): open_basedir restriction in effect. File(..) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 80 +bool(false) + +Warning: is_writable(): open_basedir restriction in effect. File(/) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 81 +bool(false) + +Warning: is_writable(): open_basedir restriction in effect. File(../bad/.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 82 +bool(false) + +Warning: is_writable(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 84 +bool(false) + +Warning: is_writable(): open_basedir restriction in effect. File(/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/test/bad/../bad/bad.txt) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 85 +bool(false) + +Warning: is_writable(): open_basedir restriction in effect. File(./../.) is not within the allowed path(s): (.) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/standard/tests/file/open_basedir.inc on line 122 +bool(false) +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) +*** Finished testing open_basedir configuration [is_writable] *** +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/session/tests/session_save_path_variation5.log +++ php5-5.2.10.dfsg.1/ext/session/tests/session_save_path_variation5.log @@ -0,0 +1,26 @@ + +---- EXPECTED OUTPUT +*** Testing session_save_path() : variation *** +bool(true) +bool(true) + +Warning: ini_set(): open_basedir restriction in effect. File(%s) is not within the allowed path(s): (.) in %s on line %d +string(0) "" +bool(true) +string(0) "" +bool(true) +string(0) "" +bool(true) +Done +---- ACTUAL OUTPUT +*** Testing session_save_path() : variation *** +bool(true) +bool(true) +string(67) "/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests" +bool(true) +string(67) "/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests" +bool(true) +string(67) "/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests" +bool(true) +Done +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/session/tests/session_write_close_variation3.exp +++ php5-5.2.10.dfsg.1/ext/session/tests/session_write_close_variation3.exp @@ -0,0 +1,9 @@ +*** Testing session_write_close() : variation *** +array(0) { +} +NULL +array(0) { +} +bool(true) +bool(true) +Done \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/session/tests/session_set_save_handler_variation3.exp +++ php5-5.2.10.dfsg.1/ext/session/tests/session_set_save_handler_variation3.exp @@ -0,0 +1,4 @@ +*** Testing session_set_save_handler() : variation *** + +bool(false) +bool(true) \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/session/tests/session_encode_variation2.php +++ php5-5.2.10.dfsg.1/ext/session/tests/session_encode_variation2.php @@ -0,0 +1,19 @@ + --- php5-5.2.10.dfsg.1.orig/ext/session/tests/session_save_path_variation5.exp +++ php5-5.2.10.dfsg.1/ext/session/tests/session_save_path_variation5.exp @@ -0,0 +1,12 @@ +*** Testing session_save_path() : variation *** +bool(true) +bool(true) + +Warning: ini_set(): open_basedir restriction in effect. File(%s) is not within the allowed path(s): (.) in %s on line %d +string(0) "" +bool(true) +string(0) "" +bool(true) +string(0) "" +bool(true) +Done \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/session/tests/session_save_path_variation5.diff +++ php5-5.2.10.dfsg.1/ext/session/tests/session_save_path_variation5.diff @@ -0,0 +1,12 @@ +004+ string(67) "/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests" +005+ bool(true) +006+ string(67) "/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests" +007+ bool(true) +008+ string(67) "/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests" +004- +005- Warning: ini_set(): open_basedir restriction in effect. File(%s) is not within the allowed path(s): (.) in %s on line %d +006- string(0) "" +008- string(0) "" +009- bool(true) +010- string(0) "" +011- bool(true) \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/session/tests/session_set_save_handler_variation3.php +++ php5-5.2.10.dfsg.1/ext/session/tests/session_set_save_handler_variation3.php @@ -0,0 +1,20 @@ + --- php5-5.2.10.dfsg.1.orig/ext/session/tests/session_start_variation9.out +++ php5-5.2.10.dfsg.1/ext/session/tests/session_start_variation9.out @@ -0,0 +1,14 @@ +Warning: Unknown: open(/var/lib/php5/sess_dbecc376be3fa92534626a295b33b39b, O_RDWR) failed: No such file or directory (2) in Unknown on line 0 + +Warning: Unknown: Cannot send session cookie - headers already sent in Unknown on line 0 + +Warning: Unknown: Cannot send session cache limiter - headers already sent in Unknown on line 0 +*** Testing session_start() : variation *** +string(32) "dbecc376be3fa92534626a295b33b39b" + +Notice: A session had already been started - ignoring session_start() in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_start_variation9.php on line 14 +bool(true) +string(32) "dbecc376be3fa92534626a295b33b39b" +bool(true) +string(0) "" +Done \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/session/tests/session_start_variation9.log +++ php5-5.2.10.dfsg.1/ext/session/tests/session_start_variation9.log @@ -0,0 +1,27 @@ + +---- EXPECTED OUTPUT +*** Testing session_start() : variation *** +string(%d) "%s" + +Notice: A session had already been started - ignoring session_start() in %s on line %d +bool(true) +string(%d) "%s" +bool(true) +string(0) "" +Done +---- ACTUAL OUTPUT +Warning: Unknown: open(/var/lib/php5/sess_dbecc376be3fa92534626a295b33b39b, O_RDWR) failed: No such file or directory (2) in Unknown on line 0 + +Warning: Unknown: Cannot send session cookie - headers already sent in Unknown on line 0 + +Warning: Unknown: Cannot send session cache limiter - headers already sent in Unknown on line 0 +*** Testing session_start() : variation *** +string(32) "dbecc376be3fa92534626a295b33b39b" + +Notice: A session had already been started - ignoring session_start() in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_start_variation9.php on line 14 +bool(true) +string(32) "dbecc376be3fa92534626a295b33b39b" +bool(true) +string(0) "" +Done +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/session/tests/session_write_close_variation3.log +++ php5-5.2.10.dfsg.1/ext/session/tests/session_write_close_variation3.log @@ -0,0 +1,37 @@ + +---- EXPECTED OUTPUT +*** Testing session_write_close() : variation *** +array(0) { +} +NULL +array(0) { +} +bool(true) +bool(true) +Done +---- ACTUAL OUTPUT +Warning: Unknown: open(/var/lib/php5/sess_d45946055e14447c7c79fa658656fc2d, O_RDWR) failed: No such file or directory (2) in Unknown on line 0 + +Warning: Unknown: Cannot send session cookie - headers already sent in Unknown on line 0 + +Warning: Unknown: Cannot send session cache limiter - headers already sent in Unknown on line 0 +*** Testing session_write_close() : variation *** +array(0) { +} + +Warning: session_write_close(): open(/var/lib/php5/sess_d45946055e14447c7c79fa658656fc2d, O_RDWR) failed: No such file or directory (2) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_write_close_variation3.php on line 14 + +Warning: session_write_close(): Failed to write session data (files). Please verify that the current setting of session.save_path is correct (/var/lib/php5) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_write_close_variation3.php on line 14 +NULL +array(0) { +} + +Warning: session_start(): open(/var/lib/php5/sess_d45946055e14447c7c79fa658656fc2d, O_RDWR) failed: No such file or directory (2) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_write_close_variation3.php on line 16 + +Warning: session_start(): Cannot send session cookie - headers already sent in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_write_close_variation3.php on line 16 + +Warning: session_start(): Cannot send session cache limiter - headers already sent in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_write_close_variation3.php on line 16 +bool(true) +bool(true) +Done +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/session/tests/session_save_path_variation5.php +++ php5-5.2.10.dfsg.1/ext/session/tests/session_save_path_variation5.php @@ -0,0 +1,34 @@ + --- php5-5.2.10.dfsg.1.orig/ext/session/tests/session_write_close_variation3.out +++ php5-5.2.10.dfsg.1/ext/session/tests/session_write_close_variation3.out @@ -0,0 +1,24 @@ +Warning: Unknown: open(/var/lib/php5/sess_d45946055e14447c7c79fa658656fc2d, O_RDWR) failed: No such file or directory (2) in Unknown on line 0 + +Warning: Unknown: Cannot send session cookie - headers already sent in Unknown on line 0 + +Warning: Unknown: Cannot send session cache limiter - headers already sent in Unknown on line 0 +*** Testing session_write_close() : variation *** +array(0) { +} + +Warning: session_write_close(): open(/var/lib/php5/sess_d45946055e14447c7c79fa658656fc2d, O_RDWR) failed: No such file or directory (2) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_write_close_variation3.php on line 14 + +Warning: session_write_close(): Failed to write session data (files). Please verify that the current setting of session.save_path is correct (/var/lib/php5) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_write_close_variation3.php on line 14 +NULL +array(0) { +} + +Warning: session_start(): open(/var/lib/php5/sess_d45946055e14447c7c79fa658656fc2d, O_RDWR) failed: No such file or directory (2) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_write_close_variation3.php on line 16 + +Warning: session_start(): Cannot send session cookie - headers already sent in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_write_close_variation3.php on line 16 + +Warning: session_start(): Cannot send session cache limiter - headers already sent in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_write_close_variation3.php on line 16 +bool(true) +bool(true) +Done \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/session/tests/session_start_variation9.php +++ php5-5.2.10.dfsg.1/ext/session/tests/session_start_variation9.php @@ -0,0 +1,21 @@ + --- php5-5.2.10.dfsg.1.orig/ext/session/tests/session_start_variation9.exp +++ php5-5.2.10.dfsg.1/ext/session/tests/session_start_variation9.exp @@ -0,0 +1,9 @@ +*** Testing session_start() : variation *** +string(%d) "%s" + +Notice: A session had already been started - ignoring session_start() in %s on line %d +bool(true) +string(%d) "%s" +bool(true) +string(0) "" +Done \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/session/tests/session_set_save_handler_variation3.out +++ php5-5.2.10.dfsg.1/ext/session/tests/session_set_save_handler_variation3.out @@ -0,0 +1,9 @@ +Warning: Unknown: open(/var/lib/php5/sess_f6e9899e0f04b6a771eb9e466d765086, O_RDWR) failed: No such file or directory (2) in Unknown on line 0 + +Warning: Unknown: Cannot send session cookie - headers already sent in Unknown on line 0 + +Warning: Unknown: Cannot send session cache limiter - headers already sent in Unknown on line 0 +*** Testing session_set_save_handler() : variation *** + +bool(false) +bool(true) \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/session/tests/session_encode_variation2.out +++ php5-5.2.10.dfsg.1/ext/session/tests/session_encode_variation2.out @@ -0,0 +1,12 @@ +Warning: Unknown: open(/var/lib/php5/sess_73774def2d48d6b8479722cc67d86102, O_RDWR) failed: No such file or directory (2) in Unknown on line 0 + +Warning: Unknown: Cannot send session cookie - headers already sent in Unknown on line 0 + +Warning: Unknown: Cannot send session cache limiter - headers already sent in Unknown on line 0 +*** Testing session_encode() : variation *** +bool(false) +bool(true) + +Warning: session_encode(): Cannot encode non-existent session. in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_encode_variation2.php on line 15 +bool(false) +Done \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/session/tests/session_commit_variation3.exp +++ php5-5.2.10.dfsg.1/ext/session/tests/session_commit_variation3.exp @@ -0,0 +1,9 @@ +*** Testing session_commit() : variation *** +array(0) { +} +NULL +array(0) { +} +bool(true) +bool(true) +Done \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/session/tests/session_write_close_variation3.diff +++ php5-5.2.10.dfsg.1/ext/session/tests/session_write_close_variation3.diff @@ -0,0 +1,15 @@ +001+ Warning: Unknown: open(/var/lib/php5/sess_d45946055e14447c7c79fa658656fc2d, O_RDWR) failed: No such file or directory (2) in Unknown on line 0 +002+ +003+ Warning: Unknown: Cannot send session cookie - headers already sent in Unknown on line 0 +004+ +005+ Warning: Unknown: Cannot send session cache limiter - headers already sent in Unknown on line 0 +009+ +010+ Warning: session_write_close(): open(/var/lib/php5/sess_d45946055e14447c7c79fa658656fc2d, O_RDWR) failed: No such file or directory (2) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_write_close_variation3.php on line 14 +011+ +012+ Warning: session_write_close(): Failed to write session data (files). Please verify that the current setting of session.save_path is correct (/var/lib/php5) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_write_close_variation3.php on line 14 +016+ +017+ Warning: session_start(): open(/var/lib/php5/sess_d45946055e14447c7c79fa658656fc2d, O_RDWR) failed: No such file or directory (2) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_write_close_variation3.php on line 16 +018+ +019+ Warning: session_start(): Cannot send session cookie - headers already sent in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_write_close_variation3.php on line 16 +020+ +021+ Warning: session_start(): Cannot send session cache limiter - headers already sent in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_write_close_variation3.php on line 16 \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/session/tests/session_encode_variation2.diff +++ php5-5.2.10.dfsg.1/ext/session/tests/session_encode_variation2.diff @@ -0,0 +1,5 @@ +001+ Warning: Unknown: open(/var/lib/php5/sess_73774def2d48d6b8479722cc67d86102, O_RDWR) failed: No such file or directory (2) in Unknown on line 0 +002+ +003+ Warning: Unknown: Cannot send session cookie - headers already sent in Unknown on line 0 +004+ +005+ Warning: Unknown: Cannot send session cache limiter - headers already sent in Unknown on line 0 \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/session/tests/session_encode_variation2.log +++ php5-5.2.10.dfsg.1/ext/session/tests/session_encode_variation2.log @@ -0,0 +1,23 @@ + +---- EXPECTED OUTPUT +*** Testing session_encode() : variation *** +bool(false) +bool(true) + +Warning: session_encode(): Cannot encode non-existent session. in %s on line %d +bool(false) +Done +---- ACTUAL OUTPUT +Warning: Unknown: open(/var/lib/php5/sess_73774def2d48d6b8479722cc67d86102, O_RDWR) failed: No such file or directory (2) in Unknown on line 0 + +Warning: Unknown: Cannot send session cookie - headers already sent in Unknown on line 0 + +Warning: Unknown: Cannot send session cache limiter - headers already sent in Unknown on line 0 +*** Testing session_encode() : variation *** +bool(false) +bool(true) + +Warning: session_encode(): Cannot encode non-existent session. in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_encode_variation2.php on line 15 +bool(false) +Done +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/session/tests/session_save_path_variation5.out +++ php5-5.2.10.dfsg.1/ext/session/tests/session_save_path_variation5.out @@ -0,0 +1,10 @@ +*** Testing session_save_path() : variation *** +bool(true) +bool(true) +string(67) "/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests" +bool(true) +string(67) "/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests" +bool(true) +string(67) "/local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests" +bool(true) +Done \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/session/tests/session_start_variation9.diff +++ php5-5.2.10.dfsg.1/ext/session/tests/session_start_variation9.diff @@ -0,0 +1,5 @@ +001+ Warning: Unknown: open(/var/lib/php5/sess_dbecc376be3fa92534626a295b33b39b, O_RDWR) failed: No such file or directory (2) in Unknown on line 0 +002+ +003+ Warning: Unknown: Cannot send session cookie - headers already sent in Unknown on line 0 +004+ +005+ Warning: Unknown: Cannot send session cache limiter - headers already sent in Unknown on line 0 \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/session/tests/session_write_close_variation3.php +++ php5-5.2.10.dfsg.1/ext/session/tests/session_write_close_variation3.php @@ -0,0 +1,21 @@ + --- php5-5.2.10.dfsg.1.orig/ext/session/tests/session_commit_variation3.log +++ php5-5.2.10.dfsg.1/ext/session/tests/session_commit_variation3.log @@ -0,0 +1,37 @@ + +---- EXPECTED OUTPUT +*** Testing session_commit() : variation *** +array(0) { +} +NULL +array(0) { +} +bool(true) +bool(true) +Done +---- ACTUAL OUTPUT +Warning: Unknown: open(/var/lib/php5/sess_1213c6754bd77470cae90ff26b22a0b6, O_RDWR) failed: No such file or directory (2) in Unknown on line 0 + +Warning: Unknown: Cannot send session cookie - headers already sent in Unknown on line 0 + +Warning: Unknown: Cannot send session cache limiter - headers already sent in Unknown on line 0 +*** Testing session_commit() : variation *** +array(0) { +} + +Warning: session_commit(): open(/var/lib/php5/sess_1213c6754bd77470cae90ff26b22a0b6, O_RDWR) failed: No such file or directory (2) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_commit_variation3.php on line 14 + +Warning: session_commit(): Failed to write session data (files). Please verify that the current setting of session.save_path is correct (/var/lib/php5) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_commit_variation3.php on line 14 +NULL +array(0) { +} + +Warning: session_start(): open(/var/lib/php5/sess_1213c6754bd77470cae90ff26b22a0b6, O_RDWR) failed: No such file or directory (2) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_commit_variation3.php on line 16 + +Warning: session_start(): Cannot send session cookie - headers already sent in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_commit_variation3.php on line 16 + +Warning: session_start(): Cannot send session cache limiter - headers already sent in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_commit_variation3.php on line 16 +bool(true) +bool(true) +Done +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/session/tests/session_commit_variation3.diff +++ php5-5.2.10.dfsg.1/ext/session/tests/session_commit_variation3.diff @@ -0,0 +1,15 @@ +001+ Warning: Unknown: open(/var/lib/php5/sess_1213c6754bd77470cae90ff26b22a0b6, O_RDWR) failed: No such file or directory (2) in Unknown on line 0 +002+ +003+ Warning: Unknown: Cannot send session cookie - headers already sent in Unknown on line 0 +004+ +005+ Warning: Unknown: Cannot send session cache limiter - headers already sent in Unknown on line 0 +009+ +010+ Warning: session_commit(): open(/var/lib/php5/sess_1213c6754bd77470cae90ff26b22a0b6, O_RDWR) failed: No such file or directory (2) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_commit_variation3.php on line 14 +011+ +012+ Warning: session_commit(): Failed to write session data (files). Please verify that the current setting of session.save_path is correct (/var/lib/php5) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_commit_variation3.php on line 14 +016+ +017+ Warning: session_start(): open(/var/lib/php5/sess_1213c6754bd77470cae90ff26b22a0b6, O_RDWR) failed: No such file or directory (2) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_commit_variation3.php on line 16 +018+ +019+ Warning: session_start(): Cannot send session cookie - headers already sent in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_commit_variation3.php on line 16 +020+ +021+ Warning: session_start(): Cannot send session cache limiter - headers already sent in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_commit_variation3.php on line 16 \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/session/tests/session_set_save_handler_variation3.log +++ php5-5.2.10.dfsg.1/ext/session/tests/session_set_save_handler_variation3.log @@ -0,0 +1,17 @@ + +---- EXPECTED OUTPUT +*** Testing session_set_save_handler() : variation *** + +bool(false) +bool(true) +---- ACTUAL OUTPUT +Warning: Unknown: open(/var/lib/php5/sess_f6e9899e0f04b6a771eb9e466d765086, O_RDWR) failed: No such file or directory (2) in Unknown on line 0 + +Warning: Unknown: Cannot send session cookie - headers already sent in Unknown on line 0 + +Warning: Unknown: Cannot send session cache limiter - headers already sent in Unknown on line 0 +*** Testing session_set_save_handler() : variation *** + +bool(false) +bool(true) +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/session/tests/session_encode_variation2.exp +++ php5-5.2.10.dfsg.1/ext/session/tests/session_encode_variation2.exp @@ -0,0 +1,7 @@ +*** Testing session_encode() : variation *** +bool(false) +bool(true) + +Warning: session_encode(): Cannot encode non-existent session. in %s on line %d +bool(false) +Done \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/session/tests/session_commit_variation3.php +++ php5-5.2.10.dfsg.1/ext/session/tests/session_commit_variation3.php @@ -0,0 +1,21 @@ + --- php5-5.2.10.dfsg.1.orig/ext/session/tests/session_set_save_handler_variation3.diff +++ php5-5.2.10.dfsg.1/ext/session/tests/session_set_save_handler_variation3.diff @@ -0,0 +1,5 @@ +001+ Warning: Unknown: open(/var/lib/php5/sess_f6e9899e0f04b6a771eb9e466d765086, O_RDWR) failed: No such file or directory (2) in Unknown on line 0 +002+ +003+ Warning: Unknown: Cannot send session cookie - headers already sent in Unknown on line 0 +004+ +005+ Warning: Unknown: Cannot send session cache limiter - headers already sent in Unknown on line 0 \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/session/tests/session_commit_variation3.out +++ php5-5.2.10.dfsg.1/ext/session/tests/session_commit_variation3.out @@ -0,0 +1,24 @@ +Warning: Unknown: open(/var/lib/php5/sess_1213c6754bd77470cae90ff26b22a0b6, O_RDWR) failed: No such file or directory (2) in Unknown on line 0 + +Warning: Unknown: Cannot send session cookie - headers already sent in Unknown on line 0 + +Warning: Unknown: Cannot send session cache limiter - headers already sent in Unknown on line 0 +*** Testing session_commit() : variation *** +array(0) { +} + +Warning: session_commit(): open(/var/lib/php5/sess_1213c6754bd77470cae90ff26b22a0b6, O_RDWR) failed: No such file or directory (2) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_commit_variation3.php on line 14 + +Warning: session_commit(): Failed to write session data (files). Please verify that the current setting of session.save_path is correct (/var/lib/php5) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_commit_variation3.php on line 14 +NULL +array(0) { +} + +Warning: session_start(): open(/var/lib/php5/sess_1213c6754bd77470cae90ff26b22a0b6, O_RDWR) failed: No such file or directory (2) in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_commit_variation3.php on line 16 + +Warning: session_start(): Cannot send session cookie - headers already sent in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_commit_variation3.php on line 16 + +Warning: session_start(): Cannot send session cache limiter - headers already sent in /local/work/source/php5_5.2.6/php5-5.2.6-1ubuntu1/ext/session/tests/session_commit_variation3.php on line 16 +bool(true) +bool(true) +Done \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/dba/tests/test0.dbm +++ php5-5.2.10.dfsg.1/ext/dba/tests/test0.dbm @@ -0,0 +1,4 @@ +key5=The last content string +key number 6=The 6th value +key number 6=The 6th value inserted again would be an error +key2=Content 2 replaced 2nd time --- php5-5.2.10.dfsg.1.orig/ext/iconv/tests/iconv_stream_filter.out +++ php5-5.2.10.dfsg.1/ext/iconv/tests/iconv_stream_filter.out @@ -0,0 +1,9 @@ +string(20) "1b244224332473244b24" +string(10) "41244f1b28" +string(2) "42" +string(20) "a4b3a4f3a4cba4c1a4cf" +string(10) "69636f6e76" +string(2) "0a" +string(20) "1b244f24332466245824" +string(10) "4e24421b28" +string(2) "4f" \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/iconv/tests/bug16069.out +++ php5-5.2.10.dfsg.1/ext/iconv/tests/bug16069.out @@ -0,0 +1 @@ +ߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥС(맥) \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/iconv/tests/iconv_stream_filter.exp +++ php5-5.2.10.dfsg.1/ext/iconv/tests/iconv_stream_filter.exp @@ -0,0 +1,11 @@ +string(20) "1b244224332473244b24" +string(10) "41244f1b28" +string(2) "42" +string(20) "a4b3a4f3a4cba4c1a4cf" +string(10) "69636f6e76" +string(2) "0a" + +Warning: fread(): iconv stream filter ("ISO-2022-JP"=>"EUC-JP"): invalid multibyte sequence in %s on line %d +string(0) "" +string(0) "" +string(0) "" \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/iconv/tests/iconv_stream_filter.php +++ php5-5.2.10.dfsg.1/ext/iconv/tests/iconv_stream_filter.php @@ -0,0 +1,22 @@ + --- php5-5.2.10.dfsg.1.orig/ext/iconv/tests/bug16069.diff +++ php5-5.2.10.dfsg.1/ext/iconv/tests/bug16069.diff @@ -0,0 +1,2 @@ +001+ ߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥС(맥) +001- ߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥС(맥) \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/iconv/tests/bug16069.exp +++ php5-5.2.10.dfsg.1/ext/iconv/tests/bug16069.exp @@ -0,0 +1 @@ +ߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥС(맥) \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/iconv/tests/iconv_stream_filter.diff +++ php5-5.2.10.dfsg.1/ext/iconv/tests/iconv_stream_filter.diff @@ -0,0 +1,8 @@ +007+ string(20) "1b244f24332466245824" +008+ string(10) "4e24421b28" +009+ string(2) "4f" +007- +008- Warning: fread(): iconv stream filter ("ISO-2022-JP"=>"EUC-JP"): invalid multibyte sequence in %s on line %d +009- string(0) "" +010- string(0) "" +011- string(0) "" \ No newline at end of file --- php5-5.2.10.dfsg.1.orig/ext/iconv/tests/bug16069.php +++ php5-5.2.10.dfsg.1/ext/iconv/tests/bug16069.php @@ -0,0 +1,8 @@ + --- php5-5.2.10.dfsg.1.orig/ext/iconv/tests/bug16069.log +++ php5-5.2.10.dfsg.1/ext/iconv/tests/bug16069.log @@ -0,0 +1,6 @@ + +---- EXPECTED OUTPUT +ߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥС(맥) +---- ACTUAL OUTPUT +ߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥСߥС(맥) +---- FAILED --- php5-5.2.10.dfsg.1.orig/ext/iconv/tests/iconv_stream_filter.log +++ php5-5.2.10.dfsg.1/ext/iconv/tests/iconv_stream_filter.log @@ -0,0 +1,24 @@ + +---- EXPECTED OUTPUT +string(20) "1b244224332473244b24" +string(10) "41244f1b28" +string(2) "42" +string(20) "a4b3a4f3a4cba4c1a4cf" +string(10) "69636f6e76" +string(2) "0a" + +Warning: fread(): iconv stream filter ("ISO-2022-JP"=>"EUC-JP"): invalid multibyte sequence in %s on line %d +string(0) "" +string(0) "" +string(0) "" +---- ACTUAL OUTPUT +string(20) "1b244224332473244b24" +string(10) "41244f1b28" +string(2) "42" +string(20) "a4b3a4f3a4cba4c1a4cf" +string(10) "69636f6e76" +string(2) "0a" +string(20) "1b244f24332466245824" +string(10) "4e24421b28" +string(2) "4f" +---- FAILED