1
0
mirror of https://github.com/php/php-src.git synced 2026-03-29 11:42:17 +02:00

- remove files

This commit is contained in:
Pierre Joye
2005-08-15 22:08:52 +00:00
parent 4e9d393cac
commit cd0c5e4ec4
15 changed files with 0 additions and 9678 deletions

View File

@@ -1,208 +0,0 @@
<?php
// /* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | 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. |
// +----------------------------------------------------------------------+
// | Author: Stig Bakken <ssb@php.net> |
// | |
// +----------------------------------------------------------------------+
//
// $Id$
if (!extension_loaded("overload")) {
// die hard without ext/overload
die("Rebuild PHP with the `overload' extension to use PEAR_Autoloader");
}
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.
*
* @author Stig Sæther Bakken <ssb@php.net>
*/
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");
?>

View File

@@ -1,426 +0,0 @@
<?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. |
// +----------------------------------------------------------------------+
// | Authors: Stig Sæther Bakken <ssb@php.net> |
// +----------------------------------------------------------------------+
//
// $Id$
require_once 'PEAR/Common.php';
/**
* Class to handle building (compiling) extensions.
*
* @author Stig Sæther Bakken <ssb@php.net>
*/
class PEAR_Builder extends PEAR_Common
{
// {{{ properties
var $php_api_version = 0;
var $zend_module_api_no = 0;
var $zend_extension_api_no = 0;
var $extensions_built = array();
var $current_callback = null;
// used for msdev builds
var $_lastline = null;
var $_firstline = null;
// }}}
// {{{ constructor
/**
* PEAR_Builder constructor.
*
* @param object $ui user interface object (instance of PEAR_Frontend_*)
*
* @access public
*/
function PEAR_Builder(&$ui)
{
parent::PEAR_Common();
$this->setFrontendObject($ui);
}
// }}}
// {{{ _build_win32()
/**
* Build an extension from source on windows.
* requires msdev
*/
function _build_win32($descfile, $callback = null)
{
if (PEAR::isError($info = $this->infoFromDescriptionFile($descfile))) {
return $info;
}
$dir = dirname($descfile);
$old_cwd = getcwd();
if (!@chdir($dir)) {
return $this->raiseError("could not chdir to $dir");
}
$this->log(2, "building in $dir");
$dsp = $info['package'].'.dsp';
if (!@is_file("$dir/$dsp")) {
return $this->raiseError("The DSP $dsp does not exist.");
}
// XXX TODO: make release build type configurable
$command = 'msdev '.$dsp.' /MAKE "'.$info['package']. ' - Release"';
$this->current_callback = $callback;
$err = $this->_runCommand($command, array(&$this, 'msdevCallback'));
if (PEAR::isError($err)) {
return $err;
}
// figure out the build platform and type
$platform = 'Win32';
$buildtype = 'Release';
if (preg_match('/.*?'.$info['package'].'\s-\s(\w+)\s(.*?)-+/i',$this->_firstline,$matches)) {
$platform = $matches[1];
$buildtype = $matches[2];
}
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.");
}
// 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+("'.
$info['package'].'\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.");
}
if (@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;
}
// }}}
// {{{ msdevCallback()
function msdevCallback($what, $data)
{
if (!$this->_firstline)
$this->_firstline = $data;
$this->_lastline = $data;
}
// }}}
// {{{ _harventInstDir
/**
* @param string
* @param string
* @param array
* @access private
*/
function _harvestInstDir($dest_prefix, $dirname, &$built_files)
{
$d = opendir($dirname);
if (!$d)
return false;
$ret = true;
while (($ent = readdir($d)) !== false) {
if ($ent{0} == '.')
continue;
$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,
);
}
}
closedir($d);
return $ret;
}
// }}}
// {{{ build()
/**
* 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 $descfile path to XML package description file
*
* @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
* @see PEAR_Common::infoFromDescriptionFile
*/
function build($descfile, $callback = null)
{
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 (PEAR::isError($info = $this->infoFromDescriptionFile($descfile))) {
return $info;
}
$dir = dirname($descfile);
$old_cwd = getcwd();
if (!@chdir($dir)) {
return $this->raiseError("could not chdir to $dir");
}
$vdir = "$info[package]-$info[version]";
if (is_dir($vdir)) {
chdir($vdir);
}
$dir = getcwd();
$this->log(2, "building in $dir");
$this->current_callback = $callback;
putenv('PATH=' . $this->config->get('bin_dir') . ':' . getenv('PATH'));
$err = $this->_runCommand("phpize", array(&$this, 'phpizeCallback'));
if (PEAR::isError($err)) {
return $err;
}
if (!$err) {
return $this->raiseError("`phpize' failed");
}
// {{{ start of interactive part
$configure_command = "$dir/configure";
if (isset($info['configure_options'])) {
foreach ($info['configure_options'] as $o) {
list($r) = $this->ui->userDialog('build',
array($o['prompt']),
array('text'),
array(@$o['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
// FIXME make configurable
if(!$user=getenv('USER')){
$user='defaultuser';
}
$build_basedir = "/var/tmp/pear-build-$user";
$build_dir = "$build_basedir/$info[package]-$info[version]";
$inst_dir = "$build_basedir/install-$info[package]-$info[version]";
$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';
}
$to_run = array(
$configure_command,
$make_command,
"$make_command INSTALL_ROOT=\"$inst_dir\" install",
"find \"$inst_dir\" -ls"
);
if (!@chdir($build_dir)) {
return $this->raiseError("could not chdir to $build_dir");
}
putenv('PHP_PEAR_VERSION=@PEAR-VER@');
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("php-config --prefix");
$this->_harvestInstDir($prefix, $inst_dir . DIRECTORY_SEPARATOR . $prefix, $built_files);
chdir($old_cwd);
return $built_files;
}
// }}}
// {{{ phpizeCallback()
/**
* 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);
}
}
}
// }}}
// {{{ _runCommand()
/**
* 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;
}
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;
}
$exitcode = @pclose($pp);
return ($exitcode == 0);
}
// }}}
// {{{ log()
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);
}
// }}}
}
?>

View File

@@ -1,398 +0,0 @@
<?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. |
// +----------------------------------------------------------------------+
// | Author: Stig Bakken <ssb@php.net> |
// +----------------------------------------------------------------------+
//
// $Id$
require_once "PEAR.php";
/**
* List of commands and what classes they are implemented in.
* @var array command => implementing class
*/
$GLOBALS['_PEAR_Command_commandlist'] = 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();
/**
* Which user interface class is being used.
* @var string class name
*/
$GLOBALS['_PEAR_Command_uiclass'] = 'PEAR_Frontend_CLI';
/**
* Instance of $_PEAR_Command_uiclass.
* @var object
*/
$GLOBALS['_PEAR_Command_uiobject'] = null;
/**
* 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().
*/
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])) {
return PEAR::raiseError("unknown command `$command'");
}
$class = $GLOBALS['_PEAR_Command_commandlist'][$command];
if (!class_exists($class)) {
return PEAR::raiseError("unknown command `$command'");
}
$ui =& PEAR_Command::getFrontendObject();
$obj = &new $class($ui, $config);
return $obj;
}
// }}}
// {{{ & getFrontendObject()
/**
* Get instance of frontend object.
*
* @return object
* @static
*/
function &getFrontendObject()
{
if (empty($GLOBALS['_PEAR_Command_uiobject'])) {
$GLOBALS['_PEAR_Command_uiobject'] = &new $GLOBALS['_PEAR_Command_uiclass'];
}
return $GLOBALS['_PEAR_Command_uiobject'];
}
// }}}
// {{{ & 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)
{
if (is_object($GLOBALS['_PEAR_Command_uiobject']) &&
is_a($GLOBALS['_PEAR_Command_uiobject'], $uiclass)) {
return $GLOBALS['_PEAR_Command_uiobject'];
}
if (!class_exists($uiclass)) {
$file = str_replace('_', '/', $uiclass) . '.php';
if (PEAR_Command::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 (method_exists($obj, 'userConfirm')) {
$GLOBALS['_PEAR_Command_uiobject'] = &$obj;
$GLOBALS['_PEAR_Command_uiclass'] = $uiclass;
return $obj;
} else {
$err = PEAR::raiseError("not a frontend class: $uiclass");
return $err;
}
}
$err = PEAR::raiseError("no such class: $uiclass");
return $err;
}
// }}}
// {{{ setFrontendType()
// }}}
// {{{ isIncludeable()
/**
* @param string $path relative or absolute include path
* @return boolean
* @static
*/
function isIncludeable($path)
{
if (file_exists($path) && is_readable($path)) {
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;
}
}
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);
}
// }}}
// {{{ 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)
{
if ($dir === null) {
$dir = dirname(__FILE__) . '/Command';
}
$dp = @opendir($dir);
if (empty($dp)) {
return PEAR::raiseError("registerCommands: opendir($dir) failed");
}
if (!$merge) {
$GLOBALS['_PEAR_Command_commandlist'] = array();
}
while ($entry = readdir($dp)) {
if ($entry{0} == '.' || substr($entry, -4) != '.php' || $entry == 'Common.php') {
continue;
}
$class = "PEAR_Command_".substr($entry, 0, -4);
$file = "$dir/$entry";
include_once $file;
// List of commands
if (empty($GLOBALS['_PEAR_Command_objects'][$class])) {
$GLOBALS['_PEAR_Command_objects'][$class] = &new $class($ui, $config);
}
$implements = $GLOBALS['_PEAR_Command_objects'][$class]->getCommands();
foreach ($implements as $command => $desc) {
$GLOBALS['_PEAR_Command_commandlist'][$command] = $class;
$GLOBALS['_PEAR_Command_commanddesc'][$command] = $desc;
}
$shortcuts = $GLOBALS['_PEAR_Command_objects'][$class]->getShortcuts();
foreach ($shortcuts as $shortcut => $command) {
$GLOBALS['_PEAR_Command_shortcuts'][$shortcut] = $command;
}
}
@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_commandlist'][$command])) {
return null;
}
$class = $GLOBALS['_PEAR_Command_commandlist'][$command];
$obj = &$GLOBALS['_PEAR_Command_objects'][$class];
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($cmds[$command])) {
$class = $cmds[$command];
return $GLOBALS['_PEAR_Command_objects'][$class]->getHelp($command);
}
return false;
}
// }}}
}
?>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,487 +0,0 @@
<?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. |
// +----------------------------------------------------------------------+
// | Authors: Tomas V.V.Cox <cox@idecnet.com> |
// | Stig Bakken <ssb@php.net> |
// +----------------------------------------------------------------------+
//
// $Id$
require_once "PEAR.php";
define('PEAR_DEPENDENCY_MISSING', -1);
define('PEAR_DEPENDENCY_CONFLICT', -2);
define('PEAR_DEPENDENCY_UPGRADE_MINOR', -3);
define('PEAR_DEPENDENCY_UPGRADE_MAJOR', -4);
define('PEAR_DEPENDENCY_BAD_DEPENDENCY', -5);
define('PEAR_DEPENDENCY_MISSING_OPTIONAL', -6);
define('PEAR_DEPENDENCY_CONFLICT_OPTIONAL', -7);
define('PEAR_DEPENDENCY_UPGRADE_MINOR_OPTIONAL', -8);
define('PEAR_DEPENDENCY_UPGRADE_MAJOR_OPTIONAL', -9);
/**
* Dependency check for PEAR packages
*
* The class is based on the dependency RFC that can be found at
* http://cvs.php.net/cvs.php/pearweb/rfc. It requires PHP >= 4.1
*
* @author Tomas V.V.Vox <cox@idecnet.com>
* @author Stig Bakken <ssb@php.net>
*/
class PEAR_Dependency
{
// {{{ constructor
/**
* Constructor
*
* @access public
* @param object Registry object
* @return void
*/
function PEAR_Dependency(&$registry)
{
$this->registry = &$registry;
}
// }}}
// {{{ callCheckMethod()
/**
* This method maps the XML dependency definition to the
* corresponding one from PEAR_Dependency
*
* <pre>
* $opts => Array
* (
* [type] => pkg
* [rel] => ge
* [version] => 3.4
* [name] => HTML_Common
* [optional] => false
* )
* </pre>
*
* @param string Error message
* @param array Options
* @return boolean
*/
function callCheckMethod(&$errmsg, $opts)
{
$rel = isset($opts['rel']) ? $opts['rel'] : 'has';
$req = isset($opts['version']) ? $opts['version'] : null;
$name = isset($opts['name']) ? $opts['name'] : null;
$opt = (isset($opts['optional']) && $opts['optional'] == 'yes') ?
$opts['optional'] : null;
$errmsg = '';
switch ($opts['type']) {
case 'pkg':
return $this->checkPackage($errmsg, $name, $req, $rel, $opt);
break;
case 'ext':
return $this->checkExtension($errmsg, $name, $req, $rel, $opt);
break;
case 'php':
return $this->checkPHP($errmsg, $req, $rel);
break;
case 'prog':
return $this->checkProgram($errmsg, $name);
break;
case 'os':
return $this->checkOS($errmsg, $name);
break;
case 'sapi':
return $this->checkSAPI($errmsg, $name);
break;
case 'zend':
return $this->checkZend($errmsg, $name);
break;
default:
return "'{$opts['type']}' dependency type not supported";
}
}
// }}}
// {{{ checkPackage()
/**
* Package dependencies check method
*
* @param string $errmsg Empty string, it will be populated with an error message, if any
* @param string $name Name of the package to test
* @param string $req The package version required
* @param string $relation How to compare versions with each other
* @param bool $opt Whether the relationship is optional
*
* @return mixed bool false if no error or the error string
*/
function checkPackage(&$errmsg, $name, $req = null, $relation = 'has',
$opt = false)
{
if (is_string($req) && substr($req, 0, 2) == 'v.') {
$req = substr($req, 2);
}
switch ($relation) {
case 'has':
if (!$this->registry->packageExists($name)) {
if ($opt) {
$errmsg = "package `$name' is recommended to utilize some features.";
return PEAR_DEPENDENCY_MISSING_OPTIONAL;
}
$errmsg = "requires package `$name'";
return PEAR_DEPENDENCY_MISSING;
}
return false;
case 'not':
if ($this->registry->packageExists($name)) {
$errmsg = "conflicts with package `$name'";
return PEAR_DEPENDENCY_CONFLICT;
}
return false;
case 'lt':
case 'le':
case 'eq':
case 'ne':
case 'ge':
case 'gt':
$version = $this->registry->packageInfo($name, 'version');
if (!$this->registry->packageExists($name)
|| !version_compare("$version", "$req", $relation))
{
$code = $this->codeFromRelation($relation, $version, $req, $opt);
if ($opt) {
$errmsg = "package `$name' version " . $this->signOperator($relation) .
" $req is recommended to utilize some features.";
if ($version) {
$errmsg .= " Installed version is $version";
}
return $code;
}
$errmsg = "requires package `$name' " .
$this->signOperator($relation) . " $req";
return $code;
}
return false;
}
$errmsg = "relation '$relation' with requirement '$req' is not supported (name=$name)";
return PEAR_DEPENDENCY_BAD_DEPENDENCY;
}
// }}}
// {{{ checkPackageUninstall()
/**
* Check package dependencies on uninstall
*
* @param string $error The resultant error string
* @param string $warning The resultant warning string
* @param string $name Name of the package to test
*
* @return bool true if there were errors
*/
function checkPackageUninstall(&$error, &$warning, $package)
{
$error = null;
$packages = $this->registry->listPackages();
foreach ($packages as $pkg) {
if ($pkg == $package) {
continue;
}
$deps = $this->registry->packageInfo($pkg, 'release_deps');
if (empty($deps)) {
continue;
}
foreach ($deps as $dep) {
if ($dep['type'] == 'pkg' && strcasecmp($dep['name'], $package) == 0) {
if ($dep['rel'] == 'ne' || $dep['rel'] == 'not') {
continue;
}
if (isset($dep['optional']) && $dep['optional'] == 'yes') {
$warning .= "\nWarning: Package '$pkg' optionally depends on '$package'";
} else {
$error .= "Package '$pkg' depends on '$package'\n";
}
}
}
}
return ($error) ? true : false;
}
// }}}
// {{{ checkExtension()
/**
* Extension dependencies check method
*
* @param string $name Name of the extension to test
* @param string $req_ext_ver Required extension version to compare with
* @param string $relation How to compare versions with eachother
* @param bool $opt Whether the relationship is optional
*
* @return mixed bool false if no error or the error string
*/
function checkExtension(&$errmsg, $name, $req = null, $relation = 'has',
$opt = false)
{
if ($relation == 'not') {
if (extension_loaded($name)) {
$errmsg = "conflicts with PHP extension '$name'";
return PEAR_DEPENDENCY_CONFLICT;
} else {
return false;
}
}
if (!extension_loaded($name)) {
if ($relation == 'not') {
return false;
}
if ($opt) {
$errmsg = "'$name' PHP extension is recommended to utilize some features";
return PEAR_DEPENDENCY_MISSING_OPTIONAL;
}
$errmsg = "'$name' PHP extension is not installed";
return PEAR_DEPENDENCY_MISSING;
}
if ($relation == 'has') {
return false;
}
$code = false;
if (is_string($req) && substr($req, 0, 2) == 'v.') {
$req = substr($req, 2);
}
$ext_ver = phpversion($name);
$operator = $relation;
// Force params to be strings, otherwise the comparation will fail (ex. 0.9==0.90)
if (!version_compare("$ext_ver", "$req", $operator)) {
$errmsg = "'$name' PHP extension version " .
$this->signOperator($operator) . " $req is required";
$code = $this->codeFromRelation($relation, $ext_ver, $req, $opt);
if ($opt) {
$errmsg = "'$name' PHP extension version " . $this->signOperator($operator) .
" $req is recommended to utilize some features";
return $code;
}
}
return $code;
}
// }}}
// {{{ checkOS()
/**
* Operating system dependencies check method
*
* @param string $os Name of the operating system
*
* @return mixed bool false if no error or the error string
*/
function checkOS(&$errmsg, $os)
{
// XXX Fixme: Implement a more flexible way, like
// comma separated values or something similar to PEAR_OS
static $myos;
if (empty($myos)) {
include_once "OS/Guess.php";
$myos = new OS_Guess();
}
// only 'has' relation is currently supported
if ($myos->matchSignature($os)) {
return false;
}
$errmsg = "'$os' operating system not supported";
return PEAR_DEPENDENCY_CONFLICT;
}
// }}}
// {{{ checkPHP()
/**
* PHP version check method
*
* @param string $req which version to compare
* @param string $relation how to compare the version
*
* @return mixed bool false if no error or the error string
*/
function checkPHP(&$errmsg, $req, $relation = 'ge')
{
// this would be a bit stupid, but oh well :)
if ($relation == 'has') {
return false;
}
if ($relation == 'not') {
$errmsg = 'Invalid dependency - "not" is not allowed for php dependencies, ' .
'php cannot conflict with itself';
return PEAR_DEPENDENCY_BAD_DEPENDENCY;
}
if (substr($req, 0, 2) == 'v.') {
$req = substr($req,2, strlen($req) - 2);
}
$php_ver = phpversion();
$operator = $relation;
if (!version_compare("$php_ver", "$req", $operator)) {
$errmsg = "PHP version " . $this->signOperator($operator) .
" $req is required";
return PEAR_DEPENDENCY_CONFLICT;
}
return false;
}
// }}}
// {{{ checkProgram()
/**
* External program check method. Looks for executable files in
* directories listed in the PATH environment variable.
*
* @param string $program which program to look for
*
* @return mixed bool false if no error or the error string
*/
function checkProgram(&$errmsg, $program)
{
// XXX FIXME honor safe mode
$exe_suffix = OS_WINDOWS ? '.exe' : '';
$path_elements = explode(PATH_SEPARATOR, getenv('PATH'));
foreach ($path_elements as $dir) {
$file = $dir . DIRECTORY_SEPARATOR . $program . $exe_suffix;
if (@file_exists($file) && @is_executable($file)) {
return false;
}
}
$errmsg = "'$program' program is not present in the PATH";
return PEAR_DEPENDENCY_MISSING;
}
// }}}
// {{{ checkSAPI()
/**
* SAPI backend check method. Version comparison is not yet
* available here.
*
* @param string $name name of SAPI backend
* @param string $req which version to compare
* @param string $relation how to compare versions (currently
* hardcoded to 'has')
* @return mixed bool false if no error or the error string
*/
function checkSAPI(&$errmsg, $name, $req = null, $relation = 'has')
{
// XXX Fixme: There is no way to know if the user has or
// not other SAPI backends installed than the installer one
$sapi_backend = php_sapi_name();
// Version comparisons not supported, sapi backends don't have
// version information yet.
if ($sapi_backend == $name) {
return false;
}
$errmsg = "'$sapi_backend' SAPI backend not supported";
return PEAR_DEPENDENCY_CONFLICT;
}
// }}}
// {{{ checkZend()
/**
* Zend version check method
*
* @param string $req which version to compare
* @param string $relation how to compare the version
*
* @return mixed bool false if no error or the error string
*/
function checkZend(&$errmsg, $req, $relation = 'ge')
{
if (substr($req, 0, 2) == 'v.') {
$req = substr($req,2, strlen($req) - 2);
}
$zend_ver = zend_version();
$operator = substr($relation,0,2);
if (!version_compare("$zend_ver", "$req", $operator)) {
$errmsg = "Zend version " . $this->signOperator($operator) .
" $req is required";
return PEAR_DEPENDENCY_CONFLICT;
}
return false;
}
// }}}
// {{{ signOperator()
/**
* 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;
}
}
// }}}
// {{{ codeFromRelation()
/**
* Convert relation into corresponding code
*
* @access public
* @param string Relation
* @param string Version
* @param string Requirement
* @param bool Optional dependency indicator
* @return integer
*/
function codeFromRelation($relation, $version, $req, $opt = false)
{
$code = PEAR_DEPENDENCY_BAD_DEPENDENCY;
switch ($relation) {
case 'gt': case 'ge': case 'eq':
// upgrade
$have_major = preg_replace('/\D.*/', '', $version);
$need_major = preg_replace('/\D.*/', '', $req);
if ($need_major > $have_major) {
$code = $opt ? PEAR_DEPENDENCY_UPGRADE_MAJOR_OPTIONAL :
PEAR_DEPENDENCY_UPGRADE_MAJOR;
} else {
$code = $opt ? PEAR_DEPENDENCY_UPGRADE_MINOR_OPTIONAL :
PEAR_DEPENDENCY_UPGRADE_MINOR;
}
break;
case 'lt': case 'le': case 'ne':
$code = $opt ? PEAR_DEPENDENCY_CONFLICT_OPTIONAL :
PEAR_DEPENDENCY_CONFLICT;
break;
}
return $code;
}
// }}}
}
?>

View File

@@ -1,348 +0,0 @@
<?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. |
// +----------------------------------------------------------------------+
// | Authors: Tomas V.V.Cox <cox@idecnet.com> |
// | |
// +----------------------------------------------------------------------+
//
// $Id$
/**
Experimental dependencies database handling functions (not yet in production)
<?php
include './DependencyDB.php';
PEAR::setErrorHandling(PEAR_ERROR_DIE);
$dep = PEAR_DependencyDB::singleton('./test.deps', '/home/cox/www/include/pear');
//$dep->rebuildDB();
$a = $dep->checkAction('uninstall', 'net_socket');
print_r($a);
?>
**/
require_once 'PEAR.php';
require_once 'PEAR/Registry.php';
require_once 'PEAR/Dependency.php';
class PEAR_DependencyDB extends PEAR
{
// {{{ properties
var $pear_reg = false;
var $pear_dep = false;
var $depdb_file = false;
var $lockfile = false;
var $lock_fp = false;
var $depdb_version = '1.0';
// }}}
// {{{ & singleton()
function &singleton($depdb_file, $reg_file)
{
$obj = new PEAR_DependencyDB;
$reg = &new PEAR_Registry($reg_file);
$obj->pear_reg = $reg;
$obj->lockfile = $reg->lockfile;
$obj->pear_dep = new PEAR_Dependency($reg);
$obj->depdb_file = $depdb_file;
$obj->assertDepsDB();
return $obj;
}
// }}}
// {{{ assertDepsDB()
function assertDepsDB()
{
if (!is_file($this->depdb_file)) {
$this->rebuildDB();
} else {
$depdb = $this->_getDepDB();
// Datatype format has been changed, rebuild the Deps DB
if ($depdb['depdb_version'] != $this->depdb_version) {
$this->rebuildDB();
}
}
}
// }}}
// {{{ _lock()
function _lock($mode = LOCK_EX)
{
if (!eregi('Windows 9', php_uname())) {
if ($mode != LOCK_UN && is_resource($this->lock_fp)) {
// 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 (@!is_file($this->lockfile)) {
touch($this->lockfile);
}
$open_mode = 'r';
}
$this->lock_fp = @fopen($this->lockfile, $open_mode);
if (!is_resource($this->lock_fp)) {
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 $this->raiseError("could not acquire $str lock ($this->lockfile)");
}
}
return true;
}
// }}}
// {{{ _unlock()
function _unlock()
{
$ret = $this->_lock(LOCK_UN);
$this->lock_fp = null;
return $ret;
}
// }}}
// {{{ rebuildDepsFile()
function rebuildDB()
{
$depdb = array('depdb_version' => $this->depdb_version);
$packages = $this->pear_reg->listPackages();
foreach ($packages as $package) {
$deps = $this->pear_reg->packageInfo($package, 'release_deps');
$this->setPackageDep($depdb, $package, $deps);
}
print_r($depdb);
$error = $this->_writeDepDB($depdb);
if (PEAR::isError($error)) {
return $error;
}
return true;
}
// }}}
// {{{ & _getDepDB()
function &_getDepDB()
{
if (!$fp = fopen($this->depdb_file, 'r')) {
$err = $this->raiseError("Could not open dependencies file `".$this->depdb_file."'");
return $err;
}
$data = unserialize(fread($fp, filesize($this->depdb_file)));
fclose($fp);
return $data;
}
// }}}
// {{{ _writeDepDB()
function _writeDepDB(&$deps)
{
if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
return $e;
}
if (!$fp = fopen($this->depdb_file, 'wb')) {
$this->_unlock();
return $this->raiseError("Could not open dependencies file `".$this->depfile."' for writting");
}
fwrite($fp, serialize($deps));
fclose($fp);
$this->_unlock();
return true;
}
// }}}
/*
// {{{ removePackageDep()
function removePackageDep($package)
{
$data = &$this->_depGetDepDB();
if (PEAR::isError($data)) {
return $data;
}
// Other packages depends on this package, can't be removed
if (isset($data['deps'][$package])) {
return $data['deps'][$package];
}
// The package depends on others, remove those dependencies
if (isset($data['pkgs'][$package])) {
foreach ($data['pkgs'][$package] as $pkg => $key) {
// remove the dependency
unset($data['deps'][$pkg][$key]);
// if no more dependencies, remove the subject too
if (!count($data['deps'][$pkg])) {
unset($data['deps'][$pkg]);
}
}
// remove the package from the index list
unset($data['pkgs'][$package]);
}
return $this->_depWriteDepDB();
}
// }}}
*/
// {{{ checkAction()
function checkAction($action, $package, $new_version = null)
{
$depdb = &$this->_getDepDB();
if (PEAR::isError($depdb)) {
return $depdb;
}
$fails = '';
switch($action) {
case 'uninstall':
// Other packages depends on this package, can't be removed
if (isset($depdb['deps'][$package])) {
foreach ($depdb['deps'][$package] as $dep) {
if (!$dep['optional']) {
$fails .= "Package '" . $dep['depend'] . "' depends on '$package'\n";
}
}
return $fails;
}
return true;
case 'install':
case 'upgrade':
// Other packages depend on this package, check deps. Ex:
// <dep type='pkg' rel='lt' version='1.0'>Foo</dep> and we are trying to
// update Foo to version 2.0
if (isset($depdb['deps'][$package])) {
foreach ($depdb['deps'][$package] as $dep) {
$relation = $dep['rel'];
if ($relation == 'not') {
$fails .= "Package '" . $dep['depend'] . "' conflicts with '$package'\n";
} elseif ($relation != 'has' && $new_version !== null) {
if (!version_compare("$new_version", "{$dep['version']}", $relation) &&
!$dep['optional']) {
$fails .= "Package '" . $dep['depend'] . "' requires ".
"$package " . $this->pear_dep->signOperator($relation) .
" " . $dep['version'];
}
}
}
if (isset($fails)) {
return $fails;
}
}
return true;
}
}
// }}}
// {{{ commitAction()
function commitAction($action, $package)
{
}
// }}}
// {{{ setPackageDep()
/**
* Update or insert a the dependencies of a package, prechecking
* that the package won't break any dependency in the process
The data structure is as follows:
$dep_db = array(
// Other packages depends on this packages
'deps' => array(
'Package Name' => array(
0 => array(
// This package depends on 'Package Name'
'depend' => 'Package',
// Which version 'Package' needs of 'Package Name'
'version' => '1.0',
// The requirement (version_compare() operator)
'rel' => 'ge',
// whether the dependency is optional
'optional' => true/false
),
),
)
// This packages are dependant on other packages
'pkgs' => array(
'Package Dependant' => array(
// This is a index list with paths over the 'deps' array for quick
// searching things like "what dependecies has this package?"
// $dep_db['deps']['Package Name'][3]
'Package Name' => 3 // key in array ['deps']['Package Name']
),
)
)
Note: It only supports package dependencies no other type
*/
function setPackageDep(&$data, $package, $rel_deps = array())
{
// This package has no dependencies
if (!is_array($rel_deps) || !count($rel_deps)) {
return true;
}
// The package depends on others, register that
foreach ($rel_deps as $dep) {
// We only support deps of type 'pkg's
if ($dep && $dep['type'] == 'pkg' && isset($dep['name'])) {
$dep_name = strtolower($dep['name']);
$write = array('depend' => $package,
'rel' => $dep['rel']);
if ($dep['rel'] != 'has') {
$write['version'] = $dep['version'];
}
if (isset($dep['optional']) && $dep['optional'] == 'yes') {
$write['optional'] = true;
} else {
$write['optional'] = false;
}
settype($data['deps'][$dep_name], 'array');
// The dependency already exists, update it
if (isset($data['pkgs'][$package][$dep_name])) {
$key = $data['pkgs'][$package][$dep_name];
$data['deps'][$dep_name][$key] = $write;
// New dependency, insert it
} else {
$key = count($data['deps'][$dep_name]);
$data['deps'][$dep_name][$key] = $write;
settype($data['pkgs'][$package], 'array');
$data['pkgs'][$package][$dep_name] = $key;
}
}
}
return true;
}
// }}}
}
?>

View File

@@ -1,680 +0,0 @@
<?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. |
// +----------------------------------------------------------------------+
// | Authors: Stig Bakken <ssb@php.net> |
// | Tomas V.V.Cox <cox@idecnet.com> |
// | Martin Jansen <mj@php.net> |
// +----------------------------------------------------------------------+
//
// $Id$
require_once 'PEAR/Common.php';
require_once 'PEAR/Registry.php';
require_once 'PEAR/Dependency.php';
require_once 'PEAR/Remote.php';
require_once 'System.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 PEAR packages and maintain the
* installed package database.
*
* @since PEAR 1.4
* @author Greg Beaver <cellog@php.net>
*/
class PEAR_Downloader extends PEAR_Common
{
/**
* @var PEAR_Config
* @access private
*/
var $_config;
/**
* @var PEAR_Registry
* @access private
*/
var $_registry;
/**
* @var PEAR_Remote
* @access private
*/
var $_remote;
/**
* Preferred Installation State (snapshot, devel, alpha, beta, stable)
* @var string|null
* @access private
*/
var $_preferredState;
/**
* Options from command-line passed to Install.
*
* Recognized options:<br />
* - 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
* @see PEAR_Command_Install
* @access private
* @var array
*/
var $_options;
/**
* Downloaded Packages after a call to download().
*
* Format of each entry:
*
* <code>
* array('pkg' => 'package_name', 'file' => '/path/to/local/file',
* 'info' => array() // parsed package.xml
* );
* </code>
* @access private
* @var array
*/
var $_downloadedPackages = array();
/**
* 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:
*
* <pre>
* array('package_name1' => parsed package.xml, 'package_name2' => parsed package.xml,
* );
* </pre>
* @access private
* @var array
*/
var $_toDownload = array();
/**
* Array of every package installed, with names lower-cased.
*
* Format:
* <code>
* array('package1' => 0, 'package2' => 1, );
* </code>
* @var array
*/
var $_installed = array();
/**
* @var array
* @access private
*/
var $_errorStack = array();
// {{{ PEAR_Downloader()
function PEAR_Downloader(&$ui, $options, &$config)
{
$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;
}
$php_dir = $this->_config->get('php_dir');
if (isset($this->_options['installroot'])) {
if (substr($this->_options['installroot'], -1) == DIRECTORY_SEPARATOR) {
$this->_options['installroot'] = substr($this->_options['installroot'], 0, -1);
}
$php_dir = $this->_prependPath($php_dir, $this->_options['installroot']);
}
$this->_registry = &new PEAR_Registry($php_dir);
$this->_remote = &new PEAR_Remote($config);
if (isset($this->_options['alldeps']) || isset($this->_options['onlyreqdeps'])) {
$this->_installed = $this->_registry->listPackages();
array_walk($this->_installed, create_function('&$v,$k','$v = strtolower($v);'));
$this->_installed = array_flip($this->_installed);
}
parent::PEAR_Common();
}
// }}}
// {{{ configSet()
function configSet($key, $value, $layer = 'user')
{
$this->_config->set($key, $value, $layer);
$this->_preferredState = $this->_config->get('preferred_state');
if (!$this->_preferredState) {
// don't inadvertantly use a non-set preferred_state
$this->_preferredState = null;
}
}
// }}}
// {{{ setOptions()
function setOptions($options)
{
$this->_options = $options;
}
// }}}
// {{{ _downloadFile()
/**
* @param string filename to download
* @param string version/state
* @param string original value passed to command-line
* @param string|null preferred state (snapshot/devel/alpha/beta/stable)
* Defaults to configuration preferred state
* @return null|PEAR_Error|string
* @access private
*/
function _downloadFile($pkgfile, $version, $origpkgfile, $state = null)
{
if (is_null($state)) {
$state = $this->_preferredState;
}
// {{{ check the package filename, and whether it's already installed
$need_download = false;
if (preg_match('#^(http|ftp)://#', $pkgfile)) {
$need_download = true;
} elseif (!@is_file($pkgfile)) {
if ($this->validPackageName($pkgfile)) {
if ($this->_registry->packageExists($pkgfile)) {
if (empty($this->_options['upgrade']) && empty($this->_options['force'])) {
$errors[] = "$pkgfile already installed";
return;
}
}
$pkgfile = $this->getPackageDownloadUrl($pkgfile, $version);
$need_download = true;
} else {
if (strlen($pkgfile)) {
$errors[] = "Could not open the package file: $pkgfile";
} else {
$errors[] = "No package file given";
}
return;
}
}
// }}}
// {{{ Download package -----------------------------------------------
if ($need_download) {
$downloaddir = $this->_config->get('download_dir');
if (empty($downloaddir)) {
if (PEAR::isError($downloaddir = System::mktemp('-d'))) {
return $downloaddir;
}
$this->log(3, '+ tmp dir created at ' . $downloaddir);
}
$callback = $this->ui ? array(&$this, '_downloadCallback') : null;
$this->pushErrorHandling(PEAR_ERROR_RETURN);
$file = $this->downloadHttp($pkgfile, $this->ui, $downloaddir, $callback);
$this->popErrorHandling();
if (PEAR::isError($file)) {
if ($this->validPackageName($origpkgfile)) {
if (!PEAR::isError($info = $this->_remote->call('package.info',
$origpkgfile))) {
if (!count($info['releases'])) {
return $this->raiseError('Package ' . $origpkgfile .
' has no releases');
} else {
return $this->raiseError('No releases of preferred state "'
. $state . '" exist for package ' . $origpkgfile .
'. Use ' . $origpkgfile . '-state to install another' .
' state (like ' . $origpkgfile .'-beta)',
PEAR_INSTALLER_ERROR_NO_PREF_STATE);
}
} else {
return $pkgfile;
}
} else {
return $this->raiseError($file);
}
}
$pkgfile = $file;
}
// }}}
return $pkgfile;
}
// }}}
// {{{ getPackageDownloadUrl()
function getPackageDownloadUrl($package, $version = null)
{
if ($version) {
$package .= "-$version";
}
if ($this === null || $this->_config === null) {
$package = "http://pear.php.net/get/$package";
} else {
$package = "http://" . $this->_config->get('master_server') .
"/get/$package";
}
if (!extension_loaded("zlib")) {
$package .= '?uncompress=yes';
}
return $package;
}
// }}}
// {{{ extractDownloadFileName($pkgfile, &$version)
function extractDownloadFileName($pkgfile, &$version)
{
if (@is_file($pkgfile)) {
return $pkgfile;
}
// regex defined in Common.php
if (preg_match(PEAR_COMMON_PACKAGE_DOWNLOAD_PREG, $pkgfile, $m)) {
$version = (isset($m[3])) ? $m[3] : null;
return $m[1];
}
$version = null;
return $pkgfile;
}
// }}}
// }}}
// {{{ getDownloadedPackages()
/**
* Retrieve a list of downloaded packages after a call to {@link download()}.
*
* Also resets the list of downloaded packages.
* @return array
*/
function getDownloadedPackages()
{
$ret = $this->_downloadedPackages;
$this->_downloadedPackages = array();
$this->_toDownload = array();
return $ret;
}
// }}}
// {{{ download()
/**
* Download any files and their dependencies, if necessary
*
* BC-compatible method name
* @param array a mixed list of package names, local files, or package.xml
*/
function download($packages)
{
return $this->doDownload($packages);
}
// }}}
// {{{ doDownload()
/**
* Download any files and their dependencies, if necessary
*
* @param array a mixed list of package names, local files, or package.xml
*/
function doDownload($packages)
{
$mywillinstall = array();
$state = $this->_preferredState;
// {{{ download files in this list if necessary
foreach($packages as $pkgfile) {
$need_download = false;
if (!is_file($pkgfile)) {
if (preg_match('#^(http|ftp)://#', $pkgfile)) {
$need_download = true;
}
$pkgfile = $this->_downloadNonFile($pkgfile);
if (PEAR::isError($pkgfile)) {
return $pkgfile;
}
if ($pkgfile === false) {
continue;
}
} // end is_file()
$tempinfo = $this->infoFromAny($pkgfile);
if ($need_download) {
$this->_toDownload[] = $tempinfo['package'];
}
if (isset($this->_options['alldeps']) || isset($this->_options['onlyreqdeps'])) {
// ignore dependencies if there are any errors
if (!PEAR::isError($tempinfo)) {
$mywillinstall[strtolower($tempinfo['package'])] = @$tempinfo['release_deps'];
}
}
$this->_downloadedPackages[] = array('pkg' => $tempinfo['package'],
'file' => $pkgfile, 'info' => $tempinfo);
} // end foreach($packages)
// }}}
// {{{ extract dependencies from downloaded files and then download
// them if necessary
if (isset($this->_options['alldeps']) || isset($this->_options['onlyreqdeps'])) {
$deppackages = array();
foreach ($mywillinstall as $package => $alldeps) {
if (!is_array($alldeps)) {
// there are no dependencies
continue;
}
$fail = false;
foreach ($alldeps as $info) {
if ($info['type'] != 'pkg') {
continue;
}
$ret = $this->_processDependency($package, $info, $mywillinstall);
if ($ret === false) {
continue;
}
if ($ret === 0) {
$fail = true;
continue;
}
if (PEAR::isError($ret)) {
return $ret;
}
$deppackages[] = $ret;
} // foreach($alldeps
if ($fail) {
$deppackages = array();
}
}
if (count($deppackages)) {
$this->doDownload($deppackages);
}
} // }}} if --alldeps or --onlyreqdeps
}
// }}}
// {{{ _downloadNonFile($pkgfile)
/**
* @return false|PEAR_Error|string false if loop should be broken out of,
* string if the file was downloaded,
* PEAR_Error on exception
* @access private
*/
function _downloadNonFile($pkgfile)
{
$origpkgfile = $pkgfile;
$state = null;
$pkgfile = $this->extractDownloadFileName($pkgfile, $version);
if (preg_match('#^(http|ftp)://#', $pkgfile)) {
return $this->_downloadFile($pkgfile, $version, $origpkgfile);
}
if (!$this->validPackageName($pkgfile)) {
return $this->raiseError("Package name '$pkgfile' not valid");
}
// ignore packages that are installed unless we are upgrading
$curinfo = $this->_registry->packageInfo($pkgfile);
if ($this->_registry->packageExists($pkgfile)
&& empty($this->_options['upgrade']) && empty($this->_options['force'])) {
$this->log(0, "Package '{$curinfo['package']}' already installed, skipping");
return false;
}
if (in_array($pkgfile, $this->_toDownload)) {
return false;
}
$releases = $this->_remote->call('package.info', $pkgfile, 'releases', true);
if (!count($releases)) {
return $this->raiseError("No releases found for package '$pkgfile'");
}
// Want a specific version/state
if ($version !== null) {
// Passed Foo-1.2
if ($this->validPackageVersion($version)) {
if (!isset($releases[$version])) {
return $this->raiseError("No release with version '$version' found for '$pkgfile'");
}
// Passed Foo-alpha
} elseif (in_array($version, $this->getReleaseStates())) {
$state = $version;
$version = 0;
foreach ($releases as $ver => $inf) {
if ($inf['state'] == $state && version_compare("$version", "$ver") < 0) {
$version = $ver;
break;
}
}
if ($version == 0) {
return $this->raiseError("No release with state '$state' found for '$pkgfile'");
}
// invalid suffix passed
} else {
return $this->raiseError("Invalid suffix '-$version', be sure to pass a valid PEAR ".
"version number or release state");
}
// Guess what to download
} else {
$states = $this->betterStates($this->_preferredState, true);
$possible = false;
$version = 0;
$higher_version = 0;
$prev_hi_ver = 0;
foreach ($releases as $ver => $inf) {
if (in_array($inf['state'], $states) && version_compare("$version", "$ver") < 0) {
$version = $ver;
break;
} else {
$ver = (string)$ver;
if (version_compare($prev_hi_ver, $ver) < 0) {
$prev_hi_ver = $higher_version = $ver;
}
}
}
if ($version === 0 && !isset($this->_options['force'])) {
return $this->raiseError('No release with state equal to: \'' . implode(', ', $states) .
"' found for '$pkgfile'");
} elseif ($version === 0) {
$this->log(0, "Warning: $pkgfile is state '" . $releases[$higher_version]['state'] . "' which is less stable " .
"than state '$this->_preferredState'");
}
}
// Check if we haven't already the version
if (empty($this->_options['force']) && !is_null($curinfo)) {
if ($curinfo['version'] == $version) {
$this->log(0, "Package '{$curinfo['package']}-{$curinfo['version']}' already installed, skipping");
return false;
} elseif (version_compare("$version", "{$curinfo['version']}") < 0) {
$this->log(0, "Package '{$curinfo['package']}' version '{$curinfo['version']}' " .
" is installed and {$curinfo['version']} is > requested '$version', skipping");
return false;
}
}
$this->_toDownload[] = $pkgfile;
return $this->_downloadFile($pkgfile, $version, $origpkgfile, $state);
}
// }}}
// {{{ _processDependency($package, $info, $mywillinstall)
/**
* Process a dependency, download if necessary
* @param array dependency information from PEAR_Remote call
* @param array packages that will be installed in this iteration
* @return false|string|PEAR_Error
* @access private
* @todo Add test for relation 'lt'/'le' -> make sure that the dependency requested is
* in fact lower than the required value. This will be very important for BC dependencies
*/
function _processDependency($package, $info, $mywillinstall)
{
$state = $this->_preferredState;
if (!isset($this->_options['alldeps']) && isset($info['optional']) &&
$info['optional'] == 'yes') {
// skip optional deps
$this->log(0, "skipping Package '$package' optional dependency '$info[name]'");
return false;
}
// {{{ get releases
$releases = $this->_remote->call('package.info', $info['name'], 'releases', true);
if (PEAR::isError($releases)) {
return $releases;
}
if (!count($releases)) {
if (!isset($this->_installed[strtolower($info['name'])])) {
$this->pushError("Package '$package' dependency '$info[name]' ".
"has no releases");
}
return false;
}
$found = false;
$save = $releases;
while(count($releases) && !$found) {
if (!empty($state) && $state != 'any') {
list($release_version, $release) = each($releases);
if ($state != $release['state'] &&
!in_array($release['state'], $this->betterStates($state)))
{
// drop this release - it ain't stable enough
array_shift($releases);
} else {
$found = true;
}
} else {
$found = true;
}
}
if (!count($releases) && !$found) {
$get = array();
foreach($save as $release) {
$get = array_merge($get,
$this->betterStates($release['state'], true));
}
$savestate = array_shift($get);
$this->pushError( "Release for '$package' dependency '$info[name]' " .
"has state '$savestate', requires '$state'");
return 0;
}
if (in_array(strtolower($info['name']), $this->_toDownload) ||
isset($mywillinstall[strtolower($info['name'])])) {
// skip upgrade check for packages we will install
return false;
}
if (!isset($this->_installed[strtolower($info['name'])])) {
// check to see if we can install the specific version required
if ($info['rel'] == 'eq') {
return $info['name'] . '-' . $info['version'];
}
// skip upgrade check for packages we don't have installed
return $info['name'];
}
// }}}
// {{{ see if a dependency must be upgraded
$inst_version = $this->_registry->packageInfo($info['name'], 'version');
if (!isset($info['version'])) {
// this is a rel='has' dependency, check against latest
if (version_compare($release_version, $inst_version, 'le')) {
return false;
} else {
return $info['name'];
}
}
if (version_compare($info['version'], $inst_version, 'le')) {
// installed version is up-to-date
return false;
}
return $info['name'];
}
// }}}
// {{{ _downloadCallback()
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 (!($bytes % 10240)) {
$this->log(1, '.', false);
}
$bytes += $params;
break;
case 'start':
$this->log(1, "Starting to download {$params[0]} (".number_format($params[1], 0, '', ',')." bytes)");
break;
}
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)) {
$path = $prepend . substr($path, 2);
} else {
$path = $prepend . $path;
}
}
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];
}
$this->_errorStack = array();
return $msgs;
}
// }}}
}
// }}}
?>

View File

@@ -1,981 +0,0 @@
<?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. |
// +----------------------------------------------------------------------+
// | Author: Gregory Beaver <cellog@php.net> |
// | |
// +----------------------------------------------------------------------+
//
// $Id$
/**
* Error Stack Implementation
*
* This is an incredibly simple implementation of a very complex error handling
* facility. It contains the ability
* to track multiple errors from multiple packages simultaneously. In addition,
* it can track errors of many levels, save data along with the error, context
* information such as the exact file, line number, class and function that
* generated the error, and if necessary, it can raise a traditional PEAR_Error.
* It has built-in support for PEAR::Log, to log errors as they occur
*
* Since version 0.2alpha, it is also possible to selectively ignore errors,
* through the use of an error callback, see {@link pushCallback()}
*
* Since version 0.3alpha, it is possible to specify the exception class
* returned from {@link push()}
*
* 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
* @author Greg Beaver <cellog@php.net>
* @version PEAR1.3.2 (beta)
* @package PEAR_ErrorStack
* @category Debugging
* @license http://www.php.net/license/3_0.txt PHP License v3.0
*/
/**
* Singleton storage
*
* Format:
* <pre>
* array(
* 'package1' => PEAR_ErrorStack object,
* 'package2' => PEAR_ErrorStack object,
* ...
* )
* </pre>
* @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:
* <code>
* // global error stack
* $global_stack = &PEAR_ErrorStack::singleton('MyPackage');
* // local error stack
* $local_stack = new PEAR_ErrorStack('MyPackage');
* </code>
* @copyright 2004 Gregory Beaver
* @package PEAR_ErrorStack
* @license http://www.php.net/license/3_0.txt PHP License
*/
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);
}
return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package] =
&new $stackClass($package, $msgCallback, $contextCallback, $throwPEAR_Error);
}
/**
* 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 '<br />';
} 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|Exception
* if compatibility mode is on, a PEAR_Error is also
* thrown. If the class Exception exists, then one
* is returned to allow code like:
* <code>
* throw ($stack->push(MY_ERROR_CODE, 'error', array('username' => 'grob')));
* </code>
*
* The errorData property of the exception class will be set to the array
* that would normally be returned. If a PEAR_Error is returned, the userinfo
* property is set to the array
*
* Otherwise, an array is returned in this format:
* <code>
* array(
* 'code' => $code,
* 'params' => $params,
* 'package' => $this->_package,
* 'level' => $level,
* 'time' => time(),
* 'context' => $context,
* 'message' => $msg,
* //['repackage' => $err] repackaged error array/Exception class
* );
* </code>
*/
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,
);
// set up the error message, if necessary
if ($this->_msgCallback) {
$msg = call_user_func_array($this->_msgCallback,
array(&$this, $err));
$err['message'] = $msg;
}
if ($repackage) {
$err['repackage'] = $repackage;
}
$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);
$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|null|Exception
* if compatibility mode is on, a PEAR_Error is also
* thrown. If the class Exception exists, then one
* is returned to allow code like:
* <code>
* throw ($stack->push(MY_ERROR_CODE, 'error', array('username' => 'grob')));
* </code>
* @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()
{
return @array_shift($this->_errors);
}
/**
* 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+)\) : (.*?)$;', $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:
*
* <code>
* $stack->push(ERROR_CODE, 'error', array(), 'server error 500');
* </code>
*
* 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 (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:
* <pre>
* array(error code => 'message template',...)
* </pre>
*
* 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'));
?>

View File

@@ -1,359 +0,0 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
// +----------------------------------------------------------------------+
// | PEAR_Exception |
// +----------------------------------------------------------------------+
// | Copyright (c) 2004 The PEAR 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 at through the world-wide-web at |
// | 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. |
// +----------------------------------------------------------------------+
// | Authors: Tomas V.V.Cox <cox@idecnet.com> |
// | Hans Lellelid <hans@velum.net> |
// | Bertrand Mansion <bmansion@mamasam.com> |
// | Greg Beaver <cellog@php.net> |
// +----------------------------------------------------------------------+
//
// $Id$
/**
* Base PEAR_Exception Class
*
* WARNING: This code should be considered stable, but the API is
* subject to immediate and drastic change, so API stability is
* at best alpha
*
* 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
*
* <code>
* 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;
* }
* </code>
*
* @since PHP 5
* @package PEAR
* @version $Revision$
* @author Tomas V.V.Cox <cox@idecnet.com>
* @author Hans Lellelid <hans@velum.net>
* @author Bertrand Mansion <bmansion@mamasam.com>
*
*/
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, array $causes);
* PEAR_Exception(string $message, array $causes, int $code);
*/
public function __construct($message, $p2 = null, $p3 = null)
{
if (is_int($p2)) {
$code = $p2;
$this->cause = null;
} elseif ($p2 instanceof Exception || is_array($p2)) {
$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:
* <pre>
* array('name' => $name, 'context' => array(...))
* </pre>
* @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'];
}
}
if ($this->cause instanceof PEAR_Exception) {
$this->cause->getCauseMessage($causes);
}
if (is_array($this->cause)) {
foreach ($this->cause as $cause) {
if ($cause instanceof PEAR_Exception) {
$cause->getCauseMessage($causes);
} 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 = '<table border="1" cellspacing="0">' . "\n";
foreach ($causes as $i => $cause) {
$html .= '<tr><td colspan="3" bgcolor="#ff9999">'
. str_repeat('-', $i) . ' <b>' . $cause['class'] . '</b>: '
. htmlspecialchars($cause['message']) . ' in <b>' . $cause['file'] . '</b> '
. 'on line <b>' . $cause['line'] . '</b>'
. "</td></tr>\n";
}
$html .= '<tr><td colspan="3" bgcolor="#aaaaaa" align="center"><b>Exception trace</b></td></tr>' . "\n"
. '<tr><td align="center" bgcolor="#cccccc" width="20"><b>#</b></td>'
. '<td align="center" bgcolor="#cccccc"><b>Function</b></td>'
. '<td align="center" bgcolor="#cccccc"><b>Location</b></td></tr>' . "\n";
foreach ($trace as $k => $v) {
$html .= '<tr><td align="center">' . $k . '</td>'
. '<td>';
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 .= '&hellip;';
$args[] = "'" . $str . "'";
}
}
}
$html .= '(' . implode(', ',$args) . ')'
. '</td>'
. '<td>' . $v['file'] . ':' . $v['line'] . '</td></tr>' . "\n";
}
$html .= '<tr><td align="center">' . ($k+1) . '</td>'
. '<td>{main}</td>'
. '<td>&nbsp;</td></tr>' . "\n"
. '</table>';
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();
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@@ -1,165 +0,0 @@
<?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. |
// +----------------------------------------------------------------------+
// | Authors: Stig Bakken <ssb@php.net> |
// | Tomas V.V.Cox <cox@idecnet.com> |
// +----------------------------------------------------------------------+
//
// $Id$
require_once 'PEAR/Common.php';
require_once 'System.php';
/**
* Administration class used to make a PEAR release tarball.
*
* TODO:
* - add an extra param the dir where to place the created package
*
* @since PHP 4.0.2
* @author Stig Bakken <ssb@php.net>
*/
class PEAR_Packager extends PEAR_Common
{
// {{{ constructor
function PEAR_Packager()
{
parent::PEAR_Common();
}
// }}}
// {{{ destructor
function _PEAR_Packager()
{
parent::_PEAR_Common();
}
// }}}
// {{{ package()
function package($pkgfile = null, $compress = true)
{
// {{{ validate supplied package.xml file
if (empty($pkgfile)) {
$pkgfile = 'package.xml';
}
// $this->pkginfo gets populated inside
$pkginfo = $this->infoFromDescriptionFile($pkgfile);
if (PEAR::isError($pkginfo)) {
return $this->raiseError($pkginfo);
}
$pkgdir = dirname(realpath($pkgfile));
$pkgfile = basename($pkgfile);
$errors = $warnings = array();
$this->validatePackageInfo($pkginfo, $errors, $warnings, $pkgdir);
foreach ($warnings as $w) {
$this->log(1, "Warning: $w");
}
foreach ($errors as $e) {
$this->log(0, "Error: $e");
}
if (sizeof($errors) > 0) {
return $this->raiseError('Errors in package');
}
// }}}
$pkgver = $pkginfo['package'] . '-' . $pkginfo['version'];
// {{{ Create the package file list
$filelist = array();
$i = 0;
foreach ($pkginfo['filelist'] as $fname => $atts) {
$file = $pkgdir . DIRECTORY_SEPARATOR . $fname;
if (!file_exists($file)) {
return $this->raiseError("File does not exist: $fname");
} else {
$filelist[$i++] = $file;
if (empty($pkginfo['filelist'][$fname]['md5sum'])) {
$md5sum = md5_file($file);
$pkginfo['filelist'][$fname]['md5sum'] = $md5sum;
}
$this->log(2, "Adding file $fname");
}
}
// }}}
// {{{ regenerate package.xml
$new_xml = $this->xmlFromInfo($pkginfo);
if (PEAR::isError($new_xml)) {
return $this->raiseError($new_xml);
}
if (!($tmpdir = System::mktemp(array('-d')))) {
return $this->raiseError("PEAR_Packager: mktemp failed");
}
$newpkgfile = $tmpdir . DIRECTORY_SEPARATOR . 'package.xml';
$np = @fopen($newpkgfile, 'wb');
if (!$np) {
return $this->raiseError("PEAR_Packager: unable to rewrite $pkgfile as $newpkgfile");
}
fwrite($np, $new_xml);
fclose($np);
// }}}
// {{{ TAR the Package -------------------------------------------
$ext = $compress ? '.tgz' : '.tar';
$dest_package = getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext;
$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($newpkgfile), '', $tmpdir);
if (PEAR::isError($ok)) {
return $this->raiseError($ok);
} elseif (!$ok) {
return $this->raiseError('PEAR_Packager: tarball creation failed');
}
// ----- Add the content of the package
if (!$tar->addModify($filelist, $pkgver, $pkgdir)) {
return $this->raiseError('PEAR_Packager: tarball creation failed');
}
$this->log(1, "Package $dest_package done");
if (file_exists("$pkgdir/CVS/Root")) {
$cvsversion = preg_replace('/[^a-z0-9]/i', '_', $pkginfo['version']);
$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)");
}
// }}}
return $dest_package;
}
// }}}
}
// {{{ md5_file() utility function
if (!function_exists('md5_file')) {
function md5_file($file) {
if (!$fd = @fopen($file, 'r')) {
return false;
}
$md5 = md5(fread($fd, filesize($file)));
fclose($fd);
return $md5;
}
}
// }}}
?>

View File

@@ -1,538 +0,0 @@
<?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. |
// +----------------------------------------------------------------------+
// | Author: Stig Bakken <ssb@php.net> |
// | Tomas V.V.Cox <cox@idecnet.com> |
// | |
// +----------------------------------------------------------------------+
//
// $Id$
/*
TODO:
- Transform into singleton()
- Add application level lock (avoid change the registry from the cmdline
while using the GTK interface, for ex.)
*/
require_once "System.php";
require_once "PEAR.php";
define('PEAR_REGISTRY_ERROR_LOCK', -2);
define('PEAR_REGISTRY_ERROR_FORMAT', -3);
define('PEAR_REGISTRY_ERROR_FILE', -4);
/**
* Administration class used to maintain the installed package database.
*/
class PEAR_Registry extends PEAR
{
// {{{ properties
/** Directory where registry files are stored.
* @var string
*/
var $statedir = '';
/** File where the file map is stored
* @var string
*/
var $filemap = '';
/** 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();
// }}}
// {{{ constructor
/**
* PEAR_Registry constructor.
*
* @param string (optional) PEAR install directory (for .php files)
*
* @access public
*/
function PEAR_Registry($pear_install_dir = PEAR_INSTALL_DIR)
{
parent::PEAR();
$ds = DIRECTORY_SEPARATOR;
$this->install_dir = $pear_install_dir;
$this->statedir = $pear_install_dir.$ds.'.registry';
$this->filemap = $pear_install_dir.$ds.'.filemap';
$this->lockfile = $pear_install_dir.$ds.'.lock';
// XXX Compatibility code should be removed in the future
// rename all registry files if any to lowercase
if (!OS_WINDOWS && $handle = @opendir($this->statedir)) {
$dest = $this->statedir . DIRECTORY_SEPARATOR;
while (false !== ($file = readdir($handle))) {
if (preg_match('/^.*[A-Z].*\.reg$/', $file)) {
rename($dest . $file, $dest . strtolower($file));
}
}
closedir($handle);
}
if (!file_exists($this->filemap)) {
$this->rebuildFileMap();
}
}
// }}}
// {{{ destructor
/**
* PEAR_Registry destructor. Makes sure no locks are forgotten.
*
* @access private
*/
function _PEAR_Registry()
{
parent::_PEAR();
if (is_resource($this->lock_fp)) {
$this->_unlock();
}
}
// }}}
// {{{ _assertStateDir()
/**
* 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()
{
if (!@is_dir($this->statedir)) {
if (!System::mkdir(array('-p', $this->statedir))) {
return $this->raiseError("could not create directory '{$this->statedir}'");
}
}
return true;
}
// }}}
// {{{ _packageFileName()
/**
* Get the name of the file where data for a given package is stored.
*
* @param string package name
*
* @return string registry file name
*
* @access public
*/
function _packageFileName($package)
{
return $this->statedir . DIRECTORY_SEPARATOR . strtolower($package) . '.reg';
}
// }}}
// {{{ _openPackageFile()
function _openPackageFile($package, $mode)
{
$this->_assertStateDir();
$file = $this->_packageFileName($package);
$fp = @fopen($file, $mode);
if (!$fp) {
return null;
}
return $fp;
}
// }}}
// {{{ _closePackageFile()
function _closePackageFile($fp)
{
fclose($fp);
}
// }}}
// {{{ rebuildFileMap()
function rebuildFileMap()
{
$packages = $this->listPackages();
$files = array();
foreach ($packages as $package) {
$version = $this->packageInfo($package, 'version');
$filelist = $this->packageInfo($package, 'filelist');
if (!is_array($filelist)) {
continue;
}
foreach ($filelist as $name => $attrs) {
if (isset($attrs['role']) && $attrs['role'] != 'php') {
continue;
}
if (isset($attrs['baseinstalldir'])) {
$file = $attrs['baseinstalldir'].DIRECTORY_SEPARATOR.$name;
} else {
$file = $name;
}
$file = preg_replace(',^/+,', '', $file);
$files[$file] = $package;
}
}
$this->_assertStateDir();
$fp = @fopen($this->filemap, 'wb');
if (!$fp) {
return false;
}
$this->filemap_cache = $files;
fwrite($fp, serialize($files));
fclose($fp);
return true;
}
// }}}
// {{{ readFileMap()
function readFileMap()
{
$fp = @fopen($this->filemap, 'r');
if (!$fp) {
return $this->raiseError('PEAR_Registry: could not open filemap', PEAR_REGISTRY_ERROR_FILE, null, null, $php_errormsg);
}
$fsize = filesize($this->filemap);
$rt = get_magic_quotes_runtime();
set_magic_quotes_runtime(0);
$data = fread($fp, $fsize);
set_magic_quotes_runtime($rt);
fclose($fp);
$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()
/**
* 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 (!eregi('Windows 9', php_uname())) {
if ($mode != LOCK_UN && is_resource($this->lock_fp)) {
// XXX does not check type of lock (LOCK_SH/LOCK_EX)
return true;
}
if (PEAR::isError($err = $this->_assertStateDir())) {
return $err;
}
$open_mode = 'w';
// XXX People reported problems with LOCK_SH and 'w'
if ($mode === LOCK_SH || $mode === LOCK_UN) {
if (@!is_file($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)) {
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 $this->raiseError("could not acquire $str lock ($this->lockfile)",
PEAR_REGISTRY_ERROR_LOCK);
}
}
return true;
}
// }}}
// {{{ _unlock()
function _unlock()
{
$ret = $this->_lock(LOCK_UN);
if (is_resource($this->lock_fp)) {
fclose($this->lock_fp);
}
$this->lock_fp = null;
return $ret;
}
// }}}
// {{{ _packageExists()
function _packageExists($package)
{
return file_exists($this->_packageFileName($package));
}
// }}}
// {{{ _packageInfo()
function _packageInfo($package = null, $key = null)
{
if ($package === null) {
return array_map(array($this, '_packageInfo'),
$this->_listPackages());
}
$fp = $this->_openPackageFile($package, 'r');
if ($fp === null) {
return null;
}
$rt = get_magic_quotes_runtime();
set_magic_quotes_runtime(0);
$data = fread($fp, filesize($this->_packageFileName($package)));
set_magic_quotes_runtime($rt);
$this->_closePackageFile($fp);
$data = unserialize($data);
if ($key === null) {
return $data;
}
if (isset($data[$key])) {
return $data[$key];
}
return null;
}
// }}}
// {{{ _listPackages()
function _listPackages()
{
$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);
}
return $pkglist;
}
// }}}
// {{{ packageExists()
function packageExists($package)
{
if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
return $e;
}
$ret = $this->_packageExists($package);
$this->_unlock();
return $ret;
}
// }}}
// {{{ packageInfo()
function packageInfo($package = null, $key = null)
{
if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
return $e;
}
$ret = $this->_packageInfo($package, $key);
$this->_unlock();
return $ret;
}
// }}}
// {{{ listPackages()
function listPackages()
{
if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
return $e;
}
$ret = $this->_listPackages();
$this->_unlock();
return $ret;
}
// }}}
// {{{ addPackage()
function addPackage($package, $info)
{
if ($this->packageExists($package)) {
return false;
}
if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
return $e;
}
$fp = $this->_openPackageFile($package, 'wb');
if ($fp === null) {
$this->_unlock();
return false;
}
$info['_lastmodified'] = time();
fwrite($fp, serialize($info));
$this->_closePackageFile($fp);
$this->_unlock();
return true;
}
// }}}
// {{{ deletePackage()
function deletePackage($package)
{
if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
return $e;
}
$file = $this->_packageFileName($package);
$ret = @unlink($file);
$this->rebuildFileMap();
$this->_unlock();
return $ret;
}
// }}}
// {{{ updatePackage()
function updatePackage($package, $info, $merge = true)
{
$oldinfo = $this->packageInfo($package);
if (empty($oldinfo)) {
return false;
}
if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
return $e;
}
$fp = $this->_openPackageFile($package, 'w');
if ($fp === null) {
$this->_unlock();
return false;
}
$info['_lastmodified'] = time();
if ($merge) {
fwrite($fp, serialize(array_merge($oldinfo, $info)));
} else {
fwrite($fp, serialize($info));
}
$this->_closePackageFile($fp);
if (isset($info['filelist'])) {
$this->rebuildFileMap();
}
$this->_unlock();
return true;
}
// }}}
// {{{ checkFileMap()
/**
* Test whether a file belongs to a package.
*
* @param string $path file path, absolute or relative to the pear
* install dir
*
* @return string which package the file belongs to, or an empty
* string if the file does not belong to an installed package
*
* @access public
*/
function checkFileMap($path)
{
if (is_array($path)) {
static $notempty;
if (empty($notempty)) {
$notempty = create_function('$a','return !empty($a);');
}
$pkgs = array();
foreach ($path as $name => $attrs) {
if (is_array($attrs) && isset($attrs['baseinstalldir'])) {
$name = $attrs['baseinstalldir'].DIRECTORY_SEPARATOR.$name;
}
$pkgs[$name] = $this->checkFileMap($name);
}
return array_filter($pkgs, $notempty);
}
if (empty($this->filemap_cache) && PEAR::isError($this->readFileMap())) {
return $err;
}
if (isset($this->filemap_cache[$path])) {
return $this->filemap_cache[$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[$path])) {
return $this->filemap_cache[$path];
}
return '';
}
// }}}
}
?>

View File

@@ -1,394 +0,0 @@
<?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. |
// +----------------------------------------------------------------------+
// | Author: Stig Bakken <ssb@php.net> |
// +----------------------------------------------------------------------+
//
// $Id$
require_once 'PEAR.php';
require_once 'PEAR/Config.php';
/**
* This is a class for doing remote operations against the central
* PEAR database.
*
* @nodep XML_RPC_Value
* @nodep XML_RPC_Message
* @nodep XML_RPC_Client
*/
class PEAR_Remote extends PEAR
{
// {{{ properties
var $config = null;
var $cache = null;
// }}}
// {{{ PEAR_Remote(config_object)
function PEAR_Remote(&$config)
{
$this->PEAR();
$this->config = &$config;
}
// }}}
// {{{ getCache()
function getCache($args)
{
$id = md5(serialize($args));
$cachedir = $this->config->get('cache_dir');
$filename = $cachedir . DIRECTORY_SEPARATOR . 'xmlrpc_cache_' . $id;
if (!file_exists($filename)) {
return null;
};
$fp = fopen($filename, 'rb');
if (!$fp) {
return null;
}
$content = fread($fp, filesize($filename));
fclose($fp);
$result = array(
'age' => time() - filemtime($filename),
'lastChange' => filemtime($filename),
'content' => unserialize($content),
);
return $result;
}
// }}}
// {{{ saveCache()
function saveCache($args, $data)
{
$id = md5(serialize($args));
$cachedir = $this->config->get('cache_dir');
if (!file_exists($cachedir)) {
System::mkdir(array('-p', $cachedir));
}
$filename = $cachedir.'/xmlrpc_cache_'.$id;
$fp = @fopen($filename, "wb");
if ($fp) {
fwrite($fp, serialize($data));
fclose($fp);
};
}
// }}}
// {{{ call(method, [args...])
function call($method)
{
$_args = $args = func_get_args();
$this->cache = $this->getCache($args);
$cachettl = $this->config->get('cache_ttl');
// If cache is newer than $cachettl seconds, we use the cache!
if ($this->cache !== null && $this->cache['age'] < $cachettl) {
return $this->cache['content'];
};
if (extension_loaded("xmlrpc")) {
$result = call_user_func_array(array(&$this, 'call_epi'), $args);
if (!PEAR::isError($result)) {
$this->saveCache($_args, $result);
};
return $result;
}
if (!@include_once("XML/RPC.php")) {
return $this->raiseError("For this remote PEAR operation you need to install the XML_RPC package");
}
array_shift($args);
$server_host = $this->config->get('master_server');
$username = $this->config->get('username');
$password = $this->config->get('password');
$eargs = array();
foreach($args as $arg) $eargs[] = $this->_encode($arg);
$f = new XML_RPC_Message($method, $eargs);
if ($this->cache !== null) {
$maxAge = '?maxAge='.$this->cache['lastChange'];
} else {
$maxAge = '';
};
$proxy_host = $proxy_port = $proxy_user = $proxy_pass = '';
if ($proxy = parse_url($this->config->get('http_proxy'))) {
$proxy_host = @$proxy['host'];
$proxy_port = @$proxy['port'];
$proxy_user = @urldecode(@$proxy['user']);
$proxy_pass = @urldecode(@$proxy['pass']);
}
$c = new XML_RPC_Client('/xmlrpc.php'.$maxAge, $server_host, 80, $proxy_host, $proxy_port, $proxy_user, $proxy_pass);
if ($username && $password) {
$c->setCredentials($username, $password);
}
if ($this->config->get('verbose') >= 3) {
$c->setDebug(1);
}
$r = $c->send($f);
if (!$r) {
return $this->raiseError("XML_RPC send failed");
}
$v = $r->value();
if ($e = $r->faultCode()) {
if ($e == $GLOBALS['XML_RPC_err']['http_error'] && strstr($r->faultString(), '304 Not Modified') !== false) {
return $this->cache['content'];
}
return $this->raiseError($r->faultString(), $e);
}
$result = XML_RPC_decode($v);
$this->saveCache($_args, $result);
return $result;
}
// }}}
// {{{ call_epi(method, [args...])
function call_epi($method)
{
do {
if (extension_loaded("xmlrpc")) {
break;
}
if (OS_WINDOWS) {
$ext = 'dll';
} elseif (PHP_OS == 'HP-UX') {
$ext = 'sl';
} elseif (PHP_OS == 'AIX') {
$ext = 'a';
} else {
$ext = 'so';
}
$ext = OS_WINDOWS ? 'dll' : 'so';
@dl("xmlrpc-epi.$ext");
if (extension_loaded("xmlrpc")) {
break;
}
@dl("xmlrpc.$ext");
if (extension_loaded("xmlrpc")) {
break;
}
return $this->raiseError("unable to load xmlrpc extension");
} while (false);
$params = func_get_args();
array_shift($params);
$method = str_replace("_", ".", $method);
$request = xmlrpc_encode_request($method, $params);
$server_host = $this->config->get("master_server");
if (empty($server_host)) {
return $this->raiseError("PEAR_Remote::call: no master_server configured");
}
$server_port = 80;
if ($http_proxy = $this->config->get('http_proxy')) {
$proxy = parse_url($http_proxy);
$proxy_host = $proxy_port = $proxy_user = $proxy_pass = '';
$proxy_host = @$proxy['host'];
$proxy_port = @$proxy['port'];
$proxy_user = @urldecode(@$proxy['user']);
$proxy_pass = @urldecode(@$proxy['pass']);
$fp = @fsockopen($proxy_host, $proxy_port);
$use_proxy = true;
} else {
$use_proxy = false;
$fp = @fsockopen($server_host, $server_port);
}
if (!$fp && $http_proxy) {
return $this->raiseError("PEAR_Remote::call: fsockopen(`$proxy_host', $proxy_port) failed");
} elseif (!$fp) {
return $this->raiseError("PEAR_Remote::call: fsockopen(`$server_host', $server_port) failed");
}
$len = strlen($request);
$req_headers = "Host: $server_host:$server_port\r\n" .
"Content-type: text/xml\r\n" .
"Content-length: $len\r\n";
$username = $this->config->get('username');
$password = $this->config->get('password');
if ($username && $password) {
$req_headers .= "Cookie: PEAR_USER=$username; PEAR_PW=$password\r\n";
$tmp = base64_encode("$username:$password");
$req_headers .= "Authorization: Basic $tmp\r\n";
}
if ($this->cache !== null) {
$maxAge = '?maxAge='.$this->cache['lastChange'];
} else {
$maxAge = '';
};
if ($use_proxy && $proxy_host != '' && $proxy_user != '') {
$req_headers .= 'Proxy-Authorization: Basic '
.base64_encode($proxy_user.':'.$proxy_pass)
."\r\n";
}
if ($this->config->get('verbose') > 3) {
print "XMLRPC REQUEST HEADERS:\n";
var_dump($req_headers);
print "XMLRPC REQUEST BODY:\n";
var_dump($request);
}
if ($use_proxy && $proxy_host != '') {
$post_string = "POST http://".$server_host;
if ($proxy_port > '') {
$post_string .= ':'.$server_port;
}
} else {
$post_string = "POST ";
}
fwrite($fp, ($post_string."/xmlrpc.php$maxAge HTTP/1.0\r\n$req_headers\r\n$request"));
$response = '';
$line1 = fgets($fp, 2048);
if (!preg_match('!^HTTP/[0-9\.]+ (\d+) (.*)!', $line1, $matches)) {
return $this->raiseError("PEAR_Remote: invalid HTTP response from XML-RPC server");
}
switch ($matches[1]) {
case "200": // OK
break;
case "304": // Not Modified
return $this->cache['content'];
case "401": // Unauthorized
if ($username && $password) {
return $this->raiseError("PEAR_Remote: authorization failed", 401);
} else {
return $this->raiseError("PEAR_Remote: authorization required, please log in first", 401);
}
default:
return $this->raiseError("PEAR_Remote: unexpected HTTP response", (int)$matches[1], null, null, "$matches[1] $matches[2]");
}
while (trim(fgets($fp, 2048)) != ''); // skip rest of headers
while ($chunk = fread($fp, 10240)) {
$response .= $chunk;
}
fclose($fp);
if ($this->config->get('verbose') > 3) {
print "XMLRPC RESPONSE:\n";
var_dump($response);
}
$ret = xmlrpc_decode($response);
if (is_array($ret) && isset($ret['__PEAR_TYPE__'])) {
if ($ret['__PEAR_TYPE__'] == 'error') {
if (isset($ret['__PEAR_CLASS__'])) {
$class = $ret['__PEAR_CLASS__'];
} else {
$class = "PEAR_Error";
}
if ($ret['code'] === '') $ret['code'] = null;
if ($ret['message'] === '') $ret['message'] = null;
if ($ret['userinfo'] === '') $ret['userinfo'] = null;
if (strtolower($class) == 'db_error') {
$ret = $this->raiseError(PEAR::errorMessage($ret['code']),
$ret['code'], null, null,
$ret['userinfo']);
} else {
$ret = $this->raiseError($ret['message'], $ret['code'],
null, null, $ret['userinfo']);
}
}
} elseif (is_array($ret) && sizeof($ret) == 1 && isset($ret[0])
&& is_array($ret[0]) &&
!empty($ret[0]['faultString']) &&
!empty($ret[0]['faultCode'])) {
extract($ret[0]);
$faultString = "XML-RPC Server Fault: " .
str_replace("\n", " ", $faultString);
return $this->raiseError($faultString, $faultCode);
}
return $ret;
}
// }}}
// {{{ _encode
// a slightly extended version of XML_RPC_encode
function _encode($php_val)
{
global $XML_RPC_Boolean, $XML_RPC_Int, $XML_RPC_Double;
global $XML_RPC_String, $XML_RPC_Array, $XML_RPC_Struct;
$type = gettype($php_val);
$xmlrpcval = new XML_RPC_Value;
switch($type) {
case "array":
reset($php_val);
$firstkey = key($php_val);
end($php_val);
$lastkey = key($php_val);
if ($firstkey === 0 && is_int($lastkey) &&
($lastkey + 1) == count($php_val)) {
$is_continuous = true;
reset($php_val);
$size = count($php_val);
for ($expect = 0; $expect < $size; $expect++, next($php_val)) {
if (key($php_val) !== $expect) {
$is_continuous = false;
break;
}
}
if ($is_continuous) {
reset($php_val);
$arr = array();
while (list($k, $v) = each($php_val)) {
$arr[$k] = $this->_encode($v);
}
$xmlrpcval->addArray($arr);
break;
}
}
// fall though if not numerical and continuous
case "object":
$arr = array();
while (list($k, $v) = each($php_val)) {
$arr[$k] = $this->_encode($v);
}
$xmlrpcval->addStruct($arr);
break;
case "integer":
$xmlrpcval->addScalar($php_val, $XML_RPC_Int);
break;
case "double":
$xmlrpcval->addScalar($php_val, $XML_RPC_Double);
break;
case "string":
case "NULL":
$xmlrpcval->addScalar($php_val, $XML_RPC_String);
break;
case "boolean":
$xmlrpcval->addScalar($php_val, $XML_RPC_Boolean);
break;
case "unknown type":
default:
return null;
}
return $xmlrpcval;
}
// }}}
}
?>

View File

@@ -1,363 +0,0 @@
<?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. |
// +----------------------------------------------------------------------+
// | Authors: Tomas V.V.Cox <cox@idecnet.com> |
// | Greg Beaver <cellog@php.net> |
// | |
// +----------------------------------------------------------------------+
//
// $Id$
//
/**
* Simplified version of PHP's test suite
* -- EXPERIMENTAL --
Try it with:
$ php -r 'include "../PEAR/RunTest.php"; $t=new PEAR_RunTest; $o=$t->run("./pear_system.phpt");print_r($o);'
TODO:
Actually finish the development and testing
*/
require_once 'PEAR.php';
require_once 'PEAR/Config.php';
define('DETAILED', 1);
putenv("PHP_PEAR_RUNTESTS=1");
class PEAR_RunTest
{
var $_logger;
/**
* An object that supports the PEAR_Common->log() signature, or null
* @param PEAR_Common|null
*/
function PEAR_RunTest($logger = null)
{
$this->_logger = $logger;
}
//
// Run an individual test case.
//
function run($file, $ini_settings = '')
{
$cwd = getcwd();
$conf = &PEAR_Config::singleton();
$php = $conf->get('php_bin');
//var_dump($php);exit;
global $log_format, $info_params, $ini_overwrites;
$info_params = '';
$log_format = 'LEOD';
// Load the sections of the test file.
$section_text = array(
'TEST' => '(unnamed test)',
'SKIPIF' => '',
'GET' => '',
'ARGS' => '',
);
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 (ereg('^--([A-Z]+)--',$line,$r)) {
$section = $r[1];
$section_text[$section] = '';
continue;
}
// Add to the section text.
$section_text[$section] .= $line;
}
fclose($fp);
$shortname = str_replace($cwd.'/', '', $file);
$tested = trim($section_text['TEST'])." [$shortname]";
$tmp = realpath(dirname($file));
$tmp_skipif = $tmp . uniqid('/phpt.');
$tmp_file = ereg_replace('\.phpt$','.php',$file);
$tmp_post = $tmp . uniqid('/phpt.');
@unlink($tmp_skipif);
@unlink($tmp_file);
@unlink($tmp_post);
// unlink old test results
@unlink(ereg_replace('\.phpt$','.diff',$file));
@unlink(ereg_replace('\.phpt$','.log',$file));
@unlink(ereg_replace('\.phpt$','.exp',$file));
@unlink(ereg_replace('\.phpt$','.out',$file));
// Check if test should be skipped.
$info = '';
$warn = false;
if (array_key_exists('SKIPIF', $section_text)) {
if (trim($section_text['SKIPIF'])) {
$this->save_text($tmp_skipif, $section_text['SKIPIF']);
//$extra = substr(PHP_OS, 0, 3) !== "WIN" ?
// "unset REQUEST_METHOD;": "";
//$output = `$extra $php $info_params -f $tmp_skipif`;
$output = `$php $info_params -f $tmp_skipif`;
unlink($tmp_skipif);
if (eregi("^skip", trim($output))) {
$skipreason = "SKIP $tested";
$reason = (eregi("^skip[[:space:]]*(.+)\$", trim($output))) ? eregi_replace("^skip[[:space:]]*(.+)\$", "\\1", trim($output)) : FALSE;
if ($reason) {
$skipreason .= " (reason: $reason)";
}
$this->_logger->log(0, $skipreason);
if (isset($old_php)) {
$php = $old_php;
}
return 'SKIPPED';
}
if (eregi("^info", trim($output))) {
$reason = (ereg("^info[[:space:]]*(.+)\$", trim($output))) ? ereg_replace("^info[[:space:]]*(.+)\$", "\\1", trim($output)) : FALSE;
if ($reason) {
$info = " (info: $reason)";
}
}
if (eregi("^warn", trim($output))) {
$reason = (ereg("^warn[[:space:]]*(.+)\$", trim($output))) ? ereg_replace("^warn[[:space:]]*(.+)\$", "\\1", trim($output)) : FALSE;
if ($reason) {
$warn = true; /* only if there is a reason */
$info = " (warn: $reason)";
}
}
}
}
// We've satisfied the preconditions - run the test!
$this->save_text($tmp_file,$section_text['FILE']);
$args = $section_text['ARGS'] ? ' -- '.$section_text['ARGS'] : '';
$cmd = "$php$ini_settings -f $tmp_file$args 2>&1";
if (isset($this->_logger)) {
$this->_logger->log(2, 'Running command "' . $cmd . '"');
}
$savedir = getcwd(); // in case the test moves us around
if (isset($section_text['RETURNS'])) {
ob_start();
system($cmd, $return_value);
$out = ob_get_contents();
ob_end_clean();
@unlink($tmp_post);
$section_text['RETURNS'] = (int) trim($section_text['RETURNS']);
$returnfail = ($return_value != $section_text['RETURNS']);
} else {
$out = `$cmd`;
$returnfail = false;
}
chdir($savedir);
// Does the output match what is expected?
$output = trim($out);
$output = preg_replace('/\r\n/', "\n", $output);
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)) {
@unlink($tmp_file);
$this->_logger->log(0, "PASS $tested$info");
if (isset($old_php)) {
$php = $old_php;
}
return 'PASSED';
}
} else {
$wanted = trim($section_text['EXPECT']);
$wanted = preg_replace('/\r\n/',"\n",$wanted);
// compare and leave on success
$ok = (0 == strcmp($output,$wanted));
if (!$returnfail && $ok) {
@unlink($tmp_file);
$this->_logger->log(0, "PASS $tested$info");
if (isset($old_php)) {
$php = $old_php;
}
return 'PASSED';
}
}
// Test failed so we need to report details.
if ($warn) {
$this->_logger->log(0, "WARN $tested$info");
} else {
$this->_logger->log(0, "FAIL $tested$info");
}
if (isset($section_text['RETURNS'])) {
$GLOBALS['__PHP_FAILED_TESTS__'][] = array(
'name' => $file,
'test_name' => $tested,
'output' => ereg_replace('\.phpt$','.log', $file),
'diff' => ereg_replace('\.phpt$','.diff', $file),
'info' => $info,
'return' => $return_value
);
} else {
$GLOBALS['__PHP_FAILED_TESTS__'][] = array(
'name' => $file,
'test_name' => $tested,
'output' => ereg_replace('\.phpt$','.log', $file),
'diff' => ereg_replace('\.phpt$','.diff', $file),
'info' => $info,
);
}
// write .exp
if (strpos($log_format,'E') !== FALSE) {
$logname = ereg_replace('\.phpt$','.exp',$file);
if (!$log = fopen($logname,'w')) {
return PEAR::raiseError("Cannot create test log - $logname");
}
fwrite($log,$wanted);
fclose($log);
}
// write .out
if (strpos($log_format,'O') !== FALSE) {
$logname = ereg_replace('\.phpt$','.out',$file);
if (!$log = fopen($logname,'w')) {
return PEAR::raiseError("Cannot create test log - $logname");
}
fwrite($log,$output);
fclose($log);
}
// write .diff
if (strpos($log_format,'D') !== FALSE) {
$logname = ereg_replace('\.phpt$','.diff',$file);
if (!$log = fopen($logname,'w')) {
return PEAR::raiseError("Cannot create test log - $logname");
}
fwrite($log, $this->generate_diff($wanted, $output,
isset($section_text['RETURNS']) ? array(trim($section_text['RETURNS']),
$return_value) : null));
fclose($log);
}
// write .log
if (strpos($log_format,'L') !== FALSE) {
$logname = ereg_replace('\.phpt$','.log',$file);
if (!$log = fopen($logname,'w')) {
return PEAR::raiseError("Cannot create test log - $logname");
}
fwrite($log,"
---- EXPECTED OUTPUT
$wanted
---- ACTUAL OUTPUT
$output
---- FAILED
");
if ($returnfail) {
fwrite($log,"
---- EXPECTED RETURN
$section_text[RETURNS]
---- ACTUAL RETURN
$return_value
");
}
fclose($log);
//error_report($file,$logname,$tested);
}
if (isset($old_php)) {
$php = $old_php;
}
return $warn ? 'WARNED' : 'FAILED';
}
function generate_diff($wanted, $output, $return_value)
{
$w = explode("\n", $wanted);
$o = explode("\n", $output);
$w1 = array_diff_assoc($w,$o);
$o1 = array_diff_assoc($o,$w);
$w2 = array();
$o2 = array();
foreach($w1 as $idx => $val) $w2[sprintf("%03d<",$idx)] = sprintf("%03d- ", $idx+1).$val;
foreach($o1 as $idx => $val) $o2[sprintf("%03d>",$idx)] = sprintf("%03d+ ", $idx+1).$val;
$diff = array_merge($w2, $o2);
ksort($diff);
if ($return_value) {
$extra = "##EXPECTED: $return_value[0]\r\n##RETURNED: $return_value[1]";
} else {
$extra = '';
}
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
}}}
";
}
}
?>