diff --git a/boot.php b/boot.php
index 438c6bb1f..084bca112 100644
--- a/boot.php
+++ b/boot.php
@@ -646,12 +646,12 @@ class App {
startup();
set_include_path(
- 'include' . PATH_SEPARATOR
+ get_include_path() . PATH_SEPARATOR
+ . 'include' . PATH_SEPARATOR
. 'library' . PATH_SEPARATOR
. 'library/langdet' . PATH_SEPARATOR
. '.' );
-
$this->scheme = 'http';
if ((x($_SERVER, 'HTTPS') && $_SERVER['HTTPS']) ||
diff --git a/composer.json b/composer.json
index a7800ffff..f2aeaa8eb 100644
--- a/composer.json
+++ b/composer.json
@@ -14,8 +14,15 @@
},
"require": {
"ezyang/htmlpurifier": "~4.7.0",
- "mobiledetect/mobiledetectlib": "2.8.*"
+ "mobiledetect/mobiledetectlib": "2.8.*",
+ "pear-pear.php.net/Text_Highlighter": "*"
},
+ "repositories": [
+ {
+ "type": "pear",
+ "url": "https://pear.php.net"
+ }
+ ],
"autoload": {
"psr-4": {
"Friendica\\": "src/"
diff --git a/composer.lock b/composer.lock
index 2ca9991bf..b35d1ca12 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
- "content-hash": "49b00f1ed3192e5173bd5577a3b91ba2",
+ "content-hash": "4d3a9e742e7ad746fb7206f3b5aff5af",
"packages": [
{
"name": "ezyang/htmlpurifier",
@@ -101,6 +101,224 @@
"php mobile detect"
],
"time": "2017-03-29T13:59:30+00:00"
+ },
+ {
+ "name": "pear-pear.php.net/Archive_Tar",
+ "version": "1.4.2",
+ "dist": {
+ "type": "file",
+ "url": "https://pear.php.net/get/Archive_Tar-1.4.2.tgz",
+ "reference": null,
+ "shasum": null
+ },
+ "require": {
+ "php": ">=5.2.0.0"
+ },
+ "replace": {
+ "pear-pear/archive_tar": "== 1.4.2.0"
+ },
+ "type": "pear-library",
+ "autoload": {
+ "classmap": [
+ ""
+ ]
+ },
+ "include-path": [
+ "/"
+ ],
+ "license": [
+ "New BSD License"
+ ],
+ "description": "This class provides handling of tar files in PHP.\nIt supports creating, listing, extracting and adding to tar files.\nGzip support is available if PHP has the zlib extension built-in or\nloaded. Bz2 compression is also supported with the bz2 extension loaded."
+ },
+ {
+ "name": "pear-pear.php.net/Console_Getopt",
+ "version": "1.4.1",
+ "dist": {
+ "type": "file",
+ "url": "https://pear.php.net/get/Console_Getopt-1.4.1.tgz",
+ "reference": null,
+ "shasum": null
+ },
+ "require": {
+ "php": ">=5.4.0.0"
+ },
+ "replace": {
+ "pear-pear/console_getopt": "== 1.4.1.0"
+ },
+ "type": "pear-library",
+ "autoload": {
+ "classmap": [
+ ""
+ ]
+ },
+ "include-path": [
+ "/"
+ ],
+ "license": [
+ "BSD-2-Clause"
+ ],
+ "description": "This is a PHP implementation of \"getopt\" supporting both\nshort and long options."
+ },
+ {
+ "name": "pear-pear.php.net/PEAR",
+ "version": "1.10.3",
+ "dist": {
+ "type": "file",
+ "url": "https://pear.php.net/get/PEAR-1.10.3.tgz",
+ "reference": null,
+ "shasum": null
+ },
+ "require": {
+ "ext-pcre": "*",
+ "ext-xml": "*",
+ "pear-pear.php.net/archive_tar": ">=1.4.0.0",
+ "pear-pear.php.net/console_getopt": ">=1.4.1.0",
+ "pear-pear.php.net/structures_graph": ">=1.1.0.0",
+ "pear-pear.php.net/xml_util": ">=1.3.0.0",
+ "php": ">=5.4.0.0"
+ },
+ "conflict": {
+ "pear-pear.php.net/pear_frontend_gtk": "<0.4.0.0",
+ "pear-pear.php.net/pear_frontend_web": "<=0.4.0.0"
+ },
+ "replace": {
+ "pear-pear/pear": "== 1.10.3.0"
+ },
+ "type": "pear-library",
+ "autoload": {
+ "classmap": [
+ ""
+ ]
+ },
+ "include-path": [
+ "/"
+ ],
+ "license": [
+ "New BSD License"
+ ],
+ "description": "The PEAR package contains:\n * the PEAR installer, for creating, distributing\n and installing packages\n * the PEAR_Exception PHP5 error handling mechanism\n * the PEAR_ErrorStack advanced error handling mechanism\n * the PEAR_Error error handling mechanism\n * the OS_Guess class for retrieving info about the OS\n where PHP is running on\n * the System class for quick handling of common operations\n with files and directories\n * the PEAR base class\n Features in a nutshell:\n * full support for channels\n * pre-download dependency validation\n * new package.xml 2.0 format allows tremendous flexibility while maintaining BC\n * support for optional dependency groups and limited support for sub-packaging\n * robust dependency support\n * full dependency validation on uninstall\n * remote install for hosts with only ftp access - no more problems with\n restricted host installation\n * full support for mirroring\n * support for bundling several packages into a single tarball\n * support for static dependencies on a url-based package\n * support for custom file roles and installation tasks"
+ },
+ {
+ "name": "pear-pear.php.net/Structures_Graph",
+ "version": "1.1.1",
+ "dist": {
+ "type": "file",
+ "url": "https://pear.php.net/get/Structures_Graph-1.1.1.tgz",
+ "reference": null,
+ "shasum": null
+ },
+ "require": {
+ "php": ">=5.3.0.0"
+ },
+ "replace": {
+ "pear-pear/structures_graph": "== 1.1.1.0"
+ },
+ "type": "pear-library",
+ "autoload": {
+ "classmap": [
+ ""
+ ]
+ },
+ "include-path": [
+ "/"
+ ],
+ "license": [
+ "LGPL-3.0+"
+ ],
+ "description": "Structures_Graph is a package for creating and manipulating graph datastructures. It allows building of directed\nand undirected graphs, with data and metadata stored in nodes. The library provides functions for graph traversing\nas well as for characteristic extraction from the graph topology."
+ },
+ {
+ "name": "pear-pear.php.net/Text_Highlighter",
+ "version": "0.8.0",
+ "dist": {
+ "type": "file",
+ "url": "https://pear.php.net/get/Text_Highlighter-0.8.0.tgz",
+ "reference": null,
+ "shasum": null
+ },
+ "require": {
+ "pear-pear.php.net/console_getopt": ">=1.4.1.0",
+ "pear-pear.php.net/pear": ">=1.10.3.0",
+ "pear-pear.php.net/xml_parser": ">=1.3.7.0",
+ "php": ">=5.4.0.0"
+ },
+ "replace": {
+ "pear-pear/text_highlighter": "== 0.8.0.0"
+ },
+ "type": "pear-library",
+ "autoload": {
+ "classmap": [
+ ""
+ ]
+ },
+ "include-path": [
+ "/"
+ ],
+ "license": [
+ "PHP License"
+ ],
+ "description": "Text_Highlighter is a package for syntax highlighting.\n\nIt provides a base class provining all the functionality,\nand a descendent classes geneator class.\n\nThe main idea is to simplify creation of subclasses\nimplementing syntax highlighting for particular language.\nSubclasses do not implement any new functioanality,\nthey just provide syntax highlighting rules.\nThe rules sources are in XML format.\n\nTo create a highlighter for a language, there is no need\nto code a new class manually. Simply describe the rules\nin XML file and use Text_Highlighter_Generator to create\na new class."
+ },
+ {
+ "name": "pear-pear.php.net/XML_Parser",
+ "version": "1.3.7",
+ "dist": {
+ "type": "file",
+ "url": "https://pear.php.net/get/XML_Parser-1.3.7.tgz",
+ "reference": null,
+ "shasum": null
+ },
+ "require": {
+ "pear-pear.php.net/pear": "*",
+ "php": ">=4.2.0.0"
+ },
+ "replace": {
+ "pear-pear/xml_parser": "== 1.3.7.0"
+ },
+ "type": "pear-library",
+ "autoload": {
+ "classmap": [
+ ""
+ ]
+ },
+ "include-path": [
+ "/"
+ ],
+ "license": [
+ "BSD License"
+ ],
+ "description": "This is an XML parser based on PHPs built-in xml extension.\nIt supports two basic modes of operation: \"func\" and \"event\". In \"func\" mode, it will look for a function named after each element (xmltag_ELEMENT for start tags and xmltag_ELEMENT_ for end tags), and in \"event\" mode it uses a set of generic callbacks.\n\nSince version 1.2.0 there's a new XML_Parser_Simple class that makes parsing of most XML documents easier, by automatically providing a stack for the elements.\nFurthermore its now possible to split the parser from the handler object, so you do not have to extend XML_Parser anymore in order to parse a document with it."
+ },
+ {
+ "name": "pear-pear.php.net/XML_Util",
+ "version": "1.4.2",
+ "dist": {
+ "type": "file",
+ "url": "https://pear.php.net/get/XML_Util-1.4.2.tgz",
+ "reference": null,
+ "shasum": null
+ },
+ "require": {
+ "ext-pcre": "*",
+ "php": ">=5.4.0.0"
+ },
+ "replace": {
+ "pear-pear/xml_util": "== 1.4.2.0"
+ },
+ "type": "pear-library",
+ "autoload": {
+ "classmap": [
+ ""
+ ]
+ },
+ "include-path": [
+ "/"
+ ],
+ "license": [
+ "BSD License"
+ ],
+ "description": "Selection of methods that are often needed when working with XML documents. Functionality includes creating of attribute lists from arrays, creation of tags, validation of XML names and more."
}
],
"packages-dev": [],
diff --git a/include/text.php b/include/text.php
index 4a23b7ac3..291998933 100644
--- a/include/text.php
+++ b/include/text.php
@@ -2125,47 +2125,48 @@ function format_network_name($network, $url = 0) {
* @param string $lang Programming language
* @return string Formated html
*/
-function text_highlight($s,$lang) {
- if($lang === 'js')
+function text_highlight($s, $lang) {
+ if ($lang === 'js') {
$lang = 'javascript';
-
- if(! strpos('Text_Highlighter',get_include_path())) {
- set_include_path(get_include_path() . PATH_SEPARATOR . 'library/Text_Highlighter');
}
- require_once('library/Text_Highlighter/Text/Highlighter.php');
- require_once('library/Text_Highlighter/Text/Highlighter/Renderer/Html.php');
+ // @TODO: Replace Text_Highlighter_Renderer_Html by scrivo/highlight.php
+
+ // Autoload the library to make constants available
+ class_exists('Text_Highlighter_Renderer_Html');
+
$options = array(
'numbers' => HL_NUMBERS_LI,
'tabsize' => 4,
- );
+ );
$tag_added = false;
- $s = trim(html_entity_decode($s,ENT_COMPAT));
- $s = str_replace(" ","\t",$s);
+ $s = trim(html_entity_decode($s, ENT_COMPAT));
+ $s = str_replace(' ', "\t", $s);
// The highlighter library insists on an opening php tag for php code blocks. If
// it isn't present, nothing is highlighted. So we're going to see if it's present.
// If not, we'll add it, and then quietly remove it after we get the processed output back.
- if($lang === 'php') {
- if(strpos('setRenderer($renderer);
$o = $hl->highlight($s);
- $o = str_replace([" ","\n"],[" ",''],$o);
+ $o = str_replace("\n", '', $o);
- if($tag_added) {
- $b = substr($o,0,strpos($o,'
'));
- $e = substr($o,strpos($o,''));
+
+ if ($tag_added) {
+ $b = substr($o, 0, strpos($o, ''));
+ $e = substr($o, strpos($o, ''));
$o = $b . $e;
}
- return('' . $o . '
');
+ return '' . $o . '
';
}
diff --git a/library/Text_Highlighter/README b/library/Text_Highlighter/README
deleted file mode 100644
index 88f71aed2..000000000
--- a/library/Text_Highlighter/README
+++ /dev/null
@@ -1,455 +0,0 @@
-# $Id$
-
-Introduction
-============
-
-Text_Highlighter is a class for syntax highlighting. The main idea is to
-simplify creation of subclasses implementing syntax highlighting for
-particular language. Subclasses do not implement any new functioanality, they
-just provide syntax highlighting rules. The rules sources are in XML format.
-To create a highlighter for a language, there is no need to code a new class
-manually. Simply describe the rules in XML file and use Text_Highlighter_Generator
-to create a new class.
-
-
-This document does not contain a formal description of API - it is very
-simple, and I believe providing some examples of code is sufficient.
-
-
-Highlighter XML source
-======================
-
-Basics
-------
-
-Creating a new syntax highlighter begins with describing the highlighting
-rules. There are two basic elements: block and region. A block is just a
-portion of text matching a regular expression and highlighted with a single
-color. Keyword is an example of a block. A region is defined by two regular
-expressions: one for start of region, and another for the end. The main
-difference from a block is that a region can contain blocks and regions
-(including same-named regions). An example of a region is a group of
-statements enclosed in curly brackets (this is used in many languages, for
-example PHP and C). Also, characters matching start and end of a region may be
-highlighted with their own color, and region contents with another.
-
-Blocks and regions may be declared as contained. Contained blocks and regions
-can only appear inside regions. If a region or a block is not declared as
-contained, it can appear both on top level and inside regions. Block or region
-declared as not-contained can only appear on top level.
-
-For any region, a list of blocks and regions that can appear inside this
-region can be specified.
-
-In this document, the term "color group" is used. Chunks of text assigned to
-same color group will be highlighted with same color. Note that in versions
-prior 0.5.0 color goups were refered as CSS classes, but since 0.5.0 not only
-HTML output is supported, so "color group" is more appropriate term.
-
-Elements
---------
-
-The toplevel element is . Attribute lang is required and denotes
-the name of the language. Its value is used as a part of generated class name,
-and must only contain letters, digits and underscores. Optional attribute
-case, when given value yes, makes the language case sensitive (default is case
-insensitive). Allowed subelements are:
-
- * : Information about the authors of the file.
- : Information about a single author of the file. (May be used
- multiple times, one per author.)
- - name="...": Author's name. Required.
- - email="...": Author's email address. Optional.
-
- * : Default color group.
- - innerGroup="...": color group name. Required.
-
- * : Region definition
- - name="...": Region name. Required.
- - innerGroup="...": Default color group of region contents. Required.
- - delimGroup="...": color group of start and end of region. Optional,
- defaults to value of innerGroup attribute.
- - start="...", end="...": Regular expression matching start and end
- of region. Required. Regular expression delimiters are optional, but
- if you need to specify delimiter, use /. The only case when the
- delimiters are needed, is specifying regular expression modifiers,
- such as m or U. Examples: \/\* or /$/m.
- - contained="yes": Marks region as contained.
- - never-contained="yes": Marks region as not-contained.
- - : Elements allowed inside this region.
- - all="yes" Region can contain any other region or block
- (except not-contained). May be used multiple times.
- - Do not allow certain regions or blocks.
- - region="..." Name of region not allowed within
- current region.
- - block="..." Name of block not allowed within
- current region.
- - region="..." Name of region allowed within current region.
- - block="..." Name of block allowed within current region.
- - Only allow this region within certain regions. May be
- used multiple times.
- - block="..." Name of parent region
-
- * : Block definition
- - name="...": Block name. Required.
- - innerGroup="...": color group of block contents. Optional. If not
- specified, color group of parent region or default color group will be
- used. One would only want to omit this attribute if there are
- keyword groups (see below) inherited from this block, and no special
- highlighting should apply when the block does not match the keyword.
- - match="..." Regular expression matching the block. Required.
- Regular expression delimiters are optional, but if you need to
- specify delimiter, use /. The only case when the delimiters are
- needed, is specifying regular expression modifiers, such as m or U.
- Examples: #|\/\/ or /$/m.
- - contained="yes": Marks block as contained.
- - never-contained="yes": Marks block as not-contained.
- - Only allow this block within certain regions. May be used
- multiple times.
- - block="..." Name of parent region
- - multiline="yes": Marks block as multi-line. By default, whole
- blocks are assumed to reside in a single line. This make the things
- faster. If you need to declare a multi-line block, use this
- attribute.
- - : Assigns another color group to a part of the block that
- matched a subpattern.
- - index="n": Subpattern index. Required.
- - innerGroup="...": color group name. Required.
-
- This is an example from CSS highlighter: the measure is matched as
- a whole, but the measurement units are highlighted with different
- color.
-
-
-
-
-
-
- * : Keyword group definition. Keyword groups are useful when you
- want to highlight some words that match a condition for a block with a
- different color. Keywords are defined with literal match, not regular
- expressions. For example, you have a block named identifier matching a
- general identifier, and want to highlight reserved words (which match
- this block as well) with different color. You inherit a keyword group
- "reserved" from "identifier" block.
- - name="...": Keyword group. Required.
- - ifdef="...", ifndef="..." : Conditional declaration. See
- "Conditions" below.
- - inherits="...": Inherited block name. Required.
- - innerGroup="...": color group of keyword group. Required.
- - case="yes|no": Overrides case-sensitivity of the language.
- Optional, defaults to global value.
- - : Single keyword definition.
- - match="..." The keyword. Note: this is not a regular
- expression, but literal match (possibly case insensitive).
-
-Note that for BC reasons element partClass is alias for partGroup, and
-attributes innerClass and delimClass are aliases of innerGroup and
-delimGroup, respectively.
-
-
-Conditions
-----------
-
-Conditional declarations allow enabling or disabling certain highlighting
-rules at runtime. For example, Java highlighter has a very big list of
-keywords matching Java standard classes. Finding a match in this list can take
-much time. For that reason, corresponding keyword group is declared with
-"ifdef" attribute :
-
-
-
-
-
- ...
- ...
-
-
-
-
-
-This keyword group will be only enabled when "java.builtins" is passed as an
-element of "defines" option:
-
- $options = array(
- 'defines' => array(
- 'java.builtins',
- ),
- 'numbers' => HL_NUMBERS_TABLE,
- );
- $highlighter = Text_Highlighter::factory('java', $options);
-
-"ifndef" attribute has reverse meaning.
-
-Currently, "ifdef" and "ifndef" attributes are only supported for
-tag.
-
-
-
-Class generation
-================
-
-Creating XML description of highlighting rules is the most complicated part of
-the process. To generate the class, you need just few lines of code:
-
- generate();
- $generator->saveCode('PHP.php');
- ?>
-
-
-
-Command-line class generation tool
-==================================
-
-Example from previous section looks pretty simple, but it does not handle any
-errors which may occur during parsing of XML source. The package provides a
-command-line script to make generation of classes even more simple, and takes
-care of possible errors. It is called generate (on Unix/Linux) or generate.bat
-(on Windows). This script is able to process multiple files in one run, and
-also to process XML from standard input and write generated code to standard
-output.
-
- Usage:
- generate options
-
- Options:
- -x filename, --xml=filename
- source XML file. Multiple input files can be specified, in which
- case each -x option must be followed by -p unless -d is specified
- Defaults to stdin
- -p filename, --php=filename
- destination PHP file. Defaults to stdout. If specied multiple times,
- each -p must follow -x
- -d dirname, --dir=dirname
- Default destination directory. File names will be taken from XML input
- ("lang" attribute of tag)
- -h, --help
- This help
-
-Examples
-
- Read from php.xml, write to PHP.php
-
- generate -x php.xml -p PHP.php
-
- Read from php.xml, write to standard output
-
- generate -x php.xml
-
- Read from php.xml, write to PHP.php, read from xml.xml, write to XML.php
-
- generate -x php.xml -p PHP.php -x xml.xml -p XML.php
-
- Read from php.xml, write to /some/dir/PHP.php, read from xml.xml, write to
- /some/dir/XML.php (assuming that xml.xml contains , and
- php.xml contains )
-
- generate -x php.xml -x xml.xml -d /some/dir/
-
-
-
-Renderers
-=========
-
-Introduction
-------------
-
-Text_Highlighter supports renderes. Using renderers, you can get output in
-different formats. Two renderers are included in the package:
-
- - HTML renderer. Generates HTML output. A style sheet should be linked to
- the document to display colored text
-
- - Console renderer. Can be used to output highlighted text to
- color-capable terminals, either directly or trough less -r
-
-
-Renderers API
--------------
-
-Renderers are subclasses of Text_Highlighter_Renderer. Renderer should
-override at least two methods - acceptToken and getOutput. Overriding other
-methods is optional, depending on the nature of renderer's output and details
-of implementation.
-
- string reset()
- resets renderer state. This method is called every time before a new
- source file is highlighted.
-
- string preprocess(string $code)
- preprocesses code. Can be used, for example, to normalize whitespace
- before highlighting. Returns preprocessed string.
-
- void acceptToken(string $group, string $content)
- the core method of the renderer. Highlighter passes chunks of text to
- this method in $content, and color group in $group
-
- void finalize()
- signals the renderer that no more tokens are available.
-
- mixed getOutput()
- returns generated output.
-
-
-Setting renderer options
---------------------------------
-
-Renderers accept an optional argument to their constructor - options array.
-Elements of this array are renderer-specific.
-
-HTML renderer
--------------
-
-HTML renderer produces HTML output with optional line numbering. The renderer
-itself does not provide information about actual colors of highlighted text.
-Instead, is used, where XXX is replaced with color group
-name (hl-var, hl-string, etc.). It is up to you to create a CSS stylesheet.
-If 'use_language' option with value evaluating to true was passed, class names
-will be formatted as "LANG-hl-XXX", where LANG is language name as defined in
-highlighter XML source ("lang" attribute of tag) in lower case.
-
-There are 3 special CSS classes:
-
- hl-main - this class applies to whole output or right table column,
- depending on 'numbers' option
- hl-gutter - applies to left column in table
- hl-table - applies to whole table
-
-HTML renderer accepts following options (each being optional):
-
- * numbers - line numbering style.
- 0 - no numbering (default)
- HL_NUMBERS_LI - use
for line numbering
- HL_NUMBERS_TABLE - create a 2-column table, with line numbers in left
- column and highlighted text in right column
-
- * tabsize - tabulation size. Defaults to 4
-
- Example:
-
- require_once 'Text/Highlighter/Renderer/Html.php';
- $options = array(
- 'numbers' => HL_NUMBERS_LI,
- 'tabsize' => 8,
- );
- $renderer = new Text_Highlighter_Renderer_HTML($options);
-
-Console renderer
-----------------
-
-Console renderer produces output for displaying on a color-capable terminal,
-either directly or through less -r, using ANSI escape sequences. By default,
-this renderer only highlights most common color groups. Additional colors
-can be specified using 'colors' option. This renderer also accepts 'numbers'
-option - a boolean value, and 'tabsize' option.
-
- Example :
-
- require_once 'Text/Highlighter/Renderer/Console.php';
- $colors = array(
- 'prepro' => "\033[35m",
- 'types' => "\033[32m",
- );
- $options = array(
- 'numbers' => true,
- 'tabsize' => 8,
- 'colors' => $colors,
- );
- $renderer = new Text_Highlighter_Renderer_Console($options);
-
-
-ANSI color escape sequences have the following format:
-
- ESC[#;#;....;#m
-
-where ESC is character with ASCII code 27 (033 octal, 0x1B hexadecimal). # is
-one of the following:
-
- 0 for normal display
- 1 for bold on
- 4 underline (mono only)
- 5 blink on
- 7 reverse video on
- 8 nondisplayed (invisible)
- 30 black foreground
- 31 red foreground
- 32 green foreground
- 33 yellow foreground
- 34 blue foreground
- 35 magenta foreground
- 36 cyan foreground
- 37 white foreground
- 40 black background
- 41 red background
- 42 green background
- 43 yellow background
- 44 blue background
- 45 magenta background
- 46 cyan background
- 47 white background
-
-
-How to use Text_Highlighter class
-=================================
-
-Creating a highlighter object
------------------------------
-
-To create a highlighter for a certain language, use Text_Highlighter::factory()
-static method:
-
- require_once 'Text/Highlighter.php';
- $hl = Text_Highlighter::factory('php');
-
-
-Setting a renderer
-------------------
-
-Actual output is produced by a renderer.
-
- require_once 'Text/Highlighter.php';
- require_once 'Text/Highlighter/Renderer/Html.php';
- $options = array(
- 'numbers' => HL_NUMBERS_LI,
- 'tabsize' => 8,
- );
- $renderer = new Text_Highlighter_Renderer_HTML($options);
- $hl = Text_Highlighter::factory('php');
- $hl->setRenderer($renderer);
-
-Note that for BC reasons, it is possible to use highlighter without setting a
-renderer. If no renderer is set, HTML renderer will be used by default. In
-this case, you should pass options as second parameter to factory method. The
-following example works exactly as previous one:
-
- require_once 'Text/Highlighter.php';
- $options = array(
- 'numbers' => HL_NUMBERS_LI,
- 'tabsize' => 8,
- );
- $hl = Text_Highlighter::factory('php', $options);
-
-
-Getting output
---------------
-
-And finally, do the highlighting and get the output:
-
- require_once 'Text/Highlighter.php';
- require_once 'Text/Highlighter/Renderer/Html.php';
- $options = array(
- 'numbers' => HL_NUMBERS_LI,
- 'tabsize' => 8,
- );
- $renderer = new Text_Highlighter_Renderer_HTML($options);
- $hl = Text_Highlighter::factory('php');
- $hl->setRenderer($renderer);
- $html = $hl->highlight(file_get_contents('example.php'));
-
-# vim: set autoindent tabstop=4 shiftwidth=4 softtabstop=4 tw=78: */
-
diff --git a/vendor/bin/composer-php b/vendor/bin/composer-php
new file mode 100644
index 000000000..ef944ba0d
--- /dev/null
+++ b/vendor/bin/composer-php
@@ -0,0 +1,15 @@
+#!/usr/bin/env sh
+SRC_DIR=`pwd`
+BIN_DIR=`dirname $0`
+VENDOR_DIR=$BIN_DIR/"../"
+DIRS=""
+for vendor in $VENDOR_DIR/*; do
+ if [ -d "$vendor" ]; then
+ for package in $vendor/*; do
+ if [ -d "$package" ]; then
+ DIRS="${DIRS}:${package}"
+ fi
+ done
+ fi
+done
+php -d include_path=".$DIRS" $@
diff --git a/vendor/bin/composer-php.bat b/vendor/bin/composer-php.bat
new file mode 100644
index 000000000..68cd54e4f
--- /dev/null
+++ b/vendor/bin/composer-php.bat
@@ -0,0 +1,11 @@
+@echo off
+setlocal enabledelayedexpansion
+set BIN_DIR=%~dp0
+set VENDOR_DIR=%BIN_DIR%\../
+set DIRS=.
+FOR /D %%V IN (%VENDOR_DIR%\*) DO (
+ FOR /D %%P IN (%%V\*) DO (
+ set DIRS=!DIRS!;%%~fP
+ )
+)
+php.exe -d include_path=!DIRS! %*
diff --git a/vendor/bin/generate b/vendor/bin/generate
new file mode 100644
index 000000000..b8b117247
--- /dev/null
+++ b/vendor/bin/generate
@@ -0,0 +1,17 @@
+#!/usr/bin/env sh
+
+dir=$(d=${0%[/\\]*}; cd "$d"; cd "../pear-pear.php.net/Text_Highlighter/bin" && pwd)
+
+# See if we are running in Cygwin by checking for cygpath program
+if command -v 'cygpath' >/dev/null 2>&1; then
+ # Cygwin paths start with /cygdrive/ which will break windows PHP,
+ # so we need to translate the dir path to windows format. However
+ # we could be using cygwin PHP which does not require this, so we
+ # test if the path to PHP starts with /cygdrive/ rather than /usr/bin
+ if [[ $(which php) == /cygdrive/* ]]; then
+ dir=$(cygpath -m "$dir");
+ fi
+fi
+
+dir=$(echo $dir | sed 's/ /\ /g')
+"${dir}/generate" "$@"
diff --git a/vendor/bin/generate.bat b/vendor/bin/generate.bat
new file mode 100644
index 000000000..0d6986c5a
--- /dev/null
+++ b/vendor/bin/generate.bat
@@ -0,0 +1,7 @@
+@echo off
+pushd .
+cd %~dp0
+cd "../pear-pear.php.net/Text_Highlighter/bin"
+set BIN_TARGET=%CD%\generate
+popd
+composer-php "%BIN_TARGET%" %*
diff --git a/vendor/bin/pear.bat b/vendor/bin/pear.bat
new file mode 100644
index 000000000..cb487f6f3
--- /dev/null
+++ b/vendor/bin/pear.bat
@@ -0,0 +1,7 @@
+@echo off
+pushd .
+cd %~dp0
+cd "../pear-pear.php.net/PEAR/bin"
+set BIN_TARGET=%CD%\pear.bat
+popd
+call "%BIN_TARGET%" %*
diff --git a/vendor/bin/peardev.bat b/vendor/bin/peardev.bat
new file mode 100644
index 000000000..cbd3811df
--- /dev/null
+++ b/vendor/bin/peardev.bat
@@ -0,0 +1,7 @@
+@echo off
+pushd .
+cd %~dp0
+cd "../pear-pear.php.net/PEAR/bin"
+set BIN_TARGET=%CD%\peardev.bat
+popd
+call "%BIN_TARGET%" %*
diff --git a/vendor/bin/pecl.bat b/vendor/bin/pecl.bat
new file mode 100644
index 000000000..1cb8d103c
--- /dev/null
+++ b/vendor/bin/pecl.bat
@@ -0,0 +1,7 @@
+@echo off
+pushd .
+cd %~dp0
+cd "../pear-pear.php.net/PEAR/bin"
+set BIN_TARGET=%CD%\pecl.bat
+popd
+call "%BIN_TARGET%" %*
diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php
index bc30e0f92..95407cff6 100644
--- a/vendor/composer/autoload_classmap.php
+++ b/vendor/composer/autoload_classmap.php
@@ -6,6 +6,8 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
+ 'Archive_Tar' => $vendorDir . '/pear-pear.php.net/Archive_Tar/Archive/Tar.php',
+ 'Console_Getopt' => $vendorDir . '/pear-pear.php.net/Console_Getopt/Console/Getopt.php',
'Detection\\MobileDetect' => $vendorDir . '/mobiledetect/mobiledetectlib/namespaced/Detection/MobileDetect.php',
'Friendica\\Core\\Config' => $baseDir . '/src/Core/Config.php',
'Friendica\\Core\\PConfig' => $baseDir . '/src/Core/PConfig.php',
@@ -240,4 +242,112 @@ return array(
'HTMLPurifier_VarParser_Native' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Native.php',
'HTMLPurifier_Zipper' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Zipper.php',
'Mobile_Detect' => $vendorDir . '/mobiledetect/mobiledetectlib/Mobile_Detect.php',
+ 'OS_Guess' => $vendorDir . '/pear-pear.php.net/PEAR/OS/Guess.php',
+ 'PEAR' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR.php',
+ 'PEAR_Builder' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Builder.php',
+ 'PEAR_ChannelFile' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/ChannelFile.php',
+ 'PEAR_ChannelFile_Parser' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/ChannelFile/Parser.php',
+ 'PEAR_Command' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Command.php',
+ 'PEAR_Command_Auth' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Command/Auth.php',
+ 'PEAR_Command_Build' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Command/Build.php',
+ 'PEAR_Command_Channels' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Command/Channels.php',
+ 'PEAR_Command_Common' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Command/Common.php',
+ 'PEAR_Command_Config' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Command/Config.php',
+ 'PEAR_Command_Install' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Command/Install.php',
+ 'PEAR_Command_Mirror' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Command/Mirror.php',
+ 'PEAR_Command_Package' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Command/Package.php',
+ 'PEAR_Command_Pickle' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Command/Pickle.php',
+ 'PEAR_Command_Registry' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Command/Registry.php',
+ 'PEAR_Command_Remote' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Command/Remote.php',
+ 'PEAR_Command_Test' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Command/Test.php',
+ 'PEAR_Common' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Common.php',
+ 'PEAR_Config' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Config.php',
+ 'PEAR_Dependency2' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Dependency2.php',
+ 'PEAR_DependencyDB' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/DependencyDB.php',
+ 'PEAR_Downloader' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Downloader.php',
+ 'PEAR_Downloader_Package' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Downloader/Package.php',
+ 'PEAR_Error' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR.php',
+ 'PEAR_ErrorStack' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/ErrorStack.php',
+ 'PEAR_Exception' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Exception.php',
+ 'PEAR_Frontend' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Frontend.php',
+ 'PEAR_Frontend_CLI' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Frontend/CLI.php',
+ 'PEAR_Installer' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Installer.php',
+ 'PEAR_Installer_Role' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Installer/Role.php',
+ 'PEAR_Installer_Role_Cfg' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Installer/Role/Cfg.php',
+ 'PEAR_Installer_Role_Common' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Installer/Role/Common.php',
+ 'PEAR_Installer_Role_Data' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Installer/Role/Data.php',
+ 'PEAR_Installer_Role_Doc' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Installer/Role/Doc.php',
+ 'PEAR_Installer_Role_Ext' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Installer/Role/Ext.php',
+ 'PEAR_Installer_Role_Man' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Installer/Role/Man.php',
+ 'PEAR_Installer_Role_Php' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Installer/Role/Php.php',
+ 'PEAR_Installer_Role_Script' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Installer/Role/Script.php',
+ 'PEAR_Installer_Role_Src' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Installer/Role/Src.php',
+ 'PEAR_Installer_Role_Test' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Installer/Role/Test.php',
+ 'PEAR_Installer_Role_Www' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Installer/Role/Www.php',
+ 'PEAR_PackageFile' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/PackageFile.php',
+ 'PEAR_PackageFile_Generator_v1' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/PackageFile/Generator/v1.php',
+ 'PEAR_PackageFile_Generator_v2' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/PackageFile/Generator/v2.php',
+ 'PEAR_PackageFile_Parser_v1' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/PackageFile/Parser/v1.php',
+ 'PEAR_PackageFile_Parser_v2' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/PackageFile/Parser/v2.php',
+ 'PEAR_PackageFile_v1' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/PackageFile/v1.php',
+ 'PEAR_PackageFile_v2' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/PackageFile/v2.php',
+ 'PEAR_PackageFile_v2_Validator' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/PackageFile/v2/Validator.php',
+ 'PEAR_PackageFile_v2_rw' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/PackageFile/v2/rw.php',
+ 'PEAR_Packager' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Packager.php',
+ 'PEAR_Proxy' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Proxy.php',
+ 'PEAR_REST' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/REST.php',
+ 'PEAR_REST_10' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/REST/10.php',
+ 'PEAR_REST_11' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/REST/11.php',
+ 'PEAR_REST_13' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/REST/13.php',
+ 'PEAR_Registry' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Registry.php',
+ 'PEAR_RunTest' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/RunTest.php',
+ 'PEAR_Task_Common' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Task/Common.php',
+ 'PEAR_Task_Postinstallscript' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Task/Postinstallscript.php',
+ 'PEAR_Task_Postinstallscript_rw' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Task/Postinstallscript/rw.php',
+ 'PEAR_Task_Replace' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Task/Replace.php',
+ 'PEAR_Task_Replace_rw' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Task/Replace/rw.php',
+ 'PEAR_Task_Unixeol' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Task/Unixeol.php',
+ 'PEAR_Task_Unixeol_rw' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Task/Unixeol/rw.php',
+ 'PEAR_Task_Windowseol' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Task/Windowseol.php',
+ 'PEAR_Task_Windowseol_rw' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Task/Windowseol/rw.php',
+ 'PEAR_Validate' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Validate.php',
+ 'PEAR_Validator_PECL' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/Validator/PECL.php',
+ 'PEAR_XMLParser' => $vendorDir . '/pear-pear.php.net/PEAR/PEAR/XMLParser.php',
+ 'Structures_Graph' => $vendorDir . '/pear-pear.php.net/Structures_Graph/Structures/Graph.php',
+ 'Structures_Graph_Manipulator_AcyclicTest' => $vendorDir . '/pear-pear.php.net/Structures_Graph/Structures/Graph/Manipulator/AcyclicTest.php',
+ 'Structures_Graph_Manipulator_TopologicalSorter' => $vendorDir . '/pear-pear.php.net/Structures_Graph/Structures/Graph/Manipulator/TopologicalSorter.php',
+ 'Structures_Graph_Node' => $vendorDir . '/pear-pear.php.net/Structures_Graph/Structures/Graph/Node.php',
+ 'System' => $vendorDir . '/pear-pear.php.net/PEAR/System.php',
+ 'Text_Highlighter' => $vendorDir . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter.php',
+ 'Text_Highlighter_ABAP' => $vendorDir . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/ABAP.php',
+ 'Text_Highlighter_AVRC' => $vendorDir . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/AVRC.php',
+ 'Text_Highlighter_CPP' => $vendorDir . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/CPP.php',
+ 'Text_Highlighter_CSS' => $vendorDir . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/CSS.php',
+ 'Text_Highlighter_DIFF' => $vendorDir . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/DIFF.php',
+ 'Text_Highlighter_DTD' => $vendorDir . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/DTD.php',
+ 'Text_Highlighter_Generator' => $vendorDir . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/Generator.php',
+ 'Text_Highlighter_HTML' => $vendorDir . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/HTML.php',
+ 'Text_Highlighter_JAVA' => $vendorDir . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/JAVA.php',
+ 'Text_Highlighter_JAVASCRIPT' => $vendorDir . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/JAVASCRIPT.php',
+ 'Text_Highlighter_MYSQL' => $vendorDir . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/MYSQL.php',
+ 'Text_Highlighter_PERL' => $vendorDir . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/PERL.php',
+ 'Text_Highlighter_PHP' => $vendorDir . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/PHP.php',
+ 'Text_Highlighter_PYTHON' => $vendorDir . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/PYTHON.php',
+ 'Text_Highlighter_RUBY' => $vendorDir . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/RUBY.php',
+ 'Text_Highlighter_Renderer' => $vendorDir . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/Renderer.php',
+ 'Text_Highlighter_Renderer_Array' => $vendorDir . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/Renderer/Array.php',
+ 'Text_Highlighter_Renderer_BB' => $vendorDir . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/Renderer/BB.php',
+ 'Text_Highlighter_Renderer_Console' => $vendorDir . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/Renderer/Console.php',
+ 'Text_Highlighter_Renderer_Html' => $vendorDir . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/Renderer/Html.php',
+ 'Text_Highlighter_Renderer_HtmlTags' => $vendorDir . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/Renderer/HtmlTags.php',
+ 'Text_Highlighter_Renderer_JSON' => $vendorDir . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/Renderer/JSON.php',
+ 'Text_Highlighter_Renderer_XML' => $vendorDir . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/Renderer/XML.php',
+ 'Text_Highlighter_SH' => $vendorDir . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/SH.php',
+ 'Text_Highlighter_SQL' => $vendorDir . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/SQL.php',
+ 'Text_Highlighter_VBSCRIPT' => $vendorDir . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/VBSCRIPT.php',
+ 'Text_Highlighter_XML' => $vendorDir . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/XML.php',
+ 'XML_Parser' => $vendorDir . '/pear-pear.php.net/XML_Parser/XML/Parser.php',
+ 'XML_Parser_Error' => $vendorDir . '/pear-pear.php.net/XML_Parser/XML/Parser.php',
+ 'XML_Parser_Simple' => $vendorDir . '/pear-pear.php.net/XML_Parser/XML/Parser/Simple.php',
+ 'XML_Util' => $vendorDir . '/pear-pear.php.net/XML_Util/XML/Util.php',
);
diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php
index 48923cf47..890b20c06 100644
--- a/vendor/composer/autoload_real.php
+++ b/vendor/composer/autoload_real.php
@@ -23,6 +23,10 @@ class ComposerAutoloaderInitFriendica
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInitFriendica', 'loadClassLoader'));
+ $includePaths = require __DIR__ . '/include_paths.php';
+ array_push($includePaths, get_include_path());
+ set_include_path(implode(PATH_SEPARATOR, $includePaths));
+
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require_once __DIR__ . '/autoload_static.php';
diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php
index f1f3423d8..370e53218 100644
--- a/vendor/composer/autoload_static.php
+++ b/vendor/composer/autoload_static.php
@@ -42,6 +42,8 @@ class ComposerStaticInitFriendica
);
public static $classMap = array (
+ 'Archive_Tar' => __DIR__ . '/..' . '/pear-pear.php.net/Archive_Tar/Archive/Tar.php',
+ 'Console_Getopt' => __DIR__ . '/..' . '/pear-pear.php.net/Console_Getopt/Console/Getopt.php',
'Detection\\MobileDetect' => __DIR__ . '/..' . '/mobiledetect/mobiledetectlib/namespaced/Detection/MobileDetect.php',
'Friendica\\Core\\Config' => __DIR__ . '/../..' . '/src/Core/Config.php',
'Friendica\\Core\\PConfig' => __DIR__ . '/../..' . '/src/Core/PConfig.php',
@@ -276,6 +278,114 @@ class ComposerStaticInitFriendica
'HTMLPurifier_VarParser_Native' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Native.php',
'HTMLPurifier_Zipper' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Zipper.php',
'Mobile_Detect' => __DIR__ . '/..' . '/mobiledetect/mobiledetectlib/Mobile_Detect.php',
+ 'OS_Guess' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/OS/Guess.php',
+ 'PEAR' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR.php',
+ 'PEAR_Builder' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Builder.php',
+ 'PEAR_ChannelFile' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/ChannelFile.php',
+ 'PEAR_ChannelFile_Parser' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/ChannelFile/Parser.php',
+ 'PEAR_Command' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Command.php',
+ 'PEAR_Command_Auth' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Command/Auth.php',
+ 'PEAR_Command_Build' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Command/Build.php',
+ 'PEAR_Command_Channels' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Command/Channels.php',
+ 'PEAR_Command_Common' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Command/Common.php',
+ 'PEAR_Command_Config' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Command/Config.php',
+ 'PEAR_Command_Install' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Command/Install.php',
+ 'PEAR_Command_Mirror' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Command/Mirror.php',
+ 'PEAR_Command_Package' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Command/Package.php',
+ 'PEAR_Command_Pickle' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Command/Pickle.php',
+ 'PEAR_Command_Registry' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Command/Registry.php',
+ 'PEAR_Command_Remote' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Command/Remote.php',
+ 'PEAR_Command_Test' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Command/Test.php',
+ 'PEAR_Common' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Common.php',
+ 'PEAR_Config' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Config.php',
+ 'PEAR_Dependency2' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Dependency2.php',
+ 'PEAR_DependencyDB' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/DependencyDB.php',
+ 'PEAR_Downloader' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Downloader.php',
+ 'PEAR_Downloader_Package' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Downloader/Package.php',
+ 'PEAR_Error' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR.php',
+ 'PEAR_ErrorStack' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/ErrorStack.php',
+ 'PEAR_Exception' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Exception.php',
+ 'PEAR_Frontend' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Frontend.php',
+ 'PEAR_Frontend_CLI' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Frontend/CLI.php',
+ 'PEAR_Installer' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Installer.php',
+ 'PEAR_Installer_Role' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Installer/Role.php',
+ 'PEAR_Installer_Role_Cfg' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Installer/Role/Cfg.php',
+ 'PEAR_Installer_Role_Common' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Installer/Role/Common.php',
+ 'PEAR_Installer_Role_Data' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Installer/Role/Data.php',
+ 'PEAR_Installer_Role_Doc' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Installer/Role/Doc.php',
+ 'PEAR_Installer_Role_Ext' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Installer/Role/Ext.php',
+ 'PEAR_Installer_Role_Man' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Installer/Role/Man.php',
+ 'PEAR_Installer_Role_Php' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Installer/Role/Php.php',
+ 'PEAR_Installer_Role_Script' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Installer/Role/Script.php',
+ 'PEAR_Installer_Role_Src' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Installer/Role/Src.php',
+ 'PEAR_Installer_Role_Test' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Installer/Role/Test.php',
+ 'PEAR_Installer_Role_Www' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Installer/Role/Www.php',
+ 'PEAR_PackageFile' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/PackageFile.php',
+ 'PEAR_PackageFile_Generator_v1' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/PackageFile/Generator/v1.php',
+ 'PEAR_PackageFile_Generator_v2' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/PackageFile/Generator/v2.php',
+ 'PEAR_PackageFile_Parser_v1' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/PackageFile/Parser/v1.php',
+ 'PEAR_PackageFile_Parser_v2' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/PackageFile/Parser/v2.php',
+ 'PEAR_PackageFile_v1' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/PackageFile/v1.php',
+ 'PEAR_PackageFile_v2' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/PackageFile/v2.php',
+ 'PEAR_PackageFile_v2_Validator' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/PackageFile/v2/Validator.php',
+ 'PEAR_PackageFile_v2_rw' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/PackageFile/v2/rw.php',
+ 'PEAR_Packager' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Packager.php',
+ 'PEAR_Proxy' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Proxy.php',
+ 'PEAR_REST' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/REST.php',
+ 'PEAR_REST_10' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/REST/10.php',
+ 'PEAR_REST_11' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/REST/11.php',
+ 'PEAR_REST_13' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/REST/13.php',
+ 'PEAR_Registry' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Registry.php',
+ 'PEAR_RunTest' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/RunTest.php',
+ 'PEAR_Task_Common' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Task/Common.php',
+ 'PEAR_Task_Postinstallscript' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Task/Postinstallscript.php',
+ 'PEAR_Task_Postinstallscript_rw' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Task/Postinstallscript/rw.php',
+ 'PEAR_Task_Replace' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Task/Replace.php',
+ 'PEAR_Task_Replace_rw' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Task/Replace/rw.php',
+ 'PEAR_Task_Unixeol' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Task/Unixeol.php',
+ 'PEAR_Task_Unixeol_rw' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Task/Unixeol/rw.php',
+ 'PEAR_Task_Windowseol' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Task/Windowseol.php',
+ 'PEAR_Task_Windowseol_rw' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Task/Windowseol/rw.php',
+ 'PEAR_Validate' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Validate.php',
+ 'PEAR_Validator_PECL' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/Validator/PECL.php',
+ 'PEAR_XMLParser' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/PEAR/XMLParser.php',
+ 'Structures_Graph' => __DIR__ . '/..' . '/pear-pear.php.net/Structures_Graph/Structures/Graph.php',
+ 'Structures_Graph_Manipulator_AcyclicTest' => __DIR__ . '/..' . '/pear-pear.php.net/Structures_Graph/Structures/Graph/Manipulator/AcyclicTest.php',
+ 'Structures_Graph_Manipulator_TopologicalSorter' => __DIR__ . '/..' . '/pear-pear.php.net/Structures_Graph/Structures/Graph/Manipulator/TopologicalSorter.php',
+ 'Structures_Graph_Node' => __DIR__ . '/..' . '/pear-pear.php.net/Structures_Graph/Structures/Graph/Node.php',
+ 'System' => __DIR__ . '/..' . '/pear-pear.php.net/PEAR/System.php',
+ 'Text_Highlighter' => __DIR__ . '/..' . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter.php',
+ 'Text_Highlighter_ABAP' => __DIR__ . '/..' . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/ABAP.php',
+ 'Text_Highlighter_AVRC' => __DIR__ . '/..' . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/AVRC.php',
+ 'Text_Highlighter_CPP' => __DIR__ . '/..' . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/CPP.php',
+ 'Text_Highlighter_CSS' => __DIR__ . '/..' . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/CSS.php',
+ 'Text_Highlighter_DIFF' => __DIR__ . '/..' . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/DIFF.php',
+ 'Text_Highlighter_DTD' => __DIR__ . '/..' . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/DTD.php',
+ 'Text_Highlighter_Generator' => __DIR__ . '/..' . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/Generator.php',
+ 'Text_Highlighter_HTML' => __DIR__ . '/..' . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/HTML.php',
+ 'Text_Highlighter_JAVA' => __DIR__ . '/..' . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/JAVA.php',
+ 'Text_Highlighter_JAVASCRIPT' => __DIR__ . '/..' . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/JAVASCRIPT.php',
+ 'Text_Highlighter_MYSQL' => __DIR__ . '/..' . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/MYSQL.php',
+ 'Text_Highlighter_PERL' => __DIR__ . '/..' . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/PERL.php',
+ 'Text_Highlighter_PHP' => __DIR__ . '/..' . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/PHP.php',
+ 'Text_Highlighter_PYTHON' => __DIR__ . '/..' . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/PYTHON.php',
+ 'Text_Highlighter_RUBY' => __DIR__ . '/..' . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/RUBY.php',
+ 'Text_Highlighter_Renderer' => __DIR__ . '/..' . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/Renderer.php',
+ 'Text_Highlighter_Renderer_Array' => __DIR__ . '/..' . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/Renderer/Array.php',
+ 'Text_Highlighter_Renderer_BB' => __DIR__ . '/..' . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/Renderer/BB.php',
+ 'Text_Highlighter_Renderer_Console' => __DIR__ . '/..' . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/Renderer/Console.php',
+ 'Text_Highlighter_Renderer_Html' => __DIR__ . '/..' . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/Renderer/Html.php',
+ 'Text_Highlighter_Renderer_HtmlTags' => __DIR__ . '/..' . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/Renderer/HtmlTags.php',
+ 'Text_Highlighter_Renderer_JSON' => __DIR__ . '/..' . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/Renderer/JSON.php',
+ 'Text_Highlighter_Renderer_XML' => __DIR__ . '/..' . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/Renderer/XML.php',
+ 'Text_Highlighter_SH' => __DIR__ . '/..' . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/SH.php',
+ 'Text_Highlighter_SQL' => __DIR__ . '/..' . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/SQL.php',
+ 'Text_Highlighter_VBSCRIPT' => __DIR__ . '/..' . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/VBSCRIPT.php',
+ 'Text_Highlighter_XML' => __DIR__ . '/..' . '/pear-pear.php.net/Text_Highlighter/Text/Highlighter/XML.php',
+ 'XML_Parser' => __DIR__ . '/..' . '/pear-pear.php.net/XML_Parser/XML/Parser.php',
+ 'XML_Parser_Error' => __DIR__ . '/..' . '/pear-pear.php.net/XML_Parser/XML/Parser.php',
+ 'XML_Parser_Simple' => __DIR__ . '/..' . '/pear-pear.php.net/XML_Parser/XML/Parser/Simple.php',
+ 'XML_Util' => __DIR__ . '/..' . '/pear-pear.php.net/XML_Util/XML/Util.php',
);
public static function getInitializer(ClassLoader $loader)
diff --git a/vendor/composer/include_paths.php b/vendor/composer/include_paths.php
new file mode 100644
index 000000000..e10abddcd
--- /dev/null
+++ b/vendor/composer/include_paths.php
@@ -0,0 +1,16 @@
+=5.4.0.0"
+ },
+ "replace": {
+ "pear-pear/console_getopt": "== 1.4.1.0"
+ },
+ "type": "pear-library",
+ "installation-source": "dist",
+ "autoload": {
+ "classmap": [
+ ""
+ ]
+ },
+ "include-path": [
+ "/"
+ ],
+ "license": [
+ "BSD-2-Clause"
+ ],
+ "description": "This is a PHP implementation of \"getopt\" supporting both\nshort and long options."
+ },
+ {
+ "name": "pear-pear.php.net/Archive_Tar",
+ "version": "1.4.2",
+ "version_normalized": "1.4.2.0",
+ "dist": {
+ "type": "file",
+ "url": "https://pear.php.net/get/Archive_Tar-1.4.2.tgz",
+ "reference": null,
+ "shasum": null
+ },
+ "require": {
+ "php": ">=5.2.0.0"
+ },
+ "replace": {
+ "pear-pear/archive_tar": "== 1.4.2.0"
+ },
+ "type": "pear-library",
+ "installation-source": "dist",
+ "autoload": {
+ "classmap": [
+ ""
+ ]
+ },
+ "include-path": [
+ "/"
+ ],
+ "license": [
+ "New BSD License"
+ ],
+ "description": "This class provides handling of tar files in PHP.\nIt supports creating, listing, extracting and adding to tar files.\nGzip support is available if PHP has the zlib extension built-in or\nloaded. Bz2 compression is also supported with the bz2 extension loaded."
+ },
+ {
+ "name": "pear-pear.php.net/Structures_Graph",
+ "version": "1.1.1",
+ "version_normalized": "1.1.1.0",
+ "dist": {
+ "type": "file",
+ "url": "https://pear.php.net/get/Structures_Graph-1.1.1.tgz",
+ "reference": null,
+ "shasum": null
+ },
+ "require": {
+ "php": ">=5.3.0.0"
+ },
+ "replace": {
+ "pear-pear/structures_graph": "== 1.1.1.0"
+ },
+ "type": "pear-library",
+ "installation-source": "dist",
+ "autoload": {
+ "classmap": [
+ ""
+ ]
+ },
+ "include-path": [
+ "/"
+ ],
+ "license": [
+ "LGPL-3.0+"
+ ],
+ "description": "Structures_Graph is a package for creating and manipulating graph datastructures. It allows building of directed\nand undirected graphs, with data and metadata stored in nodes. The library provides functions for graph traversing\nas well as for characteristic extraction from the graph topology."
+ },
+ {
+ "name": "pear-pear.php.net/XML_Util",
+ "version": "1.4.2",
+ "version_normalized": "1.4.2.0",
+ "dist": {
+ "type": "file",
+ "url": "https://pear.php.net/get/XML_Util-1.4.2.tgz",
+ "reference": null,
+ "shasum": null
+ },
+ "require": {
+ "ext-pcre": "*",
+ "php": ">=5.4.0.0"
+ },
+ "replace": {
+ "pear-pear/xml_util": "== 1.4.2.0"
+ },
+ "type": "pear-library",
+ "installation-source": "dist",
+ "autoload": {
+ "classmap": [
+ ""
+ ]
+ },
+ "include-path": [
+ "/"
+ ],
+ "license": [
+ "BSD License"
+ ],
+ "description": "Selection of methods that are often needed when working with XML documents. Functionality includes creating of attribute lists from arrays, creation of tags, validation of XML names and more."
+ },
+ {
+ "name": "pear-pear.php.net/XML_Parser",
+ "version": "1.3.7",
+ "version_normalized": "1.3.7.0",
+ "dist": {
+ "type": "file",
+ "url": "https://pear.php.net/get/XML_Parser-1.3.7.tgz",
+ "reference": null,
+ "shasum": null
+ },
+ "require": {
+ "pear-pear.php.net/pear": "*",
+ "php": ">=4.2.0.0"
+ },
+ "replace": {
+ "pear-pear/xml_parser": "== 1.3.7.0"
+ },
+ "type": "pear-library",
+ "installation-source": "dist",
+ "autoload": {
+ "classmap": [
+ ""
+ ]
+ },
+ "include-path": [
+ "/"
+ ],
+ "license": [
+ "BSD License"
+ ],
+ "description": "This is an XML parser based on PHPs built-in xml extension.\nIt supports two basic modes of operation: \"func\" and \"event\". In \"func\" mode, it will look for a function named after each element (xmltag_ELEMENT for start tags and xmltag_ELEMENT_ for end tags), and in \"event\" mode it uses a set of generic callbacks.\n\nSince version 1.2.0 there's a new XML_Parser_Simple class that makes parsing of most XML documents easier, by automatically providing a stack for the elements.\nFurthermore its now possible to split the parser from the handler object, so you do not have to extend XML_Parser anymore in order to parse a document with it."
+ },
+ {
+ "name": "pear-pear.php.net/PEAR",
+ "version": "1.10.3",
+ "version_normalized": "1.10.3.0",
+ "dist": {
+ "type": "file",
+ "url": "https://pear.php.net/get/PEAR-1.10.3.tgz",
+ "reference": null,
+ "shasum": null
+ },
+ "require": {
+ "ext-pcre": "*",
+ "ext-xml": "*",
+ "pear-pear.php.net/archive_tar": ">=1.4.0.0",
+ "pear-pear.php.net/console_getopt": ">=1.4.1.0",
+ "pear-pear.php.net/structures_graph": ">=1.1.0.0",
+ "pear-pear.php.net/xml_util": ">=1.3.0.0",
+ "php": ">=5.4.0.0"
+ },
+ "conflict": {
+ "pear-pear.php.net/pear_frontend_gtk": "<0.4.0.0",
+ "pear-pear.php.net/pear_frontend_web": "<=0.4.0.0"
+ },
+ "replace": {
+ "pear-pear/pear": "== 1.10.3.0"
+ },
+ "type": "pear-library",
+ "installation-source": "dist",
+ "autoload": {
+ "classmap": [
+ ""
+ ]
+ },
+ "include-path": [
+ "/"
+ ],
+ "license": [
+ "New BSD License"
+ ],
+ "description": "The PEAR package contains:\n * the PEAR installer, for creating, distributing\n and installing packages\n * the PEAR_Exception PHP5 error handling mechanism\n * the PEAR_ErrorStack advanced error handling mechanism\n * the PEAR_Error error handling mechanism\n * the OS_Guess class for retrieving info about the OS\n where PHP is running on\n * the System class for quick handling of common operations\n with files and directories\n * the PEAR base class\n Features in a nutshell:\n * full support for channels\n * pre-download dependency validation\n * new package.xml 2.0 format allows tremendous flexibility while maintaining BC\n * support for optional dependency groups and limited support for sub-packaging\n * robust dependency support\n * full dependency validation on uninstall\n * remote install for hosts with only ftp access - no more problems with\n restricted host installation\n * full support for mirroring\n * support for bundling several packages into a single tarball\n * support for static dependencies on a url-based package\n * support for custom file roles and installation tasks"
+ },
+ {
+ "name": "pear-pear.php.net/Text_Highlighter",
+ "version": "0.8.0",
+ "version_normalized": "0.8.0.0",
+ "dist": {
+ "type": "file",
+ "url": "https://pear.php.net/get/Text_Highlighter-0.8.0.tgz",
+ "reference": null,
+ "shasum": null
+ },
+ "require": {
+ "pear-pear.php.net/console_getopt": ">=1.4.1.0",
+ "pear-pear.php.net/pear": ">=1.10.3.0",
+ "pear-pear.php.net/xml_parser": ">=1.3.7.0",
+ "php": ">=5.4.0.0"
+ },
+ "replace": {
+ "pear-pear/text_highlighter": "== 0.8.0.0"
+ },
+ "type": "pear-library",
+ "installation-source": "dist",
+ "autoload": {
+ "classmap": [
+ ""
+ ]
+ },
+ "include-path": [
+ "/"
+ ],
+ "license": [
+ "PHP License"
+ ],
+ "description": "Text_Highlighter is a package for syntax highlighting.\n\nIt provides a base class provining all the functionality,\nand a descendent classes geneator class.\n\nThe main idea is to simplify creation of subclasses\nimplementing syntax highlighting for particular language.\nSubclasses do not implement any new functioanality,\nthey just provide syntax highlighting rules.\nThe rules sources are in XML format.\n\nTo create a highlighter for a language, there is no need\nto code a new class manually. Simply describe the rules\nin XML file and use Text_Highlighter_Generator to create\na new class."
}
]
diff --git a/vendor/pear-pear.php.net/Archive_Tar/Archive/Tar.php b/vendor/pear-pear.php.net/Archive_Tar/Archive/Tar.php
new file mode 100644
index 000000000..202fffb23
--- /dev/null
+++ b/vendor/pear-pear.php.net/Archive_Tar/Archive/Tar.php
@@ -0,0 +1,2421 @@
+
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category File_Formats
+ * @package Archive_Tar
+ * @author Vincent Blavet
+ * @copyright 1997-2010 The Authors
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @version CVS: $Id$
+ * @link http://pear.php.net/package/Archive_Tar
+ */
+
+// If the PEAR class cannot be loaded via the autoloader,
+// then try to require_once it from the PHP include path.
+if (!class_exists('PEAR')) {
+ require_once 'PEAR.php';
+}
+
+define('ARCHIVE_TAR_ATT_SEPARATOR', 90001);
+define('ARCHIVE_TAR_END_BLOCK', pack("a512", ''));
+
+if (!function_exists('gzopen') && function_exists('gzopen64')) {
+ function gzopen($filename, $mode, $use_include_path = 0)
+ {
+ return gzopen64($filename, $mode, $use_include_path);
+ }
+}
+
+if (!function_exists('gztell') && function_exists('gztell64')) {
+ function gztell($zp)
+ {
+ return gztell64($zp);
+ }
+}
+
+if (!function_exists('gzseek') && function_exists('gzseek64')) {
+ function gzseek($zp, $offset, $whence = SEEK_SET)
+ {
+ return gzseek64($zp, $offset, $whence);
+ }
+}
+
+/**
+ * Creates a (compressed) Tar archive
+ *
+ * @package Archive_Tar
+ * @author Vincent Blavet
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @version $Revision$
+ */
+class Archive_Tar extends PEAR
+{
+ /**
+ * @var string Name of the Tar
+ */
+ public $_tarname = '';
+
+ /**
+ * @var boolean if true, the Tar file will be gzipped
+ */
+ public $_compress = false;
+
+ /**
+ * @var string Type of compression : 'none', 'gz', 'bz2' or 'lzma2'
+ */
+ public $_compress_type = 'none';
+
+ /**
+ * @var string Explode separator
+ */
+ public $_separator = ' ';
+
+ /**
+ * @var file descriptor
+ */
+ public $_file = 0;
+
+ /**
+ * @var string Local Tar name of a remote Tar (http:// or ftp://)
+ */
+ public $_temp_tarname = '';
+
+ /**
+ * @var string regular expression for ignoring files or directories
+ */
+ public $_ignore_regexp = '';
+
+ /**
+ * @var object PEAR_Error object
+ */
+ public $error_object = null;
+
+ /**
+ * Format for data extraction
+ *
+ * @var string
+ */
+ public $_fmt ='';
+ /**
+ * Archive_Tar Class constructor. This flavour of the constructor only
+ * declare a new Archive_Tar object, identifying it by the name of the
+ * tar file.
+ * If the compress argument is set the tar will be read or created as a
+ * gzip or bz2 compressed TAR file.
+ *
+ * @param string $p_tarname The name of the tar archive to create
+ * @param string $p_compress can be null, 'gz', 'bz2' or 'lzma2'. This
+ * parameter indicates if gzip, bz2 or lzma2 compression
+ * is required. For compatibility reason the
+ * boolean value 'true' means 'gz'.
+ *
+ * @return bool
+ */
+ public function __construct($p_tarname, $p_compress = null)
+ {
+ parent::__construct();
+
+ $this->_compress = false;
+ $this->_compress_type = 'none';
+ if (($p_compress === null) || ($p_compress == '')) {
+ if (@file_exists($p_tarname)) {
+ if ($fp = @fopen($p_tarname, "rb")) {
+ // look for gzip magic cookie
+ $data = fread($fp, 2);
+ fclose($fp);
+ if ($data == "\37\213") {
+ $this->_compress = true;
+ $this->_compress_type = 'gz';
+ // No sure it's enought for a magic code ....
+ } elseif ($data == "BZ") {
+ $this->_compress = true;
+ $this->_compress_type = 'bz2';
+ } elseif (file_get_contents($p_tarname, false, null, 1, 4) == '7zXZ') {
+ $this->_compress = true;
+ $this->_compress_type = 'lzma2';
+ }
+ }
+ } else {
+ // probably a remote file or some file accessible
+ // through a stream interface
+ if (substr($p_tarname, -2) == 'gz') {
+ $this->_compress = true;
+ $this->_compress_type = 'gz';
+ } elseif ((substr($p_tarname, -3) == 'bz2') ||
+ (substr($p_tarname, -2) == 'bz')
+ ) {
+ $this->_compress = true;
+ $this->_compress_type = 'bz2';
+ } else {
+ if (substr($p_tarname, -2) == 'xz') {
+ $this->_compress = true;
+ $this->_compress_type = 'lzma2';
+ }
+ }
+ }
+ } else {
+ if (($p_compress === true) || ($p_compress == 'gz')) {
+ $this->_compress = true;
+ $this->_compress_type = 'gz';
+ } else {
+ if ($p_compress == 'bz2') {
+ $this->_compress = true;
+ $this->_compress_type = 'bz2';
+ } else {
+ if ($p_compress == 'lzma2') {
+ $this->_compress = true;
+ $this->_compress_type = 'lzma2';
+ } else {
+ $this->_error(
+ "Unsupported compression type '$p_compress'\n" .
+ "Supported types are 'gz', 'bz2' and 'lzma2'.\n"
+ );
+ return false;
+ }
+ }
+ }
+ }
+ $this->_tarname = $p_tarname;
+ if ($this->_compress) { // assert zlib or bz2 or xz extension support
+ if ($this->_compress_type == 'gz') {
+ $extname = 'zlib';
+ } else {
+ if ($this->_compress_type == 'bz2') {
+ $extname = 'bz2';
+ } else {
+ if ($this->_compress_type == 'lzma2') {
+ $extname = 'xz';
+ }
+ }
+ }
+
+ if (!extension_loaded($extname)) {
+ PEAR::loadExtension($extname);
+ }
+ if (!extension_loaded($extname)) {
+ $this->_error(
+ "The extension '$extname' couldn't be found.\n" .
+ "Please make sure your version of PHP was built " .
+ "with '$extname' support.\n"
+ );
+ return false;
+ }
+ }
+
+
+ if (version_compare(PHP_VERSION, "5.5.0-dev") < 0) {
+ $this->_fmt = "a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/" .
+ "a8checksum/a1typeflag/a100link/a6magic/a2version/" .
+ "a32uname/a32gname/a8devmajor/a8devminor/a131prefix";
+ } else {
+ $this->_fmt = "Z100filename/Z8mode/Z8uid/Z8gid/Z12size/Z12mtime/" .
+ "Z8checksum/Z1typeflag/Z100link/Z6magic/Z2version/" .
+ "Z32uname/Z32gname/Z8devmajor/Z8devminor/Z131prefix";
+ }
+
+
+ }
+
+ public function __destruct()
+ {
+ $this->_close();
+ // ----- Look for a local copy to delete
+ if ($this->_temp_tarname != '') {
+ @unlink($this->_temp_tarname);
+ }
+ }
+
+ /**
+ * This method creates the archive file and add the files / directories
+ * that are listed in $p_filelist.
+ * If a file with the same name exist and is writable, it is replaced
+ * by the new tar.
+ * The method return false and a PEAR error text.
+ * The $p_filelist parameter can be an array of string, each string
+ * representing a filename or a directory name with their path if
+ * needed. It can also be a single string with names separated by a
+ * single blank.
+ * For each directory added in the archive, the files and
+ * sub-directories are also added.
+ * See also createModify() method for more details.
+ *
+ * @param array $p_filelist An array of filenames and directory names, or a
+ * single string with names separated by a single
+ * blank space.
+ *
+ * @return true on success, false on error.
+ * @see createModify()
+ */
+ public function create($p_filelist)
+ {
+ return $this->createModify($p_filelist, '', '');
+ }
+
+ /**
+ * This method add the files / directories that are listed in $p_filelist in
+ * the archive. If the archive does not exist it is created.
+ * The method return false and a PEAR error text.
+ * The files and directories listed are only added at the end of the archive,
+ * even if a file with the same name is already archived.
+ * See also createModify() method for more details.
+ *
+ * @param array $p_filelist An array of filenames and directory names, or a
+ * single string with names separated by a single
+ * blank space.
+ *
+ * @return true on success, false on error.
+ * @see createModify()
+ * @access public
+ */
+ public function add($p_filelist)
+ {
+ return $this->addModify($p_filelist, '', '');
+ }
+
+ /**
+ * @param string $p_path
+ * @param bool $p_preserve
+ * @return bool
+ */
+ public function extract($p_path = '', $p_preserve = false)
+ {
+ return $this->extractModify($p_path, '', $p_preserve);
+ }
+
+ /**
+ * @return array|int
+ */
+ public function listContent()
+ {
+ $v_list_detail = array();
+
+ if ($this->_openRead()) {
+ if (!$this->_extractList('', $v_list_detail, "list", '', '')) {
+ unset($v_list_detail);
+ $v_list_detail = 0;
+ }
+ $this->_close();
+ }
+
+ return $v_list_detail;
+ }
+
+ /**
+ * This method creates the archive file and add the files / directories
+ * that are listed in $p_filelist.
+ * If the file already exists and is writable, it is replaced by the
+ * new tar. It is a create and not an add. If the file exists and is
+ * read-only or is a directory it is not replaced. The method return
+ * false and a PEAR error text.
+ * The $p_filelist parameter can be an array of string, each string
+ * representing a filename or a directory name with their path if
+ * needed. It can also be a single string with names separated by a
+ * single blank.
+ * The path indicated in $p_remove_dir will be removed from the
+ * memorized path of each file / directory listed when this path
+ * exists. By default nothing is removed (empty path '')
+ * The path indicated in $p_add_dir will be added at the beginning of
+ * the memorized path of each file / directory listed. However it can
+ * be set to empty ''. The adding of a path is done after the removing
+ * of path.
+ * The path add/remove ability enables the user to prepare an archive
+ * for extraction in a different path than the origin files are.
+ * See also addModify() method for file adding properties.
+ *
+ * @param array $p_filelist An array of filenames and directory names,
+ * or a single string with names separated by
+ * a single blank space.
+ * @param string $p_add_dir A string which contains a path to be added
+ * to the memorized path of each element in
+ * the list.
+ * @param string $p_remove_dir A string which contains a path to be
+ * removed from the memorized path of each
+ * element in the list, when relevant.
+ *
+ * @return boolean true on success, false on error.
+ * @see addModify()
+ */
+ public function createModify($p_filelist, $p_add_dir, $p_remove_dir = '')
+ {
+ $v_result = true;
+
+ if (!$this->_openWrite()) {
+ return false;
+ }
+
+ if ($p_filelist != '') {
+ if (is_array($p_filelist)) {
+ $v_list = $p_filelist;
+ } elseif (is_string($p_filelist)) {
+ $v_list = explode($this->_separator, $p_filelist);
+ } else {
+ $this->_cleanFile();
+ $this->_error('Invalid file list');
+ return false;
+ }
+
+ $v_result = $this->_addList($v_list, $p_add_dir, $p_remove_dir);
+ }
+
+ if ($v_result) {
+ $this->_writeFooter();
+ $this->_close();
+ } else {
+ $this->_cleanFile();
+ }
+
+ return $v_result;
+ }
+
+ /**
+ * This method add the files / directories listed in $p_filelist at the
+ * end of the existing archive. If the archive does not yet exists it
+ * is created.
+ * The $p_filelist parameter can be an array of string, each string
+ * representing a filename or a directory name with their path if
+ * needed. It can also be a single string with names separated by a
+ * single blank.
+ * The path indicated in $p_remove_dir will be removed from the
+ * memorized path of each file / directory listed when this path
+ * exists. By default nothing is removed (empty path '')
+ * The path indicated in $p_add_dir will be added at the beginning of
+ * the memorized path of each file / directory listed. However it can
+ * be set to empty ''. The adding of a path is done after the removing
+ * of path.
+ * The path add/remove ability enables the user to prepare an archive
+ * for extraction in a different path than the origin files are.
+ * If a file/dir is already in the archive it will only be added at the
+ * end of the archive. There is no update of the existing archived
+ * file/dir. However while extracting the archive, the last file will
+ * replace the first one. This results in a none optimization of the
+ * archive size.
+ * If a file/dir does not exist the file/dir is ignored. However an
+ * error text is send to PEAR error.
+ * If a file/dir is not readable the file/dir is ignored. However an
+ * error text is send to PEAR error.
+ *
+ * @param array $p_filelist An array of filenames and directory
+ * names, or a single string with names
+ * separated by a single blank space.
+ * @param string $p_add_dir A string which contains a path to be
+ * added to the memorized path of each
+ * element in the list.
+ * @param string $p_remove_dir A string which contains a path to be
+ * removed from the memorized path of
+ * each element in the list, when
+ * relevant.
+ *
+ * @return true on success, false on error.
+ */
+ public function addModify($p_filelist, $p_add_dir, $p_remove_dir = '')
+ {
+ $v_result = true;
+
+ if (!$this->_isArchive()) {
+ $v_result = $this->createModify(
+ $p_filelist,
+ $p_add_dir,
+ $p_remove_dir
+ );
+ } else {
+ if (is_array($p_filelist)) {
+ $v_list = $p_filelist;
+ } elseif (is_string($p_filelist)) {
+ $v_list = explode($this->_separator, $p_filelist);
+ } else {
+ $this->_error('Invalid file list');
+ return false;
+ }
+
+ $v_result = $this->_append($v_list, $p_add_dir, $p_remove_dir);
+ }
+
+ return $v_result;
+ }
+
+ /**
+ * This method add a single string as a file at the
+ * end of the existing archive. If the archive does not yet exists it
+ * is created.
+ *
+ * @param string $p_filename A string which contains the full
+ * filename path that will be associated
+ * with the string.
+ * @param string $p_string The content of the file added in
+ * the archive.
+ * @param bool|int $p_datetime A custom date/time (unix timestamp)
+ * for the file (optional).
+ * @param array $p_params An array of optional params:
+ * stamp => the datetime (replaces
+ * datetime above if it exists)
+ * mode => the permissions on the
+ * file (600 by default)
+ * type => is this a link? See the
+ * tar specification for details.
+ * (default = regular file)
+ * uid => the user ID of the file
+ * (default = 0 = root)
+ * gid => the group ID of the file
+ * (default = 0 = root)
+ *
+ * @return true on success, false on error.
+ */
+ public function addString($p_filename, $p_string, $p_datetime = false, $p_params = array())
+ {
+ $p_stamp = @$p_params["stamp"] ? $p_params["stamp"] : ($p_datetime ? $p_datetime : time());
+ $p_mode = @$p_params["mode"] ? $p_params["mode"] : 0600;
+ $p_type = @$p_params["type"] ? $p_params["type"] : "";
+ $p_uid = @$p_params["uid"] ? $p_params["uid"] : "";
+ $p_gid = @$p_params["gid"] ? $p_params["gid"] : "";
+ $v_result = true;
+
+ if (!$this->_isArchive()) {
+ if (!$this->_openWrite()) {
+ return false;
+ }
+ $this->_close();
+ }
+
+ if (!$this->_openAppend()) {
+ return false;
+ }
+
+ // Need to check the get back to the temporary file ? ....
+ $v_result = $this->_addString($p_filename, $p_string, $p_datetime, $p_params);
+
+ $this->_writeFooter();
+
+ $this->_close();
+
+ return $v_result;
+ }
+
+ /**
+ * This method extract all the content of the archive in the directory
+ * indicated by $p_path. When relevant the memorized path of the
+ * files/dir can be modified by removing the $p_remove_path path at the
+ * beginning of the file/dir path.
+ * While extracting a file, if the directory path does not exists it is
+ * created.
+ * While extracting a file, if the file already exists it is replaced
+ * without looking for last modification date.
+ * While extracting a file, if the file already exists and is write
+ * protected, the extraction is aborted.
+ * While extracting a file, if a directory with the same name already
+ * exists, the extraction is aborted.
+ * While extracting a directory, if a file with the same name already
+ * exists, the extraction is aborted.
+ * While extracting a file/directory if the destination directory exist
+ * and is write protected, or does not exist but can not be created,
+ * the extraction is aborted.
+ * If after extraction an extracted file does not show the correct
+ * stored file size, the extraction is aborted.
+ * When the extraction is aborted, a PEAR error text is set and false
+ * is returned. However the result can be a partial extraction that may
+ * need to be manually cleaned.
+ *
+ * @param string $p_path The path of the directory where the
+ * files/dir need to by extracted.
+ * @param string $p_remove_path Part of the memorized path that can be
+ * removed if present at the beginning of
+ * the file/dir path.
+ * @param boolean $p_preserve Preserve user/group ownership of files
+ *
+ * @return boolean true on success, false on error.
+ * @see extractList()
+ */
+ public function extractModify($p_path, $p_remove_path, $p_preserve = false)
+ {
+ $v_result = true;
+ $v_list_detail = array();
+
+ if ($v_result = $this->_openRead()) {
+ $v_result = $this->_extractList(
+ $p_path,
+ $v_list_detail,
+ "complete",
+ 0,
+ $p_remove_path,
+ $p_preserve
+ );
+ $this->_close();
+ }
+
+ return $v_result;
+ }
+
+ /**
+ * This method extract from the archive one file identified by $p_filename.
+ * The return value is a string with the file content, or NULL on error.
+ *
+ * @param string $p_filename The path of the file to extract in a string.
+ *
+ * @return a string with the file content or NULL.
+ */
+ public function extractInString($p_filename)
+ {
+ if ($this->_openRead()) {
+ $v_result = $this->_extractInString($p_filename);
+ $this->_close();
+ } else {
+ $v_result = null;
+ }
+
+ return $v_result;
+ }
+
+ /**
+ * This method extract from the archive only the files indicated in the
+ * $p_filelist. These files are extracted in the current directory or
+ * in the directory indicated by the optional $p_path parameter.
+ * If indicated the $p_remove_path can be used in the same way as it is
+ * used in extractModify() method.
+ *
+ * @param array $p_filelist An array of filenames and directory names,
+ * or a single string with names separated
+ * by a single blank space.
+ * @param string $p_path The path of the directory where the
+ * files/dir need to by extracted.
+ * @param string $p_remove_path Part of the memorized path that can be
+ * removed if present at the beginning of
+ * the file/dir path.
+ * @param boolean $p_preserve Preserve user/group ownership of files
+ *
+ * @return true on success, false on error.
+ * @see extractModify()
+ */
+ public function extractList($p_filelist, $p_path = '', $p_remove_path = '', $p_preserve = false)
+ {
+ $v_result = true;
+ $v_list_detail = array();
+
+ if (is_array($p_filelist)) {
+ $v_list = $p_filelist;
+ } elseif (is_string($p_filelist)) {
+ $v_list = explode($this->_separator, $p_filelist);
+ } else {
+ $this->_error('Invalid string list');
+ return false;
+ }
+
+ if ($v_result = $this->_openRead()) {
+ $v_result = $this->_extractList(
+ $p_path,
+ $v_list_detail,
+ "partial",
+ $v_list,
+ $p_remove_path,
+ $p_preserve
+ );
+ $this->_close();
+ }
+
+ return $v_result;
+ }
+
+ /**
+ * This method set specific attributes of the archive. It uses a variable
+ * list of parameters, in the format attribute code + attribute values :
+ * $arch->setAttribute(ARCHIVE_TAR_ATT_SEPARATOR, ',');
+ *
+ * @return true on success, false on error.
+ */
+ public function setAttribute()
+ {
+ $v_result = true;
+
+ // ----- Get the number of variable list of arguments
+ if (($v_size = func_num_args()) == 0) {
+ return true;
+ }
+
+ // ----- Get the arguments
+ $v_att_list = & func_get_args();
+
+ // ----- Read the attributes
+ $i = 0;
+ while ($i < $v_size) {
+
+ // ----- Look for next option
+ switch ($v_att_list[$i]) {
+ // ----- Look for options that request a string value
+ case ARCHIVE_TAR_ATT_SEPARATOR :
+ // ----- Check the number of parameters
+ if (($i + 1) >= $v_size) {
+ $this->_error(
+ 'Invalid number of parameters for '
+ . 'attribute ARCHIVE_TAR_ATT_SEPARATOR'
+ );
+ return false;
+ }
+
+ // ----- Get the value
+ $this->_separator = $v_att_list[$i + 1];
+ $i++;
+ break;
+
+ default :
+ $this->_error('Unknown attribute code ' . $v_att_list[$i] . '');
+ return false;
+ }
+
+ // ----- Next attribute
+ $i++;
+ }
+
+ return $v_result;
+ }
+
+ /**
+ * This method sets the regular expression for ignoring files and directories
+ * at import, for example:
+ * $arch->setIgnoreRegexp("#CVS|\.svn#");
+ *
+ * @param string $regexp regular expression defining which files or directories to ignore
+ */
+ public function setIgnoreRegexp($regexp)
+ {
+ $this->_ignore_regexp = $regexp;
+ }
+
+ /**
+ * This method sets the regular expression for ignoring all files and directories
+ * matching the filenames in the array list at import, for example:
+ * $arch->setIgnoreList(array('CVS', '.svn', 'bin/tool'));
+ *
+ * @param array $list a list of file or directory names to ignore
+ *
+ * @access public
+ */
+ public function setIgnoreList($list)
+ {
+ $regexp = str_replace(array('#', '.', '^', '$'), array('\#', '\.', '\^', '\$'), $list);
+ $regexp = '#/' . join('$|/', $list) . '#';
+ $this->setIgnoreRegexp($regexp);
+ }
+
+ /**
+ * @param string $p_message
+ */
+ public function _error($p_message)
+ {
+ $this->error_object = $this->raiseError($p_message);
+ }
+
+ /**
+ * @param string $p_message
+ */
+ public function _warning($p_message)
+ {
+ $this->error_object = $this->raiseError($p_message);
+ }
+
+ /**
+ * @param string $p_filename
+ * @return bool
+ */
+ public function _isArchive($p_filename = null)
+ {
+ if ($p_filename == null) {
+ $p_filename = $this->_tarname;
+ }
+ clearstatcache();
+ return @is_file($p_filename) && !@is_link($p_filename);
+ }
+
+ /**
+ * @return bool
+ */
+ public function _openWrite()
+ {
+ if ($this->_compress_type == 'gz' && function_exists('gzopen')) {
+ $this->_file = @gzopen($this->_tarname, "wb9");
+ } else {
+ if ($this->_compress_type == 'bz2' && function_exists('bzopen')) {
+ $this->_file = @bzopen($this->_tarname, "w");
+ } else {
+ if ($this->_compress_type == 'lzma2' && function_exists('xzopen')) {
+ $this->_file = @xzopen($this->_tarname, 'w');
+ } else {
+ if ($this->_compress_type == 'none') {
+ $this->_file = @fopen($this->_tarname, "wb");
+ } else {
+ $this->_error(
+ 'Unknown or missing compression type ('
+ . $this->_compress_type . ')'
+ );
+ return false;
+ }
+ }
+ }
+ }
+
+ if ($this->_file == 0) {
+ $this->_error(
+ 'Unable to open in write mode \''
+ . $this->_tarname . '\''
+ );
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * @return bool
+ */
+ public function _openRead()
+ {
+ if (strtolower(substr($this->_tarname, 0, 7)) == 'http://') {
+
+ // ----- Look if a local copy need to be done
+ if ($this->_temp_tarname == '') {
+ $this->_temp_tarname = uniqid('tar') . '.tmp';
+ if (!$v_file_from = @fopen($this->_tarname, 'rb')) {
+ $this->_error(
+ 'Unable to open in read mode \''
+ . $this->_tarname . '\''
+ );
+ $this->_temp_tarname = '';
+ return false;
+ }
+ if (!$v_file_to = @fopen($this->_temp_tarname, 'wb')) {
+ $this->_error(
+ 'Unable to open in write mode \''
+ . $this->_temp_tarname . '\''
+ );
+ $this->_temp_tarname = '';
+ return false;
+ }
+ while ($v_data = @fread($v_file_from, 1024)) {
+ @fwrite($v_file_to, $v_data);
+ }
+ @fclose($v_file_from);
+ @fclose($v_file_to);
+ }
+
+ // ----- File to open if the local copy
+ $v_filename = $this->_temp_tarname;
+ } else {
+ // ----- File to open if the normal Tar file
+
+ $v_filename = $this->_tarname;
+ }
+
+ if ($this->_compress_type == 'gz' && function_exists('gzopen')) {
+ $this->_file = @gzopen($v_filename, "rb");
+ } else {
+ if ($this->_compress_type == 'bz2' && function_exists('bzopen')) {
+ $this->_file = @bzopen($v_filename, "r");
+ } else {
+ if ($this->_compress_type == 'lzma2' && function_exists('xzopen')) {
+ $this->_file = @xzopen($v_filename, "r");
+ } else {
+ if ($this->_compress_type == 'none') {
+ $this->_file = @fopen($v_filename, "rb");
+ } else {
+ $this->_error(
+ 'Unknown or missing compression type ('
+ . $this->_compress_type . ')'
+ );
+ return false;
+ }
+ }
+ }
+ }
+
+ if ($this->_file == 0) {
+ $this->_error('Unable to open in read mode \'' . $v_filename . '\'');
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * @return bool
+ */
+ public function _openReadWrite()
+ {
+ if ($this->_compress_type == 'gz') {
+ $this->_file = @gzopen($this->_tarname, "r+b");
+ } else {
+ if ($this->_compress_type == 'bz2') {
+ $this->_error(
+ 'Unable to open bz2 in read/write mode \''
+ . $this->_tarname . '\' (limitation of bz2 extension)'
+ );
+ return false;
+ } else {
+ if ($this->_compress_type == 'lzma2') {
+ $this->_error(
+ 'Unable to open lzma2 in read/write mode \''
+ . $this->_tarname . '\' (limitation of lzma2 extension)'
+ );
+ return false;
+ } else {
+ if ($this->_compress_type == 'none') {
+ $this->_file = @fopen($this->_tarname, "r+b");
+ } else {
+ $this->_error(
+ 'Unknown or missing compression type ('
+ . $this->_compress_type . ')'
+ );
+ return false;
+ }
+ }
+ }
+ }
+
+ if ($this->_file == 0) {
+ $this->_error(
+ 'Unable to open in read/write mode \''
+ . $this->_tarname . '\''
+ );
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * @return bool
+ */
+ public function _close()
+ {
+ //if (isset($this->_file)) {
+ if (is_resource($this->_file)) {
+ if ($this->_compress_type == 'gz') {
+ @gzclose($this->_file);
+ } else {
+ if ($this->_compress_type == 'bz2') {
+ @bzclose($this->_file);
+ } else {
+ if ($this->_compress_type == 'lzma2') {
+ @xzclose($this->_file);
+ } else {
+ if ($this->_compress_type == 'none') {
+ @fclose($this->_file);
+ } else {
+ $this->_error(
+ 'Unknown or missing compression type ('
+ . $this->_compress_type . ')'
+ );
+ }
+ }
+ }
+ }
+
+ $this->_file = 0;
+ }
+
+ // ----- Look if a local copy need to be erase
+ // Note that it might be interesting to keep the url for a time : ToDo
+ if ($this->_temp_tarname != '') {
+ @unlink($this->_temp_tarname);
+ $this->_temp_tarname = '';
+ }
+
+ return true;
+ }
+
+ /**
+ * @return bool
+ */
+ public function _cleanFile()
+ {
+ $this->_close();
+
+ // ----- Look for a local copy
+ if ($this->_temp_tarname != '') {
+ // ----- Remove the local copy but not the remote tarname
+ @unlink($this->_temp_tarname);
+ $this->_temp_tarname = '';
+ } else {
+ // ----- Remove the local tarname file
+ @unlink($this->_tarname);
+ }
+ $this->_tarname = '';
+
+ return true;
+ }
+
+ /**
+ * @param mixed $p_binary_data
+ * @param integer $p_len
+ * @return bool
+ */
+ public function _writeBlock($p_binary_data, $p_len = null)
+ {
+ if (is_resource($this->_file)) {
+ if ($p_len === null) {
+ if ($this->_compress_type == 'gz') {
+ @gzputs($this->_file, $p_binary_data);
+ } else {
+ if ($this->_compress_type == 'bz2') {
+ @bzwrite($this->_file, $p_binary_data);
+ } else {
+ if ($this->_compress_type == 'lzma2') {
+ @xzwrite($this->_file, $p_binary_data);
+ } else {
+ if ($this->_compress_type == 'none') {
+ @fputs($this->_file, $p_binary_data);
+ } else {
+ $this->_error(
+ 'Unknown or missing compression type ('
+ . $this->_compress_type . ')'
+ );
+ }
+ }
+ }
+ }
+ } else {
+ if ($this->_compress_type == 'gz') {
+ @gzputs($this->_file, $p_binary_data, $p_len);
+ } else {
+ if ($this->_compress_type == 'bz2') {
+ @bzwrite($this->_file, $p_binary_data, $p_len);
+ } else {
+ if ($this->_compress_type == 'lzma2') {
+ @xzwrite($this->_file, $p_binary_data, $p_len);
+ } else {
+ if ($this->_compress_type == 'none') {
+ @fputs($this->_file, $p_binary_data, $p_len);
+ } else {
+ $this->_error(
+ 'Unknown or missing compression type ('
+ . $this->_compress_type . ')'
+ );
+ }
+ }
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * @return null|string
+ */
+ public function _readBlock()
+ {
+ $v_block = null;
+ if (is_resource($this->_file)) {
+ if ($this->_compress_type == 'gz') {
+ $v_block = @gzread($this->_file, 512);
+ } else {
+ if ($this->_compress_type == 'bz2') {
+ $v_block = @bzread($this->_file, 512);
+ } else {
+ if ($this->_compress_type == 'lzma2') {
+ $v_block = @xzread($this->_file, 512);
+ } else {
+ if ($this->_compress_type == 'none') {
+ $v_block = @fread($this->_file, 512);
+ } else {
+ $this->_error(
+ 'Unknown or missing compression type ('
+ . $this->_compress_type . ')'
+ );
+ }
+ }
+ }
+ }
+ }
+ return $v_block;
+ }
+
+ /**
+ * @param null $p_len
+ * @return bool
+ */
+ public function _jumpBlock($p_len = null)
+ {
+ if (is_resource($this->_file)) {
+ if ($p_len === null) {
+ $p_len = 1;
+ }
+
+ if ($this->_compress_type == 'gz') {
+ @gzseek($this->_file, gztell($this->_file) + ($p_len * 512));
+ } else {
+ if ($this->_compress_type == 'bz2') {
+ // ----- Replace missing bztell() and bzseek()
+ for ($i = 0; $i < $p_len; $i++) {
+ $this->_readBlock();
+ }
+ } else {
+ if ($this->_compress_type == 'lzma2') {
+ // ----- Replace missing xztell() and xzseek()
+ for ($i = 0; $i < $p_len; $i++) {
+ $this->_readBlock();
+ }
+ } else {
+ if ($this->_compress_type == 'none') {
+ @fseek($this->_file, $p_len * 512, SEEK_CUR);
+ } else {
+ $this->_error(
+ 'Unknown or missing compression type ('
+ . $this->_compress_type . ')'
+ );
+ }
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * @return bool
+ */
+ public function _writeFooter()
+ {
+ if (is_resource($this->_file)) {
+ // ----- Write the last 0 filled block for end of archive
+ $v_binary_data = pack('a1024', '');
+ $this->_writeBlock($v_binary_data);
+ }
+ return true;
+ }
+
+ /**
+ * @param array $p_list
+ * @param string $p_add_dir
+ * @param string $p_remove_dir
+ * @return bool
+ */
+ public function _addList($p_list, $p_add_dir, $p_remove_dir)
+ {
+ $v_result = true;
+ $v_header = array();
+
+ // ----- Remove potential windows directory separator
+ $p_add_dir = $this->_translateWinPath($p_add_dir);
+ $p_remove_dir = $this->_translateWinPath($p_remove_dir, false);
+
+ if (!$this->_file) {
+ $this->_error('Invalid file descriptor');
+ return false;
+ }
+
+ if (sizeof($p_list) == 0) {
+ return true;
+ }
+
+ foreach ($p_list as $v_filename) {
+ if (!$v_result) {
+ break;
+ }
+
+ // ----- Skip the current tar name
+ if ($v_filename == $this->_tarname) {
+ continue;
+ }
+
+ if ($v_filename == '') {
+ continue;
+ }
+
+ // ----- ignore files and directories matching the ignore regular expression
+ if ($this->_ignore_regexp && preg_match($this->_ignore_regexp, '/' . $v_filename)) {
+ $this->_warning("File '$v_filename' ignored");
+ continue;
+ }
+
+ if (!file_exists($v_filename) && !is_link($v_filename)) {
+ $this->_warning("File '$v_filename' does not exist");
+ continue;
+ }
+
+ // ----- Add the file or directory header
+ if (!$this->_addFile($v_filename, $v_header, $p_add_dir, $p_remove_dir)) {
+ return false;
+ }
+
+ if (@is_dir($v_filename) && !@is_link($v_filename)) {
+ if (!($p_hdir = opendir($v_filename))) {
+ $this->_warning("Directory '$v_filename' can not be read");
+ continue;
+ }
+ while (false !== ($p_hitem = readdir($p_hdir))) {
+ if (($p_hitem != '.') && ($p_hitem != '..')) {
+ if ($v_filename != ".") {
+ $p_temp_list[0] = $v_filename . '/' . $p_hitem;
+ } else {
+ $p_temp_list[0] = $p_hitem;
+ }
+
+ $v_result = $this->_addList(
+ $p_temp_list,
+ $p_add_dir,
+ $p_remove_dir
+ );
+ }
+ }
+
+ unset($p_temp_list);
+ unset($p_hdir);
+ unset($p_hitem);
+ }
+ }
+
+ return $v_result;
+ }
+
+ /**
+ * @param string $p_filename
+ * @param mixed $p_header
+ * @param string $p_add_dir
+ * @param string $p_remove_dir
+ * @param null $v_stored_filename
+ * @return bool
+ */
+ public function _addFile($p_filename, &$p_header, $p_add_dir, $p_remove_dir, $v_stored_filename = null)
+ {
+ if (!$this->_file) {
+ $this->_error('Invalid file descriptor');
+ return false;
+ }
+
+ if ($p_filename == '') {
+ $this->_error('Invalid file name');
+ return false;
+ }
+
+ if (is_null($v_stored_filename)) {
+ // ----- Calculate the stored filename
+ $p_filename = $this->_translateWinPath($p_filename, false);
+ $v_stored_filename = $p_filename;
+
+ if (strcmp($p_filename, $p_remove_dir) == 0) {
+ return true;
+ }
+
+ if ($p_remove_dir != '') {
+ if (substr($p_remove_dir, -1) != '/') {
+ $p_remove_dir .= '/';
+ }
+
+ if (substr($p_filename, 0, strlen($p_remove_dir)) == $p_remove_dir) {
+ $v_stored_filename = substr($p_filename, strlen($p_remove_dir));
+ }
+ }
+
+ $v_stored_filename = $this->_translateWinPath($v_stored_filename);
+ if ($p_add_dir != '') {
+ if (substr($p_add_dir, -1) == '/') {
+ $v_stored_filename = $p_add_dir . $v_stored_filename;
+ } else {
+ $v_stored_filename = $p_add_dir . '/' . $v_stored_filename;
+ }
+ }
+
+ $v_stored_filename = $this->_pathReduction($v_stored_filename);
+ }
+
+ if ($this->_isArchive($p_filename)) {
+ if (($v_file = @fopen($p_filename, "rb")) == 0) {
+ $this->_warning(
+ "Unable to open file '" . $p_filename
+ . "' in binary read mode"
+ );
+ return true;
+ }
+
+ if (!$this->_writeHeader($p_filename, $v_stored_filename)) {
+ return false;
+ }
+
+ while (($v_buffer = fread($v_file, 512)) != '') {
+ $v_binary_data = pack("a512", "$v_buffer");
+ $this->_writeBlock($v_binary_data);
+ }
+
+ fclose($v_file);
+ } else {
+ // ----- Only header for dir
+ if (!$this->_writeHeader($p_filename, $v_stored_filename)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @param string $p_filename
+ * @param string $p_string
+ * @param bool $p_datetime
+ * @param array $p_params
+ * @return bool
+ */
+ public function _addString($p_filename, $p_string, $p_datetime = false, $p_params = array())
+ {
+ $p_stamp = @$p_params["stamp"] ? $p_params["stamp"] : ($p_datetime ? $p_datetime : time());
+ $p_mode = @$p_params["mode"] ? $p_params["mode"] : 0600;
+ $p_type = @$p_params["type"] ? $p_params["type"] : "";
+ $p_uid = @$p_params["uid"] ? $p_params["uid"] : 0;
+ $p_gid = @$p_params["gid"] ? $p_params["gid"] : 0;
+ if (!$this->_file) {
+ $this->_error('Invalid file descriptor');
+ return false;
+ }
+
+ if ($p_filename == '') {
+ $this->_error('Invalid file name');
+ return false;
+ }
+
+ // ----- Calculate the stored filename
+ $p_filename = $this->_translateWinPath($p_filename, false);
+
+ // ----- If datetime is not specified, set current time
+ if ($p_datetime === false) {
+ $p_datetime = time();
+ }
+
+ if (!$this->_writeHeaderBlock(
+ $p_filename,
+ strlen($p_string),
+ $p_stamp,
+ $p_mode,
+ $p_type,
+ $p_uid,
+ $p_gid
+ )
+ ) {
+ return false;
+ }
+
+ $i = 0;
+ while (($v_buffer = substr($p_string, (($i++) * 512), 512)) != '') {
+ $v_binary_data = pack("a512", $v_buffer);
+ $this->_writeBlock($v_binary_data);
+ }
+
+ return true;
+ }
+
+ /**
+ * @param string $p_filename
+ * @param string $p_stored_filename
+ * @return bool
+ */
+ public function _writeHeader($p_filename, $p_stored_filename)
+ {
+ if ($p_stored_filename == '') {
+ $p_stored_filename = $p_filename;
+ }
+ $v_reduce_filename = $this->_pathReduction($p_stored_filename);
+
+ if (strlen($v_reduce_filename) > 99) {
+ if (!$this->_writeLongHeader($v_reduce_filename)) {
+ return false;
+ }
+ }
+
+ $v_info = lstat($p_filename);
+ $v_uid = sprintf("%07s", DecOct($v_info[4]));
+ $v_gid = sprintf("%07s", DecOct($v_info[5]));
+ $v_perms = sprintf("%07s", DecOct($v_info['mode'] & 000777));
+
+ $v_mtime = sprintf("%011s", DecOct($v_info['mtime']));
+
+ $v_linkname = '';
+
+ if (@is_link($p_filename)) {
+ $v_typeflag = '2';
+ $v_linkname = readlink($p_filename);
+ $v_size = sprintf("%011s", DecOct(0));
+ } elseif (@is_dir($p_filename)) {
+ $v_typeflag = "5";
+ $v_size = sprintf("%011s", DecOct(0));
+ } else {
+ $v_typeflag = '0';
+ clearstatcache();
+ $v_size = sprintf("%011s", DecOct($v_info['size']));
+ }
+
+ $v_magic = 'ustar ';
+
+ $v_version = ' ';
+
+ if (function_exists('posix_getpwuid')) {
+ $userinfo = posix_getpwuid($v_info[4]);
+ $groupinfo = posix_getgrgid($v_info[5]);
+
+ $v_uname = $userinfo['name'];
+ $v_gname = $groupinfo['name'];
+ } else {
+ $v_uname = '';
+ $v_gname = '';
+ }
+
+ $v_devmajor = '';
+
+ $v_devminor = '';
+
+ $v_prefix = '';
+
+ $v_binary_data_first = pack(
+ "a100a8a8a8a12a12",
+ $v_reduce_filename,
+ $v_perms,
+ $v_uid,
+ $v_gid,
+ $v_size,
+ $v_mtime
+ );
+ $v_binary_data_last = pack(
+ "a1a100a6a2a32a32a8a8a155a12",
+ $v_typeflag,
+ $v_linkname,
+ $v_magic,
+ $v_version,
+ $v_uname,
+ $v_gname,
+ $v_devmajor,
+ $v_devminor,
+ $v_prefix,
+ ''
+ );
+
+ // ----- Calculate the checksum
+ $v_checksum = 0;
+ // ..... First part of the header
+ for ($i = 0; $i < 148; $i++) {
+ $v_checksum += ord(substr($v_binary_data_first, $i, 1));
+ }
+ // ..... Ignore the checksum value and replace it by ' ' (space)
+ for ($i = 148; $i < 156; $i++) {
+ $v_checksum += ord(' ');
+ }
+ // ..... Last part of the header
+ for ($i = 156, $j = 0; $i < 512; $i++, $j++) {
+ $v_checksum += ord(substr($v_binary_data_last, $j, 1));
+ }
+
+ // ----- Write the first 148 bytes of the header in the archive
+ $this->_writeBlock($v_binary_data_first, 148);
+
+ // ----- Write the calculated checksum
+ $v_checksum = sprintf("%06s ", DecOct($v_checksum));
+ $v_binary_data = pack("a8", $v_checksum);
+ $this->_writeBlock($v_binary_data, 8);
+
+ // ----- Write the last 356 bytes of the header in the archive
+ $this->_writeBlock($v_binary_data_last, 356);
+
+ return true;
+ }
+
+ /**
+ * @param string $p_filename
+ * @param int $p_size
+ * @param int $p_mtime
+ * @param int $p_perms
+ * @param string $p_type
+ * @param int $p_uid
+ * @param int $p_gid
+ * @return bool
+ */
+ public function _writeHeaderBlock(
+ $p_filename,
+ $p_size,
+ $p_mtime = 0,
+ $p_perms = 0,
+ $p_type = '',
+ $p_uid = 0,
+ $p_gid = 0
+ ) {
+ $p_filename = $this->_pathReduction($p_filename);
+
+ if (strlen($p_filename) > 99) {
+ if (!$this->_writeLongHeader($p_filename)) {
+ return false;
+ }
+ }
+
+ if ($p_type == "5") {
+ $v_size = sprintf("%011s", DecOct(0));
+ } else {
+ $v_size = sprintf("%011s", DecOct($p_size));
+ }
+
+ $v_uid = sprintf("%07s", DecOct($p_uid));
+ $v_gid = sprintf("%07s", DecOct($p_gid));
+ $v_perms = sprintf("%07s", DecOct($p_perms & 000777));
+
+ $v_mtime = sprintf("%11s", DecOct($p_mtime));
+
+ $v_linkname = '';
+
+ $v_magic = 'ustar ';
+
+ $v_version = ' ';
+
+ if (function_exists('posix_getpwuid')) {
+ $userinfo = posix_getpwuid($p_uid);
+ $groupinfo = posix_getgrgid($p_gid);
+
+ $v_uname = $userinfo['name'];
+ $v_gname = $groupinfo['name'];
+ } else {
+ $v_uname = '';
+ $v_gname = '';
+ }
+
+ $v_devmajor = '';
+
+ $v_devminor = '';
+
+ $v_prefix = '';
+
+ $v_binary_data_first = pack(
+ "a100a8a8a8a12A12",
+ $p_filename,
+ $v_perms,
+ $v_uid,
+ $v_gid,
+ $v_size,
+ $v_mtime
+ );
+ $v_binary_data_last = pack(
+ "a1a100a6a2a32a32a8a8a155a12",
+ $p_type,
+ $v_linkname,
+ $v_magic,
+ $v_version,
+ $v_uname,
+ $v_gname,
+ $v_devmajor,
+ $v_devminor,
+ $v_prefix,
+ ''
+ );
+
+ // ----- Calculate the checksum
+ $v_checksum = 0;
+ // ..... First part of the header
+ for ($i = 0; $i < 148; $i++) {
+ $v_checksum += ord(substr($v_binary_data_first, $i, 1));
+ }
+ // ..... Ignore the checksum value and replace it by ' ' (space)
+ for ($i = 148; $i < 156; $i++) {
+ $v_checksum += ord(' ');
+ }
+ // ..... Last part of the header
+ for ($i = 156, $j = 0; $i < 512; $i++, $j++) {
+ $v_checksum += ord(substr($v_binary_data_last, $j, 1));
+ }
+
+ // ----- Write the first 148 bytes of the header in the archive
+ $this->_writeBlock($v_binary_data_first, 148);
+
+ // ----- Write the calculated checksum
+ $v_checksum = sprintf("%06s ", DecOct($v_checksum));
+ $v_binary_data = pack("a8", $v_checksum);
+ $this->_writeBlock($v_binary_data, 8);
+
+ // ----- Write the last 356 bytes of the header in the archive
+ $this->_writeBlock($v_binary_data_last, 356);
+
+ return true;
+ }
+
+ /**
+ * @param string $p_filename
+ * @return bool
+ */
+ public function _writeLongHeader($p_filename)
+ {
+ $v_size = sprintf("%11s ", DecOct(strlen($p_filename)));
+
+ $v_typeflag = 'L';
+
+ $v_linkname = '';
+
+ $v_magic = '';
+
+ $v_version = '';
+
+ $v_uname = '';
+
+ $v_gname = '';
+
+ $v_devmajor = '';
+
+ $v_devminor = '';
+
+ $v_prefix = '';
+
+ $v_binary_data_first = pack(
+ "a100a8a8a8a12a12",
+ '././@LongLink',
+ 0,
+ 0,
+ 0,
+ $v_size,
+ 0
+ );
+ $v_binary_data_last = pack(
+ "a1a100a6a2a32a32a8a8a155a12",
+ $v_typeflag,
+ $v_linkname,
+ $v_magic,
+ $v_version,
+ $v_uname,
+ $v_gname,
+ $v_devmajor,
+ $v_devminor,
+ $v_prefix,
+ ''
+ );
+
+ // ----- Calculate the checksum
+ $v_checksum = 0;
+ // ..... First part of the header
+ for ($i = 0; $i < 148; $i++) {
+ $v_checksum += ord(substr($v_binary_data_first, $i, 1));
+ }
+ // ..... Ignore the checksum value and replace it by ' ' (space)
+ for ($i = 148; $i < 156; $i++) {
+ $v_checksum += ord(' ');
+ }
+ // ..... Last part of the header
+ for ($i = 156, $j = 0; $i < 512; $i++, $j++) {
+ $v_checksum += ord(substr($v_binary_data_last, $j, 1));
+ }
+
+ // ----- Write the first 148 bytes of the header in the archive
+ $this->_writeBlock($v_binary_data_first, 148);
+
+ // ----- Write the calculated checksum
+ $v_checksum = sprintf("%06s ", DecOct($v_checksum));
+ $v_binary_data = pack("a8", $v_checksum);
+ $this->_writeBlock($v_binary_data, 8);
+
+ // ----- Write the last 356 bytes of the header in the archive
+ $this->_writeBlock($v_binary_data_last, 356);
+
+ // ----- Write the filename as content of the block
+ $i = 0;
+ while (($v_buffer = substr($p_filename, (($i++) * 512), 512)) != '') {
+ $v_binary_data = pack("a512", "$v_buffer");
+ $this->_writeBlock($v_binary_data);
+ }
+
+ return true;
+ }
+
+ /**
+ * @param mixed $v_binary_data
+ * @param mixed $v_header
+ * @return bool
+ */
+ public function _readHeader($v_binary_data, &$v_header)
+ {
+ if (strlen($v_binary_data) == 0) {
+ $v_header['filename'] = '';
+ return true;
+ }
+
+ if (strlen($v_binary_data) != 512) {
+ $v_header['filename'] = '';
+ $this->_error('Invalid block size : ' . strlen($v_binary_data));
+ return false;
+ }
+
+ if (!is_array($v_header)) {
+ $v_header = array();
+ }
+ // ----- Calculate the checksum
+ $v_checksum = 0;
+ // ..... First part of the header
+ $v_binary_split = str_split($v_binary_data);
+ $v_checksum += array_sum(array_map('ord', array_slice($v_binary_split, 0, 148)));
+ $v_checksum += array_sum(array_map('ord', array(' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',)));
+ $v_checksum += array_sum(array_map('ord', array_slice($v_binary_split, 156, 512)));
+
+
+ $v_data = unpack($this->_fmt, $v_binary_data);
+
+ if (strlen($v_data["prefix"]) > 0) {
+ $v_data["filename"] = "$v_data[prefix]/$v_data[filename]";
+ }
+
+ // ----- Extract the checksum
+ $v_header['checksum'] = OctDec(trim($v_data['checksum']));
+ if ($v_header['checksum'] != $v_checksum) {
+ $v_header['filename'] = '';
+
+ // ----- Look for last block (empty block)
+ if (($v_checksum == 256) && ($v_header['checksum'] == 0)) {
+ return true;
+ }
+
+ $this->_error(
+ 'Invalid checksum for file "' . $v_data['filename']
+ . '" : ' . $v_checksum . ' calculated, '
+ . $v_header['checksum'] . ' expected'
+ );
+ return false;
+ }
+
+ // ----- Extract the properties
+ $v_header['filename'] = rtrim($v_data['filename'], "\0");
+ if ($this->_maliciousFilename($v_header['filename'])) {
+ $this->_error(
+ 'Malicious .tar detected, file "' . $v_header['filename'] .
+ '" will not install in desired directory tree'
+ );
+ return false;
+ }
+ $v_header['mode'] = OctDec(trim($v_data['mode']));
+ $v_header['uid'] = OctDec(trim($v_data['uid']));
+ $v_header['gid'] = OctDec(trim($v_data['gid']));
+ $v_header['size'] = $this->_tarRecToSize($v_data['size']);
+ $v_header['mtime'] = OctDec(trim($v_data['mtime']));
+ if (($v_header['typeflag'] = $v_data['typeflag']) == "5") {
+ $v_header['size'] = 0;
+ }
+ $v_header['link'] = trim($v_data['link']);
+ /* ----- All these fields are removed form the header because
+ they do not carry interesting info
+ $v_header[magic] = trim($v_data[magic]);
+ $v_header[version] = trim($v_data[version]);
+ $v_header[uname] = trim($v_data[uname]);
+ $v_header[gname] = trim($v_data[gname]);
+ $v_header[devmajor] = trim($v_data[devmajor]);
+ $v_header[devminor] = trim($v_data[devminor]);
+ */
+
+ return true;
+ }
+
+ /**
+ * Convert Tar record size to actual size
+ *
+ * @param string $tar_size
+ * @return size of tar record in bytes
+ */
+ private function _tarRecToSize($tar_size)
+ {
+ /*
+ * First byte of size has a special meaning if bit 7 is set.
+ *
+ * Bit 7 indicates base-256 encoding if set.
+ * Bit 6 is the sign bit.
+ * Bits 5:0 are most significant value bits.
+ */
+ $ch = ord($tar_size[0]);
+ if ($ch & 0x80) {
+ // Full 12-bytes record is required.
+ $rec_str = $tar_size . "\x00";
+
+ $size = ($ch & 0x40) ? -1 : 0;
+ $size = ($size << 6) | ($ch & 0x3f);
+
+ for ($num_ch = 1; $num_ch < 12; ++$num_ch) {
+ $size = ($size * 256) + ord($rec_str[$num_ch]);
+ }
+
+ return $size;
+
+ } else {
+ return OctDec(trim($tar_size));
+ }
+ }
+
+ /**
+ * Detect and report a malicious file name
+ *
+ * @param string $file
+ *
+ * @return bool
+ */
+ private function _maliciousFilename($file)
+ {
+ if (strpos($file, '/../') !== false) {
+ return true;
+ }
+ if (strpos($file, '../') === 0) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @param $v_header
+ * @return bool
+ */
+ public function _readLongHeader(&$v_header)
+ {
+ $v_filename = '';
+ $v_filesize = $v_header['size'];
+ $n = floor($v_header['size'] / 512);
+ for ($i = 0; $i < $n; $i++) {
+ $v_content = $this->_readBlock();
+ $v_filename .= $v_content;
+ }
+ if (($v_header['size'] % 512) != 0) {
+ $v_content = $this->_readBlock();
+ $v_filename .= $v_content;
+ }
+
+ // ----- Read the next header
+ $v_binary_data = $this->_readBlock();
+
+ if (!$this->_readHeader($v_binary_data, $v_header)) {
+ return false;
+ }
+
+ $v_filename = rtrim(substr($v_filename, 0, $v_filesize), "\0");
+ $v_header['filename'] = $v_filename;
+ if ($this->_maliciousFilename($v_filename)) {
+ $this->_error(
+ 'Malicious .tar detected, file "' . $v_filename .
+ '" will not install in desired directory tree'
+ );
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * This method extract from the archive one file identified by $p_filename.
+ * The return value is a string with the file content, or null on error.
+ *
+ * @param string $p_filename The path of the file to extract in a string.
+ *
+ * @return a string with the file content or null.
+ */
+ private function _extractInString($p_filename)
+ {
+ $v_result_str = "";
+
+ while (strlen($v_binary_data = $this->_readBlock()) != 0) {
+ if (!$this->_readHeader($v_binary_data, $v_header)) {
+ return null;
+ }
+
+ if ($v_header['filename'] == '') {
+ continue;
+ }
+
+ // ----- Look for long filename
+ if ($v_header['typeflag'] == 'L') {
+ if (!$this->_readLongHeader($v_header)) {
+ return null;
+ }
+ }
+
+ if ($v_header['filename'] == $p_filename) {
+ if ($v_header['typeflag'] == "5") {
+ $this->_error(
+ 'Unable to extract in string a directory '
+ . 'entry {' . $v_header['filename'] . '}'
+ );
+ return null;
+ } else {
+ $n = floor($v_header['size'] / 512);
+ for ($i = 0; $i < $n; $i++) {
+ $v_result_str .= $this->_readBlock();
+ }
+ if (($v_header['size'] % 512) != 0) {
+ $v_content = $this->_readBlock();
+ $v_result_str .= substr(
+ $v_content,
+ 0,
+ ($v_header['size'] % 512)
+ );
+ }
+ return $v_result_str;
+ }
+ } else {
+ $this->_jumpBlock(ceil(($v_header['size'] / 512)));
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * @param string $p_path
+ * @param string $p_list_detail
+ * @param string $p_mode
+ * @param string $p_file_list
+ * @param string $p_remove_path
+ * @param bool $p_preserve
+ * @return bool
+ */
+ public function _extractList(
+ $p_path,
+ &$p_list_detail,
+ $p_mode,
+ $p_file_list,
+ $p_remove_path,
+ $p_preserve = false
+ ) {
+ $v_result = true;
+ $v_nb = 0;
+ $v_extract_all = true;
+ $v_listing = false;
+
+ $p_path = $this->_translateWinPath($p_path, false);
+ if ($p_path == '' || (substr($p_path, 0, 1) != '/'
+ && substr($p_path, 0, 3) != "../" && !strpos($p_path, ':'))
+ ) {
+ $p_path = "./" . $p_path;
+ }
+ $p_remove_path = $this->_translateWinPath($p_remove_path);
+
+ // ----- Look for path to remove format (should end by /)
+ if (($p_remove_path != '') && (substr($p_remove_path, -1) != '/')) {
+ $p_remove_path .= '/';
+ }
+ $p_remove_path_size = strlen($p_remove_path);
+
+ switch ($p_mode) {
+ case "complete" :
+ $v_extract_all = true;
+ $v_listing = false;
+ break;
+ case "partial" :
+ $v_extract_all = false;
+ $v_listing = false;
+ break;
+ case "list" :
+ $v_extract_all = false;
+ $v_listing = true;
+ break;
+ default :
+ $this->_error('Invalid extract mode (' . $p_mode . ')');
+ return false;
+ }
+
+ clearstatcache();
+
+ while (strlen($v_binary_data = $this->_readBlock()) != 0) {
+ $v_extract_file = false;
+ $v_extraction_stopped = 0;
+
+ if (!$this->_readHeader($v_binary_data, $v_header)) {
+ return false;
+ }
+
+ if ($v_header['filename'] == '') {
+ continue;
+ }
+
+ // ----- Look for long filename
+ if ($v_header['typeflag'] == 'L') {
+ if (!$this->_readLongHeader($v_header)) {
+ return false;
+ }
+ }
+
+ // ignore extended / pax headers
+ if ($v_header['typeflag'] == 'x' || $v_header['typeflag'] == 'g') {
+ $this->_jumpBlock(ceil(($v_header['size'] / 512)));
+ continue;
+ }
+
+ if ((!$v_extract_all) && (is_array($p_file_list))) {
+ // ----- By default no unzip if the file is not found
+ $v_extract_file = false;
+
+ for ($i = 0; $i < sizeof($p_file_list); $i++) {
+ // ----- Look if it is a directory
+ if (substr($p_file_list[$i], -1) == '/') {
+ // ----- Look if the directory is in the filename path
+ if ((strlen($v_header['filename']) > strlen($p_file_list[$i]))
+ && (substr($v_header['filename'], 0, strlen($p_file_list[$i]))
+ == $p_file_list[$i])
+ ) {
+ $v_extract_file = true;
+ break;
+ }
+ } // ----- It is a file, so compare the file names
+ elseif ($p_file_list[$i] == $v_header['filename']) {
+ $v_extract_file = true;
+ break;
+ }
+ }
+ } else {
+ $v_extract_file = true;
+ }
+
+ // ----- Look if this file need to be extracted
+ if (($v_extract_file) && (!$v_listing)) {
+ if (($p_remove_path != '')
+ && (substr($v_header['filename'] . '/', 0, $p_remove_path_size)
+ == $p_remove_path)
+ ) {
+ $v_header['filename'] = substr(
+ $v_header['filename'],
+ $p_remove_path_size
+ );
+ if ($v_header['filename'] == '') {
+ continue;
+ }
+ }
+ if (($p_path != './') && ($p_path != '/')) {
+ while (substr($p_path, -1) == '/') {
+ $p_path = substr($p_path, 0, strlen($p_path) - 1);
+ }
+
+ if (substr($v_header['filename'], 0, 1) == '/') {
+ $v_header['filename'] = $p_path . $v_header['filename'];
+ } else {
+ $v_header['filename'] = $p_path . '/' . $v_header['filename'];
+ }
+ }
+ if (file_exists($v_header['filename'])) {
+ if ((@is_dir($v_header['filename']))
+ && ($v_header['typeflag'] == '')
+ ) {
+ $this->_error(
+ 'File ' . $v_header['filename']
+ . ' already exists as a directory'
+ );
+ return false;
+ }
+ if (($this->_isArchive($v_header['filename']))
+ && ($v_header['typeflag'] == "5")
+ ) {
+ $this->_error(
+ 'Directory ' . $v_header['filename']
+ . ' already exists as a file'
+ );
+ return false;
+ }
+ if (!is_writeable($v_header['filename'])) {
+ $this->_error(
+ 'File ' . $v_header['filename']
+ . ' already exists and is write protected'
+ );
+ return false;
+ }
+ if (filemtime($v_header['filename']) > $v_header['mtime']) {
+ // To be completed : An error or silent no replace ?
+ }
+ } // ----- Check the directory availability and create it if necessary
+ elseif (($v_result
+ = $this->_dirCheck(
+ ($v_header['typeflag'] == "5"
+ ? $v_header['filename']
+ : dirname($v_header['filename']))
+ )) != 1
+ ) {
+ $this->_error('Unable to create path for ' . $v_header['filename']);
+ return false;
+ }
+
+ if ($v_extract_file) {
+ if ($v_header['typeflag'] == "5") {
+ if (!@file_exists($v_header['filename'])) {
+ if (!@mkdir($v_header['filename'], 0777)) {
+ $this->_error(
+ 'Unable to create directory {'
+ . $v_header['filename'] . '}'
+ );
+ return false;
+ }
+ }
+ } elseif ($v_header['typeflag'] == "2") {
+ if (@file_exists($v_header['filename'])) {
+ @unlink($v_header['filename']);
+ }
+ if (!@symlink($v_header['link'], $v_header['filename'])) {
+ $this->_error(
+ 'Unable to extract symbolic link {'
+ . $v_header['filename'] . '}'
+ );
+ return false;
+ }
+ } else {
+ if (($v_dest_file = @fopen($v_header['filename'], "wb")) == 0) {
+ $this->_error(
+ 'Error while opening {' . $v_header['filename']
+ . '} in write binary mode'
+ );
+ return false;
+ } else {
+ $n = floor($v_header['size'] / 512);
+ for ($i = 0; $i < $n; $i++) {
+ $v_content = $this->_readBlock();
+ fwrite($v_dest_file, $v_content, 512);
+ }
+ if (($v_header['size'] % 512) != 0) {
+ $v_content = $this->_readBlock();
+ fwrite($v_dest_file, $v_content, ($v_header['size'] % 512));
+ }
+
+ @fclose($v_dest_file);
+
+ if ($p_preserve) {
+ @chown($v_header['filename'], $v_header['uid']);
+ @chgrp($v_header['filename'], $v_header['gid']);
+ }
+
+ // ----- Change the file mode, mtime
+ @touch($v_header['filename'], $v_header['mtime']);
+ if ($v_header['mode'] & 0111) {
+ // make file executable, obey umask
+ $mode = fileperms($v_header['filename']) | (~umask() & 0111);
+ @chmod($v_header['filename'], $mode);
+ }
+ }
+
+ // ----- Check the file size
+ clearstatcache();
+ if (!is_file($v_header['filename'])) {
+ $this->_error(
+ 'Extracted file ' . $v_header['filename']
+ . 'does not exist. Archive may be corrupted.'
+ );
+ return false;
+ }
+
+ $filesize = filesize($v_header['filename']);
+ if ($filesize != $v_header['size']) {
+ $this->_error(
+ 'Extracted file ' . $v_header['filename']
+ . ' does not have the correct file size \''
+ . $filesize
+ . '\' (' . $v_header['size']
+ . ' expected). Archive may be corrupted.'
+ );
+ return false;
+ }
+ }
+ } else {
+ $this->_jumpBlock(ceil(($v_header['size'] / 512)));
+ }
+ } else {
+ $this->_jumpBlock(ceil(($v_header['size'] / 512)));
+ }
+
+ /* TBC : Seems to be unused ...
+ if ($this->_compress)
+ $v_end_of_file = @gzeof($this->_file);
+ else
+ $v_end_of_file = @feof($this->_file);
+ */
+
+ if ($v_listing || $v_extract_file || $v_extraction_stopped) {
+ // ----- Log extracted files
+ if (($v_file_dir = dirname($v_header['filename']))
+ == $v_header['filename']
+ ) {
+ $v_file_dir = '';
+ }
+ if ((substr($v_header['filename'], 0, 1) == '/') && ($v_file_dir == '')) {
+ $v_file_dir = '/';
+ }
+
+ $p_list_detail[$v_nb++] = $v_header;
+ if (is_array($p_file_list) && (count($p_list_detail) == count($p_file_list))) {
+ return true;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @return bool
+ */
+ public function _openAppend()
+ {
+ if (filesize($this->_tarname) == 0) {
+ return $this->_openWrite();
+ }
+
+ if ($this->_compress) {
+ $this->_close();
+
+ if (!@rename($this->_tarname, $this->_tarname . ".tmp")) {
+ $this->_error(
+ 'Error while renaming \'' . $this->_tarname
+ . '\' to temporary file \'' . $this->_tarname
+ . '.tmp\''
+ );
+ return false;
+ }
+
+ if ($this->_compress_type == 'gz') {
+ $v_temp_tar = @gzopen($this->_tarname . ".tmp", "rb");
+ } elseif ($this->_compress_type == 'bz2') {
+ $v_temp_tar = @bzopen($this->_tarname . ".tmp", "r");
+ } elseif ($this->_compress_type == 'lzma2') {
+ $v_temp_tar = @xzopen($this->_tarname . ".tmp", "r");
+ }
+
+
+ if ($v_temp_tar == 0) {
+ $this->_error(
+ 'Unable to open file \'' . $this->_tarname
+ . '.tmp\' in binary read mode'
+ );
+ @rename($this->_tarname . ".tmp", $this->_tarname);
+ return false;
+ }
+
+ if (!$this->_openWrite()) {
+ @rename($this->_tarname . ".tmp", $this->_tarname);
+ return false;
+ }
+
+ if ($this->_compress_type == 'gz') {
+ $end_blocks = 0;
+
+ while (!@gzeof($v_temp_tar)) {
+ $v_buffer = @gzread($v_temp_tar, 512);
+ if ($v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer) == 0) {
+ $end_blocks++;
+ // do not copy end blocks, we will re-make them
+ // after appending
+ continue;
+ } elseif ($end_blocks > 0) {
+ for ($i = 0; $i < $end_blocks; $i++) {
+ $this->_writeBlock(ARCHIVE_TAR_END_BLOCK);
+ }
+ $end_blocks = 0;
+ }
+ $v_binary_data = pack("a512", $v_buffer);
+ $this->_writeBlock($v_binary_data);
+ }
+
+ @gzclose($v_temp_tar);
+ } elseif ($this->_compress_type == 'bz2') {
+ $end_blocks = 0;
+
+ while (strlen($v_buffer = @bzread($v_temp_tar, 512)) > 0) {
+ if ($v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer) == 0) {
+ $end_blocks++;
+ // do not copy end blocks, we will re-make them
+ // after appending
+ continue;
+ } elseif ($end_blocks > 0) {
+ for ($i = 0; $i < $end_blocks; $i++) {
+ $this->_writeBlock(ARCHIVE_TAR_END_BLOCK);
+ }
+ $end_blocks = 0;
+ }
+ $v_binary_data = pack("a512", $v_buffer);
+ $this->_writeBlock($v_binary_data);
+ }
+
+ @bzclose($v_temp_tar);
+ } elseif ($this->_compress_type == 'lzma2') {
+ $end_blocks = 0;
+
+ while (strlen($v_buffer = @xzread($v_temp_tar, 512)) > 0) {
+ if ($v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer) == 0) {
+ $end_blocks++;
+ // do not copy end blocks, we will re-make them
+ // after appending
+ continue;
+ } elseif ($end_blocks > 0) {
+ for ($i = 0; $i < $end_blocks; $i++) {
+ $this->_writeBlock(ARCHIVE_TAR_END_BLOCK);
+ }
+ $end_blocks = 0;
+ }
+ $v_binary_data = pack("a512", $v_buffer);
+ $this->_writeBlock($v_binary_data);
+ }
+
+ @xzclose($v_temp_tar);
+ }
+
+ if (!@unlink($this->_tarname . ".tmp")) {
+ $this->_error(
+ 'Error while deleting temporary file \''
+ . $this->_tarname . '.tmp\''
+ );
+ }
+ } else {
+ // ----- For not compressed tar, just add files before the last
+ // one or two 512 bytes block
+ if (!$this->_openReadWrite()) {
+ return false;
+ }
+
+ clearstatcache();
+ $v_size = filesize($this->_tarname);
+
+ // We might have zero, one or two end blocks.
+ // The standard is two, but we should try to handle
+ // other cases.
+ fseek($this->_file, $v_size - 1024);
+ if (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) {
+ fseek($this->_file, $v_size - 1024);
+ } elseif (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) {
+ fseek($this->_file, $v_size - 512);
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @param $p_filelist
+ * @param string $p_add_dir
+ * @param string $p_remove_dir
+ * @return bool
+ */
+ public function _append($p_filelist, $p_add_dir = '', $p_remove_dir = '')
+ {
+ if (!$this->_openAppend()) {
+ return false;
+ }
+
+ if ($this->_addList($p_filelist, $p_add_dir, $p_remove_dir)) {
+ $this->_writeFooter();
+ }
+
+ $this->_close();
+
+ return true;
+ }
+
+ /**
+ * Check if a directory exists and create it (including parent
+ * dirs) if not.
+ *
+ * @param string $p_dir directory to check
+ *
+ * @return bool true if the directory exists or was created
+ */
+ public function _dirCheck($p_dir)
+ {
+ clearstatcache();
+ if ((@is_dir($p_dir)) || ($p_dir == '')) {
+ return true;
+ }
+
+ $p_parent_dir = dirname($p_dir);
+
+ if (($p_parent_dir != $p_dir) &&
+ ($p_parent_dir != '') &&
+ (!$this->_dirCheck($p_parent_dir))
+ ) {
+ return false;
+ }
+
+ if (!@mkdir($p_dir, 0777)) {
+ $this->_error("Unable to create directory '$p_dir'");
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Compress path by changing for example "/dir/foo/../bar" to "/dir/bar",
+ * rand emove double slashes.
+ *
+ * @param string $p_dir path to reduce
+ *
+ * @return string reduced path
+ */
+ private function _pathReduction($p_dir)
+ {
+ $v_result = '';
+
+ // ----- Look for not empty path
+ if ($p_dir != '') {
+ // ----- Explode path by directory names
+ $v_list = explode('/', $p_dir);
+
+ // ----- Study directories from last to first
+ for ($i = sizeof($v_list) - 1; $i >= 0; $i--) {
+ // ----- Look for current path
+ if ($v_list[$i] == ".") {
+ // ----- Ignore this directory
+ // Should be the first $i=0, but no check is done
+ } else {
+ if ($v_list[$i] == "..") {
+ // ----- Ignore it and ignore the $i-1
+ $i--;
+ } else {
+ if (($v_list[$i] == '')
+ && ($i != (sizeof($v_list) - 1))
+ && ($i != 0)
+ ) {
+ // ----- Ignore only the double '//' in path,
+ // but not the first and last /
+ } else {
+ $v_result = $v_list[$i] . ($i != (sizeof($v_list) - 1) ? '/'
+ . $v_result : '');
+ }
+ }
+ }
+ }
+ }
+
+ if (defined('OS_WINDOWS') && OS_WINDOWS) {
+ $v_result = strtr($v_result, '\\', '/');
+ }
+
+ return $v_result;
+ }
+
+ /**
+ * @param $p_path
+ * @param bool $p_remove_disk_letter
+ * @return string
+ */
+ public function _translateWinPath($p_path, $p_remove_disk_letter = true)
+ {
+ if (defined('OS_WINDOWS') && OS_WINDOWS) {
+ // ----- Look for potential disk letter
+ if (($p_remove_disk_letter)
+ && (($v_position = strpos($p_path, ':')) != false)
+ ) {
+ $p_path = substr($p_path, $v_position + 1);
+ }
+ // ----- Change potential windows directory separator
+ if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0, 1) == '\\')) {
+ $p_path = strtr($p_path, '\\', '/');
+ }
+ }
+ return $p_path;
+ }
+}
diff --git a/vendor/pear-pear.php.net/Console_Getopt/Console/Getopt.php b/vendor/pear-pear.php.net/Console_Getopt/Console/Getopt.php
new file mode 100644
index 000000000..0da88585d
--- /dev/null
+++ b/vendor/pear-pear.php.net/Console_Getopt/Console/Getopt.php
@@ -0,0 +1,360 @@
+
+ * @license http://www.php.net/license/3_0.txt PHP 3.0
+ * @version CVS: $Id$
+ * @link http://pear.php.net/package/Console_Getopt
+ */
+
+require_once 'PEAR.php';
+
+/**
+ * Command-line options parsing class.
+ *
+ * @category Console
+ * @package Console_Getopt
+ * @author Andrei Zmievski
+ * @license http://www.php.net/license/3_0.txt PHP 3.0
+ * @link http://pear.php.net/package/Console_Getopt
+ */
+class Console_Getopt
+{
+
+ /**
+ * Parses the command-line options.
+ *
+ * The first parameter to this function should be the list of command-line
+ * arguments without the leading reference to the running program.
+ *
+ * The second parameter is a string of allowed short options. Each of the
+ * option letters can be followed by a colon ':' to specify that the option
+ * requires an argument, or a double colon '::' to specify that the option
+ * takes an optional argument.
+ *
+ * The third argument is an optional array of allowed long options. The
+ * leading '--' should not be included in the option name. Options that
+ * require an argument should be followed by '=', and options that take an
+ * option argument should be followed by '=='.
+ *
+ * The return value is an array of two elements: the list of parsed
+ * options and the list of non-option command-line arguments. Each entry in
+ * the list of parsed options is a pair of elements - the first one
+ * specifies the option, and the second one specifies the option argument,
+ * if there was one.
+ *
+ * Long and short options can be mixed.
+ *
+ * Most of the semantics of this function are based on GNU getopt_long().
+ *
+ * @param array $args an array of command-line arguments
+ * @param string $short_options specifies the list of allowed short options
+ * @param array $long_options specifies the list of allowed long options
+ * @param boolean $skip_unknown suppresses Console_Getopt: unrecognized option
+ *
+ * @return array two-element array containing the list of parsed options and
+ * the non-option arguments
+ */
+ public static function getopt2($args, $short_options, $long_options = null, $skip_unknown = false)
+ {
+ return Console_Getopt::doGetopt(2, $args, $short_options, $long_options, $skip_unknown);
+ }
+
+ /**
+ * This function expects $args to start with the script name (POSIX-style).
+ * Preserved for backwards compatibility.
+ *
+ * @param array $args an array of command-line arguments
+ * @param string $short_options specifies the list of allowed short options
+ * @param array $long_options specifies the list of allowed long options
+ *
+ * @see getopt2()
+ * @return array two-element array containing the list of parsed options and
+ * the non-option arguments
+ */
+ public static function getopt($args, $short_options, $long_options = null, $skip_unknown = false)
+ {
+ return Console_Getopt::doGetopt(1, $args, $short_options, $long_options, $skip_unknown);
+ }
+
+ /**
+ * The actual implementation of the argument parsing code.
+ *
+ * @param int $version Version to use
+ * @param array $args an array of command-line arguments
+ * @param string $short_options specifies the list of allowed short options
+ * @param array $long_options specifies the list of allowed long options
+ * @param boolean $skip_unknown suppresses Console_Getopt: unrecognized option
+ *
+ * @return array
+ */
+ public static function doGetopt($version, $args, $short_options, $long_options = null, $skip_unknown = false)
+ {
+ // in case you pass directly readPHPArgv() as the first arg
+ if (PEAR::isError($args)) {
+ return $args;
+ }
+
+ if (empty($args)) {
+ return array(array(), array());
+ }
+
+ $non_opts = $opts = array();
+
+ settype($args, 'array');
+
+ if ($long_options) {
+ sort($long_options);
+ }
+
+ /*
+ * Preserve backwards compatibility with callers that relied on
+ * erroneous POSIX fix.
+ */
+ if ($version < 2) {
+ if (isset($args[0]{0}) && $args[0]{0} != '-') {
+ array_shift($args);
+ }
+ }
+
+ reset($args);
+ while (list($i, $arg) = each($args)) {
+ /* The special element '--' means explicit end of
+ options. Treat the rest of the arguments as non-options
+ and end the loop. */
+ if ($arg == '--') {
+ $non_opts = array_merge($non_opts, array_slice($args, $i + 1));
+ break;
+ }
+
+ if ($arg{0} != '-' || (strlen($arg) > 1 && $arg{1} == '-' && !$long_options)) {
+ $non_opts = array_merge($non_opts, array_slice($args, $i));
+ break;
+ } elseif (strlen($arg) > 1 && $arg{1} == '-') {
+ $error = Console_Getopt::_parseLongOption(substr($arg, 2),
+ $long_options,
+ $opts,
+ $args,
+ $skip_unknown);
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+ } elseif ($arg == '-') {
+ // - is stdin
+ $non_opts = array_merge($non_opts, array_slice($args, $i));
+ break;
+ } else {
+ $error = Console_Getopt::_parseShortOption(substr($arg, 1),
+ $short_options,
+ $opts,
+ $args,
+ $skip_unknown);
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+ }
+ }
+
+ return array($opts, $non_opts);
+ }
+
+ /**
+ * Parse short option
+ *
+ * @param string $arg Argument
+ * @param string[] $short_options Available short options
+ * @param string[][] &$opts
+ * @param string[] &$args
+ * @param boolean $skip_unknown suppresses Console_Getopt: unrecognized option
+ *
+ * @return void
+ */
+ protected static function _parseShortOption($arg, $short_options, &$opts, &$args, $skip_unknown)
+ {
+ for ($i = 0; $i < strlen($arg); $i++) {
+ $opt = $arg{$i};
+ $opt_arg = null;
+
+ /* Try to find the short option in the specifier string. */
+ if (($spec = strstr($short_options, $opt)) === false || $arg{$i} == ':') {
+ if ($skip_unknown === true) {
+ break;
+ }
+
+ $msg = "Console_Getopt: unrecognized option -- $opt";
+ return PEAR::raiseError($msg);
+ }
+
+ if (strlen($spec) > 1 && $spec{1} == ':') {
+ if (strlen($spec) > 2 && $spec{2} == ':') {
+ if ($i + 1 < strlen($arg)) {
+ /* Option takes an optional argument. Use the remainder of
+ the arg string if there is anything left. */
+ $opts[] = array($opt, substr($arg, $i + 1));
+ break;
+ }
+ } else {
+ /* Option requires an argument. Use the remainder of the arg
+ string if there is anything left. */
+ if ($i + 1 < strlen($arg)) {
+ $opts[] = array($opt, substr($arg, $i + 1));
+ break;
+ } else if (list(, $opt_arg) = each($args)) {
+ /* Else use the next argument. */;
+ if (Console_Getopt::_isShortOpt($opt_arg)
+ || Console_Getopt::_isLongOpt($opt_arg)) {
+ $msg = "option requires an argument --$opt";
+ return PEAR::raiseError("Console_Getopt: " . $msg);
+ }
+ } else {
+ $msg = "option requires an argument --$opt";
+ return PEAR::raiseError("Console_Getopt: " . $msg);
+ }
+ }
+ }
+
+ $opts[] = array($opt, $opt_arg);
+ }
+ }
+
+ /**
+ * Checks if an argument is a short option
+ *
+ * @param string $arg Argument to check
+ *
+ * @return bool
+ */
+ protected static function _isShortOpt($arg)
+ {
+ return strlen($arg) == 2 && $arg[0] == '-'
+ && preg_match('/[a-zA-Z]/', $arg[1]);
+ }
+
+ /**
+ * Checks if an argument is a long option
+ *
+ * @param string $arg Argument to check
+ *
+ * @return bool
+ */
+ protected static function _isLongOpt($arg)
+ {
+ return strlen($arg) > 2 && $arg[0] == '-' && $arg[1] == '-' &&
+ preg_match('/[a-zA-Z]+$/', substr($arg, 2));
+ }
+
+ /**
+ * Parse long option
+ *
+ * @param string $arg Argument
+ * @param string[] $long_options Available long options
+ * @param string[][] &$opts
+ * @param string[] &$args
+ *
+ * @return void|PEAR_Error
+ */
+ protected static function _parseLongOption($arg, $long_options, &$opts, &$args, $skip_unknown)
+ {
+ @list($opt, $opt_arg) = explode('=', $arg, 2);
+
+ $opt_len = strlen($opt);
+
+ for ($i = 0; $i < count($long_options); $i++) {
+ $long_opt = $long_options[$i];
+ $opt_start = substr($long_opt, 0, $opt_len);
+
+ $long_opt_name = str_replace('=', '', $long_opt);
+
+ /* Option doesn't match. Go on to the next one. */
+ if ($long_opt_name != $opt) {
+ continue;
+ }
+
+ $opt_rest = substr($long_opt, $opt_len);
+
+ /* Check that the options uniquely matches one of the allowed
+ options. */
+ if ($i + 1 < count($long_options)) {
+ $next_option_rest = substr($long_options[$i + 1], $opt_len);
+ } else {
+ $next_option_rest = '';
+ }
+
+ if ($opt_rest != '' && $opt{0} != '=' &&
+ $i + 1 < count($long_options) &&
+ $opt == substr($long_options[$i+1], 0, $opt_len) &&
+ $next_option_rest != '' &&
+ $next_option_rest{0} != '=') {
+
+ $msg = "Console_Getopt: option --$opt is ambiguous";
+ return PEAR::raiseError($msg);
+ }
+
+ if (substr($long_opt, -1) == '=') {
+ if (substr($long_opt, -2) != '==') {
+ /* Long option requires an argument.
+ Take the next argument if one wasn't specified. */;
+ if (!strlen($opt_arg) && !(list(, $opt_arg) = each($args))) {
+ $msg = "Console_Getopt: option requires an argument --$opt";
+ return PEAR::raiseError($msg);
+ }
+
+ if (Console_Getopt::_isShortOpt($opt_arg)
+ || Console_Getopt::_isLongOpt($opt_arg)) {
+ $msg = "Console_Getopt: option requires an argument --$opt";
+ return PEAR::raiseError($msg);
+ }
+ }
+ } else if ($opt_arg) {
+ $msg = "Console_Getopt: option --$opt doesn't allow an argument";
+ return PEAR::raiseError($msg);
+ }
+
+ $opts[] = array('--' . $opt, $opt_arg);
+ return;
+ }
+
+ if ($skip_unknown === true) {
+ return;
+ }
+
+ return PEAR::raiseError("Console_Getopt: unrecognized option --$opt");
+ }
+
+ /**
+ * Safely read the $argv PHP array across different PHP configurations.
+ * Will take care on register_globals and register_argc_argv ini directives
+ *
+ * @return mixed the $argv PHP array or PEAR error if not registered
+ */
+ public static function readPHPArgv()
+ {
+ global $argv;
+ if (!is_array($argv)) {
+ if (!@is_array($_SERVER['argv'])) {
+ if (!@is_array($GLOBALS['HTTP_SERVER_VARS']['argv'])) {
+ $msg = "Could not read cmd args (register_argc_argv=Off?)";
+ return PEAR::raiseError("Console_Getopt: " . $msg);
+ }
+ return $GLOBALS['HTTP_SERVER_VARS']['argv'];
+ }
+ return $_SERVER['argv'];
+ }
+ return $argv;
+ }
+
+}
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/OS/Guess.php b/vendor/pear-pear.php.net/PEAR/OS/Guess.php
new file mode 100644
index 000000000..7e8e8d3f8
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/OS/Guess.php
@@ -0,0 +1,337 @@
+
+ * @author Gregory Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since PEAR 0.1
+ */
+
+// {{{ uname examples
+
+// php_uname() without args returns the same as 'uname -a', or a PHP-custom
+// string for Windows.
+// PHP versions prior to 4.3 return the uname of the host where PHP was built,
+// as of 4.3 it returns the uname of the host running the PHP code.
+//
+// PC RedHat Linux 7.1:
+// Linux host.example.com 2.4.2-2 #1 Sun Apr 8 20:41:30 EDT 2001 i686 unknown
+//
+// PC Debian Potato:
+// Linux host 2.4.17 #2 SMP Tue Feb 12 15:10:04 CET 2002 i686 unknown
+//
+// PC FreeBSD 3.3:
+// FreeBSD host.example.com 3.3-STABLE FreeBSD 3.3-STABLE #0: Mon Feb 21 00:42:31 CET 2000 root@example.com:/usr/src/sys/compile/CONFIG i386
+//
+// PC FreeBSD 4.3:
+// FreeBSD host.example.com 4.3-RELEASE FreeBSD 4.3-RELEASE #1: Mon Jun 25 11:19:43 EDT 2001 root@example.com:/usr/src/sys/compile/CONFIG i386
+//
+// PC FreeBSD 4.5:
+// FreeBSD host.example.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Wed Feb 6 23:59:23 CET 2002 root@example.com:/usr/src/sys/compile/CONFIG i386
+//
+// PC FreeBSD 4.5 w/uname from GNU shellutils:
+// FreeBSD host.example.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Wed Feb i386 unknown
+//
+// HP 9000/712 HP-UX 10:
+// HP-UX iq B.10.10 A 9000/712 2008429113 two-user license
+//
+// HP 9000/712 HP-UX 10 w/uname from GNU shellutils:
+// HP-UX host B.10.10 A 9000/712 unknown
+//
+// IBM RS6000/550 AIX 4.3:
+// AIX host 3 4 000003531C00
+//
+// AIX 4.3 w/uname from GNU shellutils:
+// AIX host 3 4 000003531C00 unknown
+//
+// SGI Onyx IRIX 6.5 w/uname from GNU shellutils:
+// IRIX64 host 6.5 01091820 IP19 mips
+//
+// SGI Onyx IRIX 6.5:
+// IRIX64 host 6.5 01091820 IP19
+//
+// SparcStation 20 Solaris 8 w/uname from GNU shellutils:
+// SunOS host.example.com 5.8 Generic_108528-12 sun4m sparc
+//
+// SparcStation 20 Solaris 8:
+// SunOS host.example.com 5.8 Generic_108528-12 sun4m sparc SUNW,SPARCstation-20
+//
+// Mac OS X (Darwin)
+// Darwin home-eden.local 7.5.0 Darwin Kernel Version 7.5.0: Thu Aug 5 19:26:16 PDT 2004; root:xnu/xnu-517.7.21.obj~3/RELEASE_PPC Power Macintosh
+//
+// Mac OS X early versions
+//
+
+// }}}
+
+/* TODO:
+ * - define endianness, to allow matchSignature("bigend") etc.
+ */
+
+/**
+ * Retrieves information about the current operating system
+ *
+ * This class uses php_uname() to grok information about the current OS
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Gregory Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 0.1
+ */
+class OS_Guess
+{
+ var $sysname;
+ var $nodename;
+ var $cpu;
+ var $release;
+ var $extra;
+
+ function __construct($uname = null)
+ {
+ list($this->sysname,
+ $this->release,
+ $this->cpu,
+ $this->extra,
+ $this->nodename) = $this->parseSignature($uname);
+ }
+
+ function parseSignature($uname = null)
+ {
+ static $sysmap = array(
+ 'HP-UX' => 'hpux',
+ 'IRIX64' => 'irix',
+ );
+ static $cpumap = array(
+ 'i586' => 'i386',
+ 'i686' => 'i386',
+ 'ppc' => 'powerpc',
+ );
+ if ($uname === null) {
+ $uname = php_uname();
+ }
+ $parts = preg_split('/\s+/', trim($uname));
+ $n = count($parts);
+
+ $release = $machine = $cpu = '';
+ $sysname = $parts[0];
+ $nodename = $parts[1];
+ $cpu = $parts[$n-1];
+ $extra = '';
+ if ($cpu == 'unknown') {
+ $cpu = $parts[$n - 2];
+ }
+
+ switch ($sysname) {
+ case 'AIX' :
+ $release = "$parts[3].$parts[2]";
+ break;
+ case 'Windows' :
+ switch ($parts[1]) {
+ case '95/98':
+ $release = '9x';
+ break;
+ default:
+ $release = $parts[1];
+ break;
+ }
+ $cpu = 'i386';
+ break;
+ case 'Linux' :
+ $extra = $this->_detectGlibcVersion();
+ // use only the first two digits from the kernel version
+ $release = preg_replace('/^([0-9]+\.[0-9]+).*/', '\1', $parts[2]);
+ break;
+ case 'Mac' :
+ $sysname = 'darwin';
+ $nodename = $parts[2];
+ $release = $parts[3];
+ if ($cpu == 'Macintosh') {
+ if ($parts[$n - 2] == 'Power') {
+ $cpu = 'powerpc';
+ }
+ }
+ break;
+ case 'Darwin' :
+ if ($cpu == 'Macintosh') {
+ if ($parts[$n - 2] == 'Power') {
+ $cpu = 'powerpc';
+ }
+ }
+ $release = preg_replace('/^([0-9]+\.[0-9]+).*/', '\1', $parts[2]);
+ break;
+ default:
+ $release = preg_replace('/-.*/', '', $parts[2]);
+ break;
+ }
+
+ if (isset($sysmap[$sysname])) {
+ $sysname = $sysmap[$sysname];
+ } else {
+ $sysname = strtolower($sysname);
+ }
+ if (isset($cpumap[$cpu])) {
+ $cpu = $cpumap[$cpu];
+ }
+ return array($sysname, $release, $cpu, $extra, $nodename);
+ }
+
+ function _detectGlibcVersion()
+ {
+ static $glibc = false;
+ if ($glibc !== false) {
+ return $glibc; // no need to run this multiple times
+ }
+ $major = $minor = 0;
+ include_once "System.php";
+ // Use glibc's header file to
+ // get major and minor version number:
+ if (@file_exists('/usr/include/features.h') &&
+ @is_readable('/usr/include/features.h')) {
+ if (!@file_exists('/usr/bin/cpp') || !@is_executable('/usr/bin/cpp')) {
+ $features_file = fopen('/usr/include/features.h', 'rb');
+ while (!feof($features_file)) {
+ $line = fgets($features_file, 8192);
+ if (!$line || (strpos($line, '#define') === false)) {
+ continue;
+ }
+ if (strpos($line, '__GLIBC__')) {
+ // major version number #define __GLIBC__ version
+ $line = preg_split('/\s+/', $line);
+ $glibc_major = trim($line[2]);
+ if (isset($glibc_minor)) {
+ break;
+ }
+ continue;
+ }
+
+ if (strpos($line, '__GLIBC_MINOR__')) {
+ // got the minor version number
+ // #define __GLIBC_MINOR__ version
+ $line = preg_split('/\s+/', $line);
+ $glibc_minor = trim($line[2]);
+ if (isset($glibc_major)) {
+ break;
+ }
+ continue;
+ }
+ }
+ fclose($features_file);
+ if (!isset($glibc_major) || !isset($glibc_minor)) {
+ return $glibc = '';
+ }
+ return $glibc = 'glibc' . trim($glibc_major) . "." . trim($glibc_minor) ;
+ } // no cpp
+
+ $tmpfile = System::mktemp("glibctest");
+ $fp = fopen($tmpfile, "w");
+ fwrite($fp, "#include \n__GLIBC__ __GLIBC_MINOR__\n");
+ fclose($fp);
+ $cpp = popen("/usr/bin/cpp $tmpfile", "r");
+ while ($line = fgets($cpp, 1024)) {
+ if ($line{0} == '#' || trim($line) == '') {
+ continue;
+ }
+
+ if (list($major, $minor) = explode(' ', trim($line))) {
+ break;
+ }
+ }
+ pclose($cpp);
+ unlink($tmpfile);
+ } // features.h
+
+ if (!($major && $minor) && @is_link('/lib/libc.so.6')) {
+ // Let's try reading the libc.so.6 symlink
+ if (preg_match('/^libc-(.*)\.so$/', basename(readlink('/lib/libc.so.6')), $matches)) {
+ list($major, $minor) = explode('.', $matches[1]);
+ }
+ }
+
+ if (!($major && $minor)) {
+ return $glibc = '';
+ }
+
+ return $glibc = "glibc{$major}.{$minor}";
+ }
+
+ function getSignature()
+ {
+ if (empty($this->extra)) {
+ return "{$this->sysname}-{$this->release}-{$this->cpu}";
+ }
+ return "{$this->sysname}-{$this->release}-{$this->cpu}-{$this->extra}";
+ }
+
+ function getSysname()
+ {
+ return $this->sysname;
+ }
+
+ function getNodename()
+ {
+ return $this->nodename;
+ }
+
+ function getCpu()
+ {
+ return $this->cpu;
+ }
+
+ function getRelease()
+ {
+ return $this->release;
+ }
+
+ function getExtra()
+ {
+ return $this->extra;
+ }
+
+ function matchSignature($match)
+ {
+ $fragments = is_array($match) ? $match : explode('-', $match);
+ $n = count($fragments);
+ $matches = 0;
+ if ($n > 0) {
+ $matches += $this->_matchFragment($fragments[0], $this->sysname);
+ }
+ if ($n > 1) {
+ $matches += $this->_matchFragment($fragments[1], $this->release);
+ }
+ if ($n > 2) {
+ $matches += $this->_matchFragment($fragments[2], $this->cpu);
+ }
+ if ($n > 3) {
+ $matches += $this->_matchFragment($fragments[3], $this->extra);
+ }
+ return ($matches == $n);
+ }
+
+ function _matchFragment($fragment, $value)
+ {
+ if (strcspn($fragment, '*?') < strlen($fragment)) {
+ $reg = '/^' . str_replace(array('*', '?', '/'), array('.*', '.', '\\/'), $fragment) . '\\z/';
+ return preg_match($reg, $value);
+ }
+ return ($fragment == '*' || !strcasecmp($fragment, $value));
+ }
+
+}
+/*
+ * Local Variables:
+ * indent-tabs-mode: nil
+ * c-basic-offset: 4
+ * End:
+ */
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR.php b/vendor/pear-pear.php.net/PEAR/PEAR.php
new file mode 100644
index 000000000..7aa3c4ce5
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR.php
@@ -0,0 +1,1113 @@
+
+ * @author Stig Bakken
+ * @author Tomas V.V.Cox
+ * @author Greg Beaver
+ * @copyright 1997-2010 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ */
+
+/**#@+
+ * ERROR constants
+ */
+define('PEAR_ERROR_RETURN', 1);
+define('PEAR_ERROR_PRINT', 2);
+define('PEAR_ERROR_TRIGGER', 4);
+define('PEAR_ERROR_DIE', 8);
+define('PEAR_ERROR_CALLBACK', 16);
+/**
+ * WARNING: obsolete
+ * @deprecated
+ */
+define('PEAR_ERROR_EXCEPTION', 32);
+/**#@-*/
+
+if (substr(PHP_OS, 0, 3) == 'WIN') {
+ define('OS_WINDOWS', true);
+ define('OS_UNIX', false);
+ define('PEAR_OS', 'Windows');
+} else {
+ define('OS_WINDOWS', false);
+ define('OS_UNIX', true);
+ define('PEAR_OS', 'Unix'); // blatant assumption
+}
+
+$GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_RETURN;
+$GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE;
+$GLOBALS['_PEAR_destructor_object_list'] = array();
+$GLOBALS['_PEAR_shutdown_funcs'] = array();
+$GLOBALS['_PEAR_error_handler_stack'] = array();
+
+@ini_set('track_errors', true);
+
+/**
+ * Base class for other PEAR classes. Provides rudimentary
+ * emulation of destructors.
+ *
+ * If you want a destructor in your class, inherit PEAR and make a
+ * destructor method called _yourclassname (same name as the
+ * constructor, but with a "_" prefix). Also, in your constructor you
+ * have to call the PEAR constructor: $this->PEAR();.
+ * The destructor method will be called without parameters. Note that
+ * at in some SAPI implementations (such as Apache), any output during
+ * the request shutdown (in which destructors are called) seems to be
+ * discarded. If you need to get any debug information from your
+ * destructor, use error_log(), syslog() or something similar.
+ *
+ * IMPORTANT! To use the emulated destructors you need to create the
+ * objects by reference: $obj =& new PEAR_child;
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Tomas V.V. Cox
+ * @author Greg Beaver
+ * @copyright 1997-2006 The PHP Group
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @see PEAR_Error
+ * @since Class available since PHP 4.0.2
+ * @link http://pear.php.net/manual/en/core.pear.php#core.pear.pear
+ */
+class PEAR
+{
+ /**
+ * Whether to enable internal debug messages.
+ *
+ * @var bool
+ * @access private
+ */
+ var $_debug = false;
+
+ /**
+ * Default error mode for this object.
+ *
+ * @var int
+ * @access private
+ */
+ var $_default_error_mode = null;
+
+ /**
+ * Default error options used for this object when error mode
+ * is PEAR_ERROR_TRIGGER.
+ *
+ * @var int
+ * @access private
+ */
+ var $_default_error_options = null;
+
+ /**
+ * Default error handler (callback) for this object, if error mode is
+ * PEAR_ERROR_CALLBACK.
+ *
+ * @var string
+ * @access private
+ */
+ var $_default_error_handler = '';
+
+ /**
+ * Which class to use for error objects.
+ *
+ * @var string
+ * @access private
+ */
+ var $_error_class = 'PEAR_Error';
+
+ /**
+ * An array of expected errors.
+ *
+ * @var array
+ * @access private
+ */
+ var $_expected_errors = array();
+
+ /**
+ * List of methods that can be called both statically and non-statically.
+ * @var array
+ */
+ protected static $bivalentMethods = array(
+ 'setErrorHandling' => true,
+ 'raiseError' => true,
+ 'throwError' => true,
+ 'pushErrorHandling' => true,
+ 'popErrorHandling' => true,
+ );
+
+ /**
+ * Constructor. Registers this object in
+ * $_PEAR_destructor_object_list for destructor emulation if a
+ * destructor object exists.
+ *
+ * @param string $error_class (optional) which class to use for
+ * error objects, defaults to PEAR_Error.
+ * @access public
+ * @return void
+ */
+ function __construct($error_class = null)
+ {
+ $classname = strtolower(get_class($this));
+ if ($this->_debug) {
+ print "PEAR constructor called, class=$classname\n";
+ }
+
+ if ($error_class !== null) {
+ $this->_error_class = $error_class;
+ }
+
+ while ($classname && strcasecmp($classname, "pear")) {
+ $destructor = "_$classname";
+ if (method_exists($this, $destructor)) {
+ global $_PEAR_destructor_object_list;
+ $_PEAR_destructor_object_list[] = &$this;
+ if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) {
+ register_shutdown_function("_PEAR_call_destructors");
+ $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true;
+ }
+ break;
+ } else {
+ $classname = get_parent_class($classname);
+ }
+ }
+ }
+
+ /**
+ * Only here for backwards compatibility.
+ * E.g. Archive_Tar calls $this->PEAR() in its constructor.
+ *
+ * @param string $error_class Which class to use for error objects,
+ * defaults to PEAR_Error.
+ */
+ public function PEAR($error_class = null)
+ {
+ self::__construct($error_class);
+ }
+
+ /**
+ * Destructor (the emulated type of...). Does nothing right now,
+ * but is included for forward compatibility, so subclass
+ * destructors should always call it.
+ *
+ * See the note in the class desciption about output from
+ * destructors.
+ *
+ * @access public
+ * @return void
+ */
+ function _PEAR() {
+ if ($this->_debug) {
+ printf("PEAR destructor called, class=%s\n", strtolower(get_class($this)));
+ }
+ }
+
+ public function __call($method, $arguments)
+ {
+ if (!isset(self::$bivalentMethods[$method])) {
+ trigger_error(
+ 'Call to undefined method PEAR::' . $method . '()', E_USER_ERROR
+ );
+ }
+ return call_user_func_array(
+ array(get_class(), '_' . $method),
+ array_merge(array($this), $arguments)
+ );
+ }
+
+ public static function __callStatic($method, $arguments)
+ {
+ if (!isset(self::$bivalentMethods[$method])) {
+ trigger_error(
+ 'Call to undefined method PEAR::' . $method . '()', E_USER_ERROR
+ );
+ }
+ return call_user_func_array(
+ array(get_class(), '_' . $method),
+ array_merge(array(null), $arguments)
+ );
+ }
+
+ /**
+ * If you have a class that's mostly/entirely static, and you need static
+ * properties, you can use this method to simulate them. Eg. in your method(s)
+ * do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar');
+ * You MUST use a reference, or they will not persist!
+ *
+ * @param string $class The calling classname, to prevent clashes
+ * @param string $var The variable to retrieve.
+ * @return mixed A reference to the variable. If not set it will be
+ * auto initialised to NULL.
+ */
+ public static function &getStaticProperty($class, $var)
+ {
+ static $properties;
+ if (!isset($properties[$class])) {
+ $properties[$class] = array();
+ }
+
+ if (!array_key_exists($var, $properties[$class])) {
+ $properties[$class][$var] = null;
+ }
+
+ return $properties[$class][$var];
+ }
+
+ /**
+ * Use this function to register a shutdown method for static
+ * classes.
+ *
+ * @param mixed $func The function name (or array of class/method) to call
+ * @param mixed $args The arguments to pass to the function
+ *
+ * @return void
+ */
+ public static function registerShutdownFunc($func, $args = array())
+ {
+ // if we are called statically, there is a potential
+ // that no shutdown func is registered. Bug #6445
+ if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) {
+ register_shutdown_function("_PEAR_call_destructors");
+ $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true;
+ }
+ $GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args);
+ }
+
+ /**
+ * Tell whether a value is a PEAR error.
+ *
+ * @param mixed $data the value to test
+ * @param int $code if $data is an error object, return true
+ * only if $code is a string and
+ * $obj->getMessage() == $code or
+ * $code is an integer and $obj->getCode() == $code
+ *
+ * @return bool true if parameter is an error
+ */
+ public static function isError($data, $code = null)
+ {
+ if (!is_a($data, 'PEAR_Error')) {
+ return false;
+ }
+
+ if (is_null($code)) {
+ return true;
+ } elseif (is_string($code)) {
+ return $data->getMessage() == $code;
+ }
+
+ return $data->getCode() == $code;
+ }
+
+ /**
+ * Sets how errors generated by this object should be handled.
+ * Can be invoked both in objects and statically. If called
+ * statically, setErrorHandling sets the default behaviour for all
+ * PEAR objects. If called in an object, setErrorHandling sets
+ * the default behaviour for that object.
+ *
+ * @param object $object
+ * Object the method was called on (non-static mode)
+ *
+ * @param int $mode
+ * One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT,
+ * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE,
+ * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION.
+ *
+ * @param mixed $options
+ * When $mode is PEAR_ERROR_TRIGGER, this is the error level (one
+ * of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR).
+ *
+ * When $mode is PEAR_ERROR_CALLBACK, this parameter is expected
+ * to be the callback function or method. A callback
+ * function is a string with the name of the function, a
+ * callback method is an array of two elements: the element
+ * at index 0 is the object, and the element at index 1 is
+ * the name of the method to call in the object.
+ *
+ * When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is
+ * a printf format string used when printing the error
+ * message.
+ *
+ * @access public
+ * @return void
+ * @see PEAR_ERROR_RETURN
+ * @see PEAR_ERROR_PRINT
+ * @see PEAR_ERROR_TRIGGER
+ * @see PEAR_ERROR_DIE
+ * @see PEAR_ERROR_CALLBACK
+ * @see PEAR_ERROR_EXCEPTION
+ *
+ * @since PHP 4.0.5
+ */
+ protected static function _setErrorHandling(
+ $object, $mode = null, $options = null
+ ) {
+ if ($object !== null) {
+ $setmode = &$object->_default_error_mode;
+ $setoptions = &$object->_default_error_options;
+ } else {
+ $setmode = &$GLOBALS['_PEAR_default_error_mode'];
+ $setoptions = &$GLOBALS['_PEAR_default_error_options'];
+ }
+
+ switch ($mode) {
+ case PEAR_ERROR_EXCEPTION:
+ case PEAR_ERROR_RETURN:
+ case PEAR_ERROR_PRINT:
+ case PEAR_ERROR_TRIGGER:
+ case PEAR_ERROR_DIE:
+ case null:
+ $setmode = $mode;
+ $setoptions = $options;
+ break;
+
+ case PEAR_ERROR_CALLBACK:
+ $setmode = $mode;
+ // class/object method callback
+ if (is_callable($options)) {
+ $setoptions = $options;
+ } else {
+ trigger_error("invalid error callback", E_USER_WARNING);
+ }
+ break;
+
+ default:
+ trigger_error("invalid error mode", E_USER_WARNING);
+ break;
+ }
+ }
+
+ /**
+ * This method is used to tell which errors you expect to get.
+ * Expected errors are always returned with error mode
+ * PEAR_ERROR_RETURN. Expected error codes are stored in a stack,
+ * and this method pushes a new element onto it. The list of
+ * expected errors are in effect until they are popped off the
+ * stack with the popExpect() method.
+ *
+ * Note that this method can not be called statically
+ *
+ * @param mixed $code a single error code or an array of error codes to expect
+ *
+ * @return int the new depth of the "expected errors" stack
+ * @access public
+ */
+ function expectError($code = '*')
+ {
+ if (is_array($code)) {
+ array_push($this->_expected_errors, $code);
+ } else {
+ array_push($this->_expected_errors, array($code));
+ }
+ return count($this->_expected_errors);
+ }
+
+ /**
+ * This method pops one element off the expected error codes
+ * stack.
+ *
+ * @return array the list of error codes that were popped
+ */
+ function popExpect()
+ {
+ return array_pop($this->_expected_errors);
+ }
+
+ /**
+ * This method checks unsets an error code if available
+ *
+ * @param mixed error code
+ * @return bool true if the error code was unset, false otherwise
+ * @access private
+ * @since PHP 4.3.0
+ */
+ function _checkDelExpect($error_code)
+ {
+ $deleted = false;
+ foreach ($this->_expected_errors as $key => $error_array) {
+ if (in_array($error_code, $error_array)) {
+ unset($this->_expected_errors[$key][array_search($error_code, $error_array)]);
+ $deleted = true;
+ }
+
+ // clean up empty arrays
+ if (0 == count($this->_expected_errors[$key])) {
+ unset($this->_expected_errors[$key]);
+ }
+ }
+
+ return $deleted;
+ }
+
+ /**
+ * This method deletes all occurrences of the specified element from
+ * the expected error codes stack.
+ *
+ * @param mixed $error_code error code that should be deleted
+ * @return mixed list of error codes that were deleted or error
+ * @access public
+ * @since PHP 4.3.0
+ */
+ function delExpect($error_code)
+ {
+ $deleted = false;
+ if ((is_array($error_code) && (0 != count($error_code)))) {
+ // $error_code is a non-empty array here; we walk through it trying
+ // to unset all values
+ foreach ($error_code as $key => $error) {
+ $deleted = $this->_checkDelExpect($error) ? true : false;
+ }
+
+ return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME
+ } elseif (!empty($error_code)) {
+ // $error_code comes alone, trying to unset it
+ if ($this->_checkDelExpect($error_code)) {
+ return true;
+ }
+
+ return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME
+ }
+
+ // $error_code is empty
+ return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME
+ }
+
+ /**
+ * This method is a wrapper that returns an instance of the
+ * configured error class with this object's default error
+ * handling applied. If the $mode and $options parameters are not
+ * specified, the object's defaults are used.
+ *
+ * @param mixed $message a text error message or a PEAR error object
+ *
+ * @param int $code a numeric error code (it is up to your class
+ * to define these if you want to use codes)
+ *
+ * @param int $mode One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT,
+ * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE,
+ * PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION.
+ *
+ * @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter
+ * specifies the PHP-internal error level (one of
+ * E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR).
+ * If $mode is PEAR_ERROR_CALLBACK, this
+ * parameter specifies the callback function or
+ * method. In other error modes this parameter
+ * is ignored.
+ *
+ * @param string $userinfo If you need to pass along for example debug
+ * information, this parameter is meant for that.
+ *
+ * @param string $error_class The returned error object will be
+ * instantiated from this class, if specified.
+ *
+ * @param bool $skipmsg If true, raiseError will only pass error codes,
+ * the error message parameter will be dropped.
+ *
+ * @return object a PEAR error object
+ * @see PEAR::setErrorHandling
+ * @since PHP 4.0.5
+ */
+ protected static function _raiseError($object,
+ $message = null,
+ $code = null,
+ $mode = null,
+ $options = null,
+ $userinfo = null,
+ $error_class = null,
+ $skipmsg = false)
+ {
+ // The error is yet a PEAR error object
+ if (is_object($message)) {
+ $code = $message->getCode();
+ $userinfo = $message->getUserInfo();
+ $error_class = $message->getType();
+ $message->error_message_prefix = '';
+ $message = $message->getMessage();
+ }
+
+ if (
+ $object !== null &&
+ isset($object->_expected_errors) &&
+ count($object->_expected_errors) > 0 &&
+ count($exp = end($object->_expected_errors))
+ ) {
+ if ($exp[0] == "*" ||
+ (is_int(reset($exp)) && in_array($code, $exp)) ||
+ (is_string(reset($exp)) && in_array($message, $exp))
+ ) {
+ $mode = PEAR_ERROR_RETURN;
+ }
+ }
+
+ // No mode given, try global ones
+ if ($mode === null) {
+ // Class error handler
+ if ($object !== null && isset($object->_default_error_mode)) {
+ $mode = $object->_default_error_mode;
+ $options = $object->_default_error_options;
+ // Global error handler
+ } elseif (isset($GLOBALS['_PEAR_default_error_mode'])) {
+ $mode = $GLOBALS['_PEAR_default_error_mode'];
+ $options = $GLOBALS['_PEAR_default_error_options'];
+ }
+ }
+
+ if ($error_class !== null) {
+ $ec = $error_class;
+ } elseif ($object !== null && isset($object->_error_class)) {
+ $ec = $object->_error_class;
+ } else {
+ $ec = 'PEAR_Error';
+ }
+
+ if ($skipmsg) {
+ $a = new $ec($code, $mode, $options, $userinfo);
+ } else {
+ $a = new $ec($message, $code, $mode, $options, $userinfo);
+ }
+
+ return $a;
+ }
+
+ /**
+ * Simpler form of raiseError with fewer options. In most cases
+ * message, code and userinfo are enough.
+ *
+ * @param mixed $message a text error message or a PEAR error object
+ *
+ * @param int $code a numeric error code (it is up to your class
+ * to define these if you want to use codes)
+ *
+ * @param string $userinfo If you need to pass along for example debug
+ * information, this parameter is meant for that.
+ *
+ * @return object a PEAR error object
+ * @see PEAR::raiseError
+ */
+ protected static function _throwError($object, $message = null, $code = null, $userinfo = null)
+ {
+ if ($object !== null) {
+ $a = &$object->raiseError($message, $code, null, null, $userinfo);
+ return $a;
+ }
+
+ $a = &PEAR::raiseError($message, $code, null, null, $userinfo);
+ return $a;
+ }
+
+ public static function staticPushErrorHandling($mode, $options = null)
+ {
+ $stack = &$GLOBALS['_PEAR_error_handler_stack'];
+ $def_mode = &$GLOBALS['_PEAR_default_error_mode'];
+ $def_options = &$GLOBALS['_PEAR_default_error_options'];
+ $stack[] = array($def_mode, $def_options);
+ switch ($mode) {
+ case PEAR_ERROR_EXCEPTION:
+ case PEAR_ERROR_RETURN:
+ case PEAR_ERROR_PRINT:
+ case PEAR_ERROR_TRIGGER:
+ case PEAR_ERROR_DIE:
+ case null:
+ $def_mode = $mode;
+ $def_options = $options;
+ break;
+
+ case PEAR_ERROR_CALLBACK:
+ $def_mode = $mode;
+ // class/object method callback
+ if (is_callable($options)) {
+ $def_options = $options;
+ } else {
+ trigger_error("invalid error callback", E_USER_WARNING);
+ }
+ break;
+
+ default:
+ trigger_error("invalid error mode", E_USER_WARNING);
+ break;
+ }
+ $stack[] = array($mode, $options);
+ return true;
+ }
+
+ public static function staticPopErrorHandling()
+ {
+ $stack = &$GLOBALS['_PEAR_error_handler_stack'];
+ $setmode = &$GLOBALS['_PEAR_default_error_mode'];
+ $setoptions = &$GLOBALS['_PEAR_default_error_options'];
+ array_pop($stack);
+ list($mode, $options) = $stack[sizeof($stack) - 1];
+ array_pop($stack);
+ switch ($mode) {
+ case PEAR_ERROR_EXCEPTION:
+ case PEAR_ERROR_RETURN:
+ case PEAR_ERROR_PRINT:
+ case PEAR_ERROR_TRIGGER:
+ case PEAR_ERROR_DIE:
+ case null:
+ $setmode = $mode;
+ $setoptions = $options;
+ break;
+
+ case PEAR_ERROR_CALLBACK:
+ $setmode = $mode;
+ // class/object method callback
+ if (is_callable($options)) {
+ $setoptions = $options;
+ } else {
+ trigger_error("invalid error callback", E_USER_WARNING);
+ }
+ break;
+
+ default:
+ trigger_error("invalid error mode", E_USER_WARNING);
+ break;
+ }
+ return true;
+ }
+
+ /**
+ * Push a new error handler on top of the error handler options stack. With this
+ * you can easily override the actual error handler for some code and restore
+ * it later with popErrorHandling.
+ *
+ * @param mixed $mode (same as setErrorHandling)
+ * @param mixed $options (same as setErrorHandling)
+ *
+ * @return bool Always true
+ *
+ * @see PEAR::setErrorHandling
+ */
+ protected static function _pushErrorHandling($object, $mode, $options = null)
+ {
+ $stack = &$GLOBALS['_PEAR_error_handler_stack'];
+ if ($object !== null) {
+ $def_mode = &$object->_default_error_mode;
+ $def_options = &$object->_default_error_options;
+ } else {
+ $def_mode = &$GLOBALS['_PEAR_default_error_mode'];
+ $def_options = &$GLOBALS['_PEAR_default_error_options'];
+ }
+ $stack[] = array($def_mode, $def_options);
+
+ if ($object !== null) {
+ $object->setErrorHandling($mode, $options);
+ } else {
+ PEAR::setErrorHandling($mode, $options);
+ }
+ $stack[] = array($mode, $options);
+ return true;
+ }
+
+ /**
+ * Pop the last error handler used
+ *
+ * @return bool Always true
+ *
+ * @see PEAR::pushErrorHandling
+ */
+ protected static function _popErrorHandling($object)
+ {
+ $stack = &$GLOBALS['_PEAR_error_handler_stack'];
+ array_pop($stack);
+ list($mode, $options) = $stack[sizeof($stack) - 1];
+ array_pop($stack);
+ if ($object !== null) {
+ $object->setErrorHandling($mode, $options);
+ } else {
+ PEAR::setErrorHandling($mode, $options);
+ }
+ return true;
+ }
+
+ /**
+ * OS independent PHP extension load. Remember to take care
+ * on the correct extension name for case sensitive OSes.
+ *
+ * @param string $ext The extension name
+ * @return bool Success or not on the dl() call
+ */
+ public static function loadExtension($ext)
+ {
+ if (extension_loaded($ext)) {
+ return true;
+ }
+
+ // if either returns true dl() will produce a FATAL error, stop that
+ if (
+ function_exists('dl') === false ||
+ ini_get('enable_dl') != 1
+ ) {
+ return false;
+ }
+
+ if (OS_WINDOWS) {
+ $suffix = '.dll';
+ } elseif (PHP_OS == 'HP-UX') {
+ $suffix = '.sl';
+ } elseif (PHP_OS == 'AIX') {
+ $suffix = '.a';
+ } elseif (PHP_OS == 'OSX') {
+ $suffix = '.bundle';
+ } else {
+ $suffix = '.so';
+ }
+
+ return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix);
+ }
+}
+
+function _PEAR_call_destructors()
+{
+ global $_PEAR_destructor_object_list;
+ if (is_array($_PEAR_destructor_object_list) &&
+ sizeof($_PEAR_destructor_object_list))
+ {
+ reset($_PEAR_destructor_object_list);
+
+ $destructLifoExists = PEAR::getStaticProperty('PEAR', 'destructlifo');
+
+ if ($destructLifoExists) {
+ $_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list);
+ }
+
+ while (list($k, $objref) = each($_PEAR_destructor_object_list)) {
+ $classname = get_class($objref);
+ while ($classname) {
+ $destructor = "_$classname";
+ if (method_exists($objref, $destructor)) {
+ $objref->$destructor();
+ break;
+ } else {
+ $classname = get_parent_class($classname);
+ }
+ }
+ }
+ // Empty the object list to ensure that destructors are
+ // not called more than once.
+ $_PEAR_destructor_object_list = array();
+ }
+
+ // Now call the shutdown functions
+ if (
+ isset($GLOBALS['_PEAR_shutdown_funcs']) &&
+ is_array($GLOBALS['_PEAR_shutdown_funcs']) &&
+ !empty($GLOBALS['_PEAR_shutdown_funcs'])
+ ) {
+ foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) {
+ call_user_func_array($value[0], $value[1]);
+ }
+ }
+}
+
+/**
+ * Standard PEAR error class for PHP 4
+ *
+ * This class is supserseded by {@link PEAR_Exception} in PHP 5
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Tomas V.V. Cox
+ * @author Gregory Beaver
+ * @copyright 1997-2006 The PHP Group
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/manual/en/core.pear.pear-error.php
+ * @see PEAR::raiseError(), PEAR::throwError()
+ * @since Class available since PHP 4.0.2
+ */
+class PEAR_Error
+{
+ var $error_message_prefix = '';
+ var $mode = PEAR_ERROR_RETURN;
+ var $level = E_USER_NOTICE;
+ var $code = -1;
+ var $message = '';
+ var $userinfo = '';
+ var $backtrace = null;
+
+ /**
+ * PEAR_Error constructor
+ *
+ * @param string $message message
+ *
+ * @param int $code (optional) error code
+ *
+ * @param int $mode (optional) error mode, one of: PEAR_ERROR_RETURN,
+ * PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER,
+ * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION
+ *
+ * @param mixed $options (optional) error level, _OR_ in the case of
+ * PEAR_ERROR_CALLBACK, the callback function or object/method
+ * tuple.
+ *
+ * @param string $userinfo (optional) additional user/debug info
+ *
+ * @access public
+ *
+ */
+ function __construct($message = 'unknown error', $code = null,
+ $mode = null, $options = null, $userinfo = null)
+ {
+ if ($mode === null) {
+ $mode = PEAR_ERROR_RETURN;
+ }
+ $this->message = $message;
+ $this->code = $code;
+ $this->mode = $mode;
+ $this->userinfo = $userinfo;
+
+ $skiptrace = PEAR::getStaticProperty('PEAR_Error', 'skiptrace');
+
+ if (!$skiptrace) {
+ $this->backtrace = debug_backtrace();
+ if (isset($this->backtrace[0]) && isset($this->backtrace[0]['object'])) {
+ unset($this->backtrace[0]['object']);
+ }
+ }
+
+ if ($mode & PEAR_ERROR_CALLBACK) {
+ $this->level = E_USER_NOTICE;
+ $this->callback = $options;
+ } else {
+ if ($options === null) {
+ $options = E_USER_NOTICE;
+ }
+
+ $this->level = $options;
+ $this->callback = null;
+ }
+
+ if ($this->mode & PEAR_ERROR_PRINT) {
+ if (is_null($options) || is_int($options)) {
+ $format = "%s";
+ } else {
+ $format = $options;
+ }
+
+ printf($format, $this->getMessage());
+ }
+
+ if ($this->mode & PEAR_ERROR_TRIGGER) {
+ trigger_error($this->getMessage(), $this->level);
+ }
+
+ if ($this->mode & PEAR_ERROR_DIE) {
+ $msg = $this->getMessage();
+ if (is_null($options) || is_int($options)) {
+ $format = "%s";
+ if (substr($msg, -1) != "\n") {
+ $msg .= "\n";
+ }
+ } else {
+ $format = $options;
+ }
+ printf($format, $msg);
+ exit($code);
+ }
+
+ if ($this->mode & PEAR_ERROR_CALLBACK && is_callable($this->callback)) {
+ call_user_func($this->callback, $this);
+ }
+
+ if ($this->mode & PEAR_ERROR_EXCEPTION) {
+ trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_Exception for exceptions", E_USER_WARNING);
+ eval('$e = new Exception($this->message, $this->code);throw($e);');
+ }
+ }
+
+ /**
+ * Only here for backwards compatibility.
+ *
+ * Class "Cache_Error" still uses it, among others.
+ *
+ * @param string $message Message
+ * @param int $code Error code
+ * @param int $mode Error mode
+ * @param mixed $options See __construct()
+ * @param string $userinfo Additional user/debug info
+ */
+ public function PEAR_Error(
+ $message = 'unknown error', $code = null, $mode = null,
+ $options = null, $userinfo = null
+ ) {
+ self::__construct($message, $code, $mode, $options, $userinfo);
+ }
+
+ /**
+ * Get the error mode from an error object.
+ *
+ * @return int error mode
+ * @access public
+ */
+ function getMode()
+ {
+ return $this->mode;
+ }
+
+ /**
+ * Get the callback function/method from an error object.
+ *
+ * @return mixed callback function or object/method array
+ * @access public
+ */
+ function getCallback()
+ {
+ return $this->callback;
+ }
+
+ /**
+ * Get the error message from an error object.
+ *
+ * @return string full error message
+ * @access public
+ */
+ function getMessage()
+ {
+ return ($this->error_message_prefix . $this->message);
+ }
+
+ /**
+ * Get error code from an error object
+ *
+ * @return int error code
+ * @access public
+ */
+ function getCode()
+ {
+ return $this->code;
+ }
+
+ /**
+ * Get the name of this error/exception.
+ *
+ * @return string error/exception name (type)
+ * @access public
+ */
+ function getType()
+ {
+ return get_class($this);
+ }
+
+ /**
+ * Get additional user-supplied information.
+ *
+ * @return string user-supplied information
+ * @access public
+ */
+ function getUserInfo()
+ {
+ return $this->userinfo;
+ }
+
+ /**
+ * Get additional debug information supplied by the application.
+ *
+ * @return string debug information
+ * @access public
+ */
+ function getDebugInfo()
+ {
+ return $this->getUserInfo();
+ }
+
+ /**
+ * Get the call backtrace from where the error was generated.
+ * Supported with PHP 4.3.0 or newer.
+ *
+ * @param int $frame (optional) what frame to fetch
+ * @return array Backtrace, or NULL if not available.
+ * @access public
+ */
+ function getBacktrace($frame = null)
+ {
+ if (defined('PEAR_IGNORE_BACKTRACE')) {
+ return null;
+ }
+ if ($frame === null) {
+ return $this->backtrace;
+ }
+ return $this->backtrace[$frame];
+ }
+
+ function addUserInfo($info)
+ {
+ if (empty($this->userinfo)) {
+ $this->userinfo = $info;
+ } else {
+ $this->userinfo .= " ** $info";
+ }
+ }
+
+ function __toString()
+ {
+ return $this->getMessage();
+ }
+
+ /**
+ * Make a string representation of this object.
+ *
+ * @return string a string with an object summary
+ * @access public
+ */
+ function toString()
+ {
+ $modes = array();
+ $levels = array(E_USER_NOTICE => 'notice',
+ E_USER_WARNING => 'warning',
+ E_USER_ERROR => 'error');
+ if ($this->mode & PEAR_ERROR_CALLBACK) {
+ if (is_array($this->callback)) {
+ $callback = (is_object($this->callback[0]) ?
+ strtolower(get_class($this->callback[0])) :
+ $this->callback[0]) . '::' .
+ $this->callback[1];
+ } else {
+ $callback = $this->callback;
+ }
+ return sprintf('[%s: message="%s" code=%d mode=callback '.
+ 'callback=%s prefix="%s" info="%s"]',
+ strtolower(get_class($this)), $this->message, $this->code,
+ $callback, $this->error_message_prefix,
+ $this->userinfo);
+ }
+ if ($this->mode & PEAR_ERROR_PRINT) {
+ $modes[] = 'print';
+ }
+ if ($this->mode & PEAR_ERROR_TRIGGER) {
+ $modes[] = 'trigger';
+ }
+ if ($this->mode & PEAR_ERROR_DIE) {
+ $modes[] = 'die';
+ }
+ if ($this->mode & PEAR_ERROR_RETURN) {
+ $modes[] = 'return';
+ }
+ return sprintf('[%s: message="%s" code=%d mode=%s level=%s '.
+ 'prefix="%s" info="%s"]',
+ strtolower(get_class($this)), $this->message, $this->code,
+ implode("|", $modes), $levels[$this->level],
+ $this->error_message_prefix,
+ $this->userinfo);
+ }
+}
+
+/*
+ * Local Variables:
+ * mode: php
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Builder.php b/vendor/pear-pear.php.net/PEAR/PEAR/Builder.php
new file mode 100644
index 000000000..9df3b9eac
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Builder.php
@@ -0,0 +1,499 @@
+
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ *
+ * TODO: log output parameters in PECL command line
+ * TODO: msdev path in configuration
+ */
+
+/**
+ * Needed for extending PEAR_Builder
+ */
+require_once 'PEAR/Common.php';
+require_once 'PEAR/PackageFile.php';
+require_once 'System.php';
+
+/**
+ * Class to handle building (compiling) extensions.
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since PHP 4.0.2
+ * @see http://pear.php.net/manual/en/core.ppm.pear-builder.php
+ */
+class PEAR_Builder extends PEAR_Common
+{
+ var $php_api_version = 0;
+ var $zend_module_api_no = 0;
+ var $zend_extension_api_no = 0;
+
+ var $extensions_built = array();
+
+ /**
+ * @var string Used for reporting when it is not possible to pass function
+ * via extra parameter, e.g. log, msdevCallback
+ */
+ var $current_callback = null;
+
+ // used for msdev builds
+ var $_lastline = null;
+ var $_firstline = null;
+
+ /**
+ * PEAR_Builder constructor.
+ *
+ * @param object $ui user interface object (instance of PEAR_Frontend_*)
+ *
+ * @access public
+ */
+ function __construct(&$ui)
+ {
+ parent::__construct();
+ $this->setFrontendObject($ui);
+ }
+
+ /**
+ * Build an extension from source on windows.
+ * requires msdev
+ */
+ function _build_win32($descfile, $callback = null)
+ {
+ if (is_object($descfile)) {
+ $pkg = $descfile;
+ $descfile = $pkg->getPackageFile();
+ } else {
+ $pf = new PEAR_PackageFile($this->config, $this->debug);
+ $pkg = &$pf->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL);
+ if (PEAR::isError($pkg)) {
+ return $pkg;
+ }
+ }
+ $dir = dirname($descfile);
+ $old_cwd = getcwd();
+
+ if (!file_exists($dir) || !is_dir($dir) || !chdir($dir)) {
+ return $this->raiseError("could not chdir to $dir");
+ }
+
+ // packages that were in a .tar have the packagefile in this directory
+ $vdir = $pkg->getPackage() . '-' . $pkg->getVersion();
+ if (file_exists($dir) && is_dir($vdir)) {
+ if (!chdir($vdir)) {
+ return $this->raiseError("could not chdir to " . realpath($vdir));
+ }
+
+ $dir = getcwd();
+ }
+
+ $this->log(2, "building in $dir");
+
+ $dsp = $pkg->getPackage().'.dsp';
+ if (!file_exists("$dir/$dsp")) {
+ return $this->raiseError("The DSP $dsp does not exist.");
+ }
+ // XXX TODO: make release build type configurable
+ $command = 'msdev '.$dsp.' /MAKE "'.$pkg->getPackage(). ' - Release"';
+
+ $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('/.*?'.$pkg->getPackage().'\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+("'.
+ $pkg->getPackage().'\s-\s'.
+ $platform.'\s'.
+ $buildtype.'").*?'.
+ '\/out:"(.*?)"/is';
+
+ if ($dsptext && preg_match($regex, $dsptext, $matches)) {
+ // what we get back is a relative path to the output file itself.
+ $outfile = realpath($matches[2]);
+ } else {
+ return $this->raiseError("Could not retrieve output information from $dsp.");
+ }
+ // realpath returns false if the file doesn't exist
+ if ($outfile && copy($outfile, "$dir/$out")) {
+ $outfile = "$dir/$out";
+ }
+
+ $built_files[] = array(
+ 'file' => "$outfile",
+ 'php_api' => $this->php_api_version,
+ 'zend_mod_api' => $this->zend_module_api_no,
+ 'zend_ext_api' => $this->zend_extension_api_no,
+ );
+
+ return $built_files;
+ }
+ // }}}
+
+ // {{{ msdevCallback()
+ function msdevCallback($what, $data)
+ {
+ if (!$this->_firstline)
+ $this->_firstline = $data;
+ $this->_lastline = $data;
+ call_user_func($this->current_callback, $what, $data);
+ }
+
+ /**
+ * @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 an extension from source. Runs "phpize" in the source
+ * directory, but compiles in a temporary directory
+ * (TMPDIR/pear-build-USER/PACKAGE-VERSION).
+ *
+ * @param string|PEAR_PackageFile_v* $descfile path to XML package description file, or
+ * a PEAR_PackageFile object
+ *
+ * @param mixed $callback callback function used to report output,
+ * see PEAR_Builder::_runCommand for details
+ *
+ * @return array an array of associative arrays with built files,
+ * format:
+ * array( array( 'file' => '/path/to/ext.so',
+ * 'php_api' => YYYYMMDD,
+ * 'zend_mod_api' => YYYYMMDD,
+ * 'zend_ext_api' => YYYYMMDD ),
+ * ... )
+ *
+ * @access public
+ *
+ * @see PEAR_Builder::_runCommand
+ */
+ function build($descfile, $callback = null)
+ {
+ if (preg_match('/(\\/|\\\\|^)([^\\/\\\\]+)?php([^\\/\\\\]+)?$/',
+ $this->config->get('php_bin'), $matches)) {
+ if (isset($matches[2]) && strlen($matches[2]) &&
+ trim($matches[2]) != trim($this->config->get('php_prefix'))) {
+ $this->log(0, 'WARNING: php_bin ' . $this->config->get('php_bin') .
+ ' appears to have a prefix ' . $matches[2] . ', but' .
+ ' config variable php_prefix does not match');
+ }
+
+ if (isset($matches[3]) && strlen($matches[3]) &&
+ trim($matches[3]) != trim($this->config->get('php_suffix'))) {
+ $this->log(0, 'WARNING: php_bin ' . $this->config->get('php_bin') .
+ ' appears to have a suffix ' . $matches[3] . ', but' .
+ ' config variable php_suffix does not match');
+ }
+ }
+
+ $this->current_callback = $callback;
+ if (PEAR_OS == "Windows") {
+ return $this->_build_win32($descfile, $callback);
+ }
+
+ if (PEAR_OS != 'Unix') {
+ return $this->raiseError("building extensions not supported on this platform");
+ }
+
+ if (is_object($descfile)) {
+ $pkg = $descfile;
+ $descfile = $pkg->getPackageFile();
+ if (is_a($pkg, 'PEAR_PackageFile_v1')) {
+ $dir = dirname($descfile);
+ } else {
+ $dir = $pkg->_config->get('temp_dir') . '/' . $pkg->getName();
+ // automatically delete at session end
+ $this->addTempFile($dir);
+ }
+ } else {
+ $pf = new PEAR_PackageFile($this->config);
+ $pkg = &$pf->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL);
+ if (PEAR::isError($pkg)) {
+ return $pkg;
+ }
+ $dir = dirname($descfile);
+ }
+
+ // Find config. outside of normal path - e.g. config.m4
+ foreach (array_keys($pkg->getInstallationFileList()) as $item) {
+ if (stristr(basename($item), 'config.m4') && dirname($item) != '.') {
+ $dir .= DIRECTORY_SEPARATOR . dirname($item);
+ break;
+ }
+ }
+
+ $old_cwd = getcwd();
+ if (!file_exists($dir) || !is_dir($dir) || !chdir($dir)) {
+ return $this->raiseError("could not chdir to $dir");
+ }
+
+ $vdir = $pkg->getPackage() . '-' . $pkg->getVersion();
+ if (is_dir($vdir)) {
+ chdir($vdir);
+ }
+
+ $dir = getcwd();
+ $this->log(2, "building in $dir");
+ putenv('PATH=' . $this->config->get('bin_dir') . ':' . getenv('PATH'));
+ $err = $this->_runCommand($this->config->get('php_prefix')
+ . "phpize" .
+ $this->config->get('php_suffix'),
+ array(&$this, 'phpizeCallback'));
+ if (PEAR::isError($err)) {
+ return $err;
+ }
+
+ if (!$err) {
+ return $this->raiseError("`phpize' failed");
+ }
+
+ // {{{ start of interactive part
+ $configure_command = "$dir/configure";
+
+ $phpConfigName = $this->config->get('php_prefix')
+ . 'php-config'
+ . $this->config->get('php_suffix');
+ $phpConfigPath = System::which($phpConfigName);
+ if ($phpConfigPath !== false) {
+ $configure_command .= ' --with-php-config='
+ . $phpConfigPath;
+ }
+
+ $configure_options = $pkg->getConfigureOptions();
+ if ($configure_options) {
+ foreach ($configure_options as $o) {
+ $default = array_key_exists('default', $o) ? $o['default'] : null;
+ list($r) = $this->ui->userDialog('build',
+ array($o['prompt']),
+ array('text'),
+ array($default));
+ if (substr($o['name'], 0, 5) == 'with-' &&
+ ($r == 'yes' || $r == 'autodetect')) {
+ $configure_command .= " --$o[name]";
+ } else {
+ $configure_command .= " --$o[name]=".trim($r);
+ }
+ }
+ }
+ // }}} end of interactive part
+
+ // FIXME make configurable
+ if (!$user=getenv('USER')) {
+ $user='defaultuser';
+ }
+
+ $tmpdir = $this->config->get('temp_dir');
+ $build_basedir = System::mktemp(' -t "' . $tmpdir . '" -d "pear-build-' . $user . '"');
+ $build_dir = "$build_basedir/$vdir";
+ $inst_dir = "$build_basedir/install-$vdir";
+ $this->log(1, "building in $build_dir");
+ if (is_dir($build_dir)) {
+ System::rm(array('-rf', $build_dir));
+ }
+
+ if (!System::mkDir(array('-p', $build_dir))) {
+ return $this->raiseError("could not create build dir: $build_dir");
+ }
+
+ $this->addTempFile($build_dir);
+ if (!System::mkDir(array('-p', $inst_dir))) {
+ return $this->raiseError("could not create temporary install dir: $inst_dir");
+ }
+ $this->addTempFile($inst_dir);
+
+ $make_command = getenv('MAKE') ? getenv('MAKE') : 'make';
+
+ $to_run = array(
+ $configure_command,
+ $make_command,
+ "$make_command INSTALL_ROOT=\"$inst_dir\" install",
+ "find \"$inst_dir\" | xargs ls -dils"
+ );
+ if (!file_exists($build_dir) || !is_dir($build_dir) || !chdir($build_dir)) {
+ return $this->raiseError("could not chdir to $build_dir");
+ }
+ putenv('PHP_PEAR_VERSION=1.10.3');
+ foreach ($to_run as $cmd) {
+ $err = $this->_runCommand($cmd, $callback);
+ if (PEAR::isError($err)) {
+ chdir($old_cwd);
+ return $err;
+ }
+ if (!$err) {
+ chdir($old_cwd);
+ return $this->raiseError("`$cmd' failed");
+ }
+ }
+ if (!($dp = opendir("modules"))) {
+ chdir($old_cwd);
+ return $this->raiseError("no `modules' directory found");
+ }
+ $built_files = array();
+ $prefix = exec($this->config->get('php_prefix')
+ . "php-config" .
+ $this->config->get('php_suffix') . " --prefix");
+ $this->_harvestInstDir($prefix, $inst_dir . DIRECTORY_SEPARATOR . $prefix, $built_files);
+ chdir($old_cwd);
+ return $built_files;
+ }
+
+ /**
+ * 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);
+ }
+ }
+ }
+
+ /**
+ * 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 = is_resource($pp) ? pclose($pp) : -1;
+ return ($exitcode == 0);
+ }
+
+ function log($level, $msg, $append_crlf = true)
+ {
+ if ($this->current_callback) {
+ if ($this->debug >= $level) {
+ call_user_func($this->current_callback, 'output', $msg);
+ }
+ return;
+ }
+ return parent::log($level, $msg, $append_crlf);
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/ChannelFile.php b/vendor/pear-pear.php.net/PEAR/PEAR/ChannelFile.php
new file mode 100644
index 000000000..9e990d134
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/ChannelFile.php
@@ -0,0 +1,1560 @@
+
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+
+/**
+ * Needed for error handling
+ */
+require_once 'PEAR/ErrorStack.php';
+require_once 'PEAR/XMLParser.php';
+require_once 'PEAR/Common.php';
+
+/**
+ * Error code if the channel.xml tag does not contain a valid version
+ */
+define('PEAR_CHANNELFILE_ERROR_NO_VERSION', 1);
+/**
+ * Error code if the channel.xml tag version is not supported (version 1.0 is the only supported version,
+ * currently
+ */
+define('PEAR_CHANNELFILE_ERROR_INVALID_VERSION', 2);
+
+/**
+ * Error code if parsing is attempted with no xml extension
+ */
+define('PEAR_CHANNELFILE_ERROR_NO_XML_EXT', 3);
+
+/**
+ * Error code if creating the xml parser resource fails
+ */
+define('PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER', 4);
+
+/**
+ * Error code used for all sax xml parsing errors
+ */
+define('PEAR_CHANNELFILE_ERROR_PARSER_ERROR', 5);
+
+/**#@+
+ * Validation errors
+ */
+/**
+ * Error code when channel name is missing
+ */
+define('PEAR_CHANNELFILE_ERROR_NO_NAME', 6);
+/**
+ * Error code when channel name is invalid
+ */
+define('PEAR_CHANNELFILE_ERROR_INVALID_NAME', 7);
+/**
+ * Error code when channel summary is missing
+ */
+define('PEAR_CHANNELFILE_ERROR_NO_SUMMARY', 8);
+/**
+ * Error code when channel summary is multi-line
+ */
+define('PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY', 9);
+/**
+ * Error code when channel server is missing for protocol
+ */
+define('PEAR_CHANNELFILE_ERROR_NO_HOST', 10);
+/**
+ * Error code when channel server is invalid for protocol
+ */
+define('PEAR_CHANNELFILE_ERROR_INVALID_HOST', 11);
+/**
+ * Error code when a mirror name is invalid
+ */
+define('PEAR_CHANNELFILE_ERROR_INVALID_MIRROR', 21);
+/**
+ * Error code when a mirror type is invalid
+ */
+define('PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE', 22);
+/**
+ * Error code when an attempt is made to generate xml, but the parsed content is invalid
+ */
+define('PEAR_CHANNELFILE_ERROR_INVALID', 23);
+/**
+ * Error code when an empty package name validate regex is passed in
+ */
+define('PEAR_CHANNELFILE_ERROR_EMPTY_REGEX', 24);
+/**
+ * Error code when a tag has no version
+ */
+define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION', 25);
+/**
+ * Error code when a tag has no name
+ */
+define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME', 26);
+/**
+ * Error code when a tag has no name
+ */
+define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME', 27);
+/**
+ * Error code when a tag has no version attribute
+ */
+define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION', 28);
+/**
+ * Error code when a mirror does not exist but is called for in one of the set*
+ * methods.
+ */
+define('PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND', 32);
+/**
+ * Error code when a server port is not numeric
+ */
+define('PEAR_CHANNELFILE_ERROR_INVALID_PORT', 33);
+/**
+ * Error code when contains no version attribute
+ */
+define('PEAR_CHANNELFILE_ERROR_NO_STATICVERSION', 34);
+/**
+ * Error code when contains no type attribute in a protocol definition
+ */
+define('PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE', 35);
+/**
+ * Error code when a mirror is defined and the channel.xml represents the __uri pseudo-channel
+ */
+define('PEAR_CHANNELFILE_URI_CANT_MIRROR', 36);
+/**
+ * Error code when ssl attribute is present and is not "yes"
+ */
+define('PEAR_CHANNELFILE_ERROR_INVALID_SSL', 37);
+/**#@-*/
+
+/**
+ * Mirror types allowed. Currently only internet servers are recognized.
+ */
+$GLOBALS['_PEAR_CHANNELS_MIRROR_TYPES'] = array('server');
+
+
+/**
+ * The Channel handling class
+ *
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_ChannelFile
+{
+ /**
+ * @access private
+ * @var PEAR_ErrorStack
+ * @access private
+ */
+ var $_stack;
+
+ /**
+ * Supported channel.xml versions, for parsing
+ * @var array
+ * @access private
+ */
+ var $_supportedVersions = array('1.0');
+
+ /**
+ * Parsed channel information
+ * @var array
+ * @access private
+ */
+ var $_channelInfo;
+
+ /**
+ * index into the subchannels array, used for parsing xml
+ * @var int
+ * @access private
+ */
+ var $_subchannelIndex;
+
+ /**
+ * index into the mirrors array, used for parsing xml
+ * @var int
+ * @access private
+ */
+ var $_mirrorIndex;
+
+ /**
+ * Flag used to determine the validity of parsed content
+ * @var boolean
+ * @access private
+ */
+ var $_isValid = false;
+
+ function __construct()
+ {
+ $this->_stack = new PEAR_ErrorStack('PEAR_ChannelFile');
+ $this->_stack->setErrorMessageTemplate($this->_getErrorMessage());
+ $this->_isValid = false;
+ }
+
+ /**
+ * @return array
+ * @access protected
+ */
+ function _getErrorMessage()
+ {
+ return
+ array(
+ PEAR_CHANNELFILE_ERROR_INVALID_VERSION =>
+ 'While parsing channel.xml, an invalid version number "%version% was passed in, expecting one of %versions%',
+ PEAR_CHANNELFILE_ERROR_NO_VERSION =>
+ 'No version number found in tag',
+ PEAR_CHANNELFILE_ERROR_NO_XML_EXT =>
+ '%error%',
+ PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER =>
+ 'Unable to create XML parser',
+ PEAR_CHANNELFILE_ERROR_PARSER_ERROR =>
+ '%error%',
+ PEAR_CHANNELFILE_ERROR_NO_NAME =>
+ 'Missing channel name',
+ PEAR_CHANNELFILE_ERROR_INVALID_NAME =>
+ 'Invalid channel %tag% "%name%"',
+ PEAR_CHANNELFILE_ERROR_NO_SUMMARY =>
+ 'Missing channel summary',
+ PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY =>
+ 'Channel summary should be on one line, but is multi-line',
+ PEAR_CHANNELFILE_ERROR_NO_HOST =>
+ 'Missing channel server for %type% server',
+ PEAR_CHANNELFILE_ERROR_INVALID_HOST =>
+ 'Server name "%server%" is invalid for %type% server',
+ PEAR_CHANNELFILE_ERROR_INVALID_MIRROR =>
+ 'Invalid mirror name "%name%", mirror type %type%',
+ PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE =>
+ 'Invalid mirror type "%type%"',
+ PEAR_CHANNELFILE_ERROR_INVALID =>
+ 'Cannot generate xml, contents are invalid',
+ PEAR_CHANNELFILE_ERROR_EMPTY_REGEX =>
+ 'packagenameregex cannot be empty',
+ PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION =>
+ '%parent% %protocol% function has no version',
+ PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME =>
+ '%parent% %protocol% function has no name',
+ PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE =>
+ '%parent% rest baseurl has no type',
+ PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME =>
+ 'Validation package has no name in tag',
+ PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION =>
+ 'Validation package "%package%" has no version',
+ PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND =>
+ 'Mirror "%mirror%" does not exist',
+ PEAR_CHANNELFILE_ERROR_INVALID_PORT =>
+ 'Port "%port%" must be numeric',
+ PEAR_CHANNELFILE_ERROR_NO_STATICVERSION =>
+ ' tag must contain version attribute',
+ PEAR_CHANNELFILE_URI_CANT_MIRROR =>
+ 'The __uri pseudo-channel cannot have mirrors',
+ PEAR_CHANNELFILE_ERROR_INVALID_SSL =>
+ '%server% has invalid ssl attribute "%ssl%" can only be yes or not present',
+ );
+ }
+
+ /**
+ * @param string contents of package.xml file
+ * @return bool success of parsing
+ */
+ function fromXmlString($data)
+ {
+ if (preg_match('/_supportedVersions)) {
+ $this->_stack->push(PEAR_CHANNELFILE_ERROR_INVALID_VERSION, 'error',
+ array('version' => $channelversion[1]));
+ return false;
+ }
+ $parser = new PEAR_XMLParser;
+ $result = $parser->parse($data);
+ if ($result !== true) {
+ if ($result->getCode() == 1) {
+ $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_XML_EXT, 'error',
+ array('error' => $result->getMessage()));
+ } else {
+ $this->_stack->push(PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER, 'error');
+ }
+ return false;
+ }
+ $this->_channelInfo = $parser->getData();
+ return true;
+ } else {
+ $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_VERSION, 'error', array('xml' => $data));
+ return false;
+ }
+ }
+
+ /**
+ * @return array
+ */
+ function toArray()
+ {
+ if (!$this->_isValid && !$this->validate()) {
+ return false;
+ }
+ return $this->_channelInfo;
+ }
+
+ /**
+ * @param array
+ *
+ * @return PEAR_ChannelFile|false false if invalid
+ */
+ public static function &fromArray(
+ $data, $compatibility = false, $stackClass = 'PEAR_ErrorStack'
+ ) {
+ $a = new PEAR_ChannelFile($compatibility, $stackClass);
+ $a->_fromArray($data);
+ if (!$a->validate()) {
+ $a = false;
+ return $a;
+ }
+ return $a;
+ }
+
+ /**
+ * Unlike {@link fromArray()} this does not do any validation
+ *
+ * @param array
+ *
+ * @return PEAR_ChannelFile
+ */
+ public static function &fromArrayWithErrors(
+ $data, $compatibility = false, $stackClass = 'PEAR_ErrorStack'
+ ) {
+ $a = new PEAR_ChannelFile($compatibility, $stackClass);
+ $a->_fromArray($data);
+ return $a;
+ }
+
+ /**
+ * @param array
+ * @access private
+ */
+ function _fromArray($data)
+ {
+ $this->_channelInfo = $data;
+ }
+
+ /**
+ * Wrapper to {@link PEAR_ErrorStack::getErrors()}
+ * @param boolean determines whether to purge the error stack after retrieving
+ * @return array
+ */
+ function getErrors($purge = false)
+ {
+ return $this->_stack->getErrors($purge);
+ }
+
+ /**
+ * Unindent given string (?)
+ *
+ * @param string $str The string that has to be unindented.
+ * @return string
+ * @access private
+ */
+ function _unIndent($str)
+ {
+ // remove leading newlines
+ $str = preg_replace('/^[\r\n]+/', '', $str);
+ // find whitespace at the beginning of the first line
+ $indent_len = strspn($str, " \t");
+ $indent = substr($str, 0, $indent_len);
+ $data = '';
+ // remove the same amount of whitespace from following lines
+ foreach (explode("\n", $str) as $line) {
+ if (substr($line, 0, $indent_len) == $indent) {
+ $data .= substr($line, $indent_len) . "\n";
+ }
+ }
+ return $data;
+ }
+
+ /**
+ * Parse a channel.xml file. Expects the name of
+ * a channel xml file as input.
+ *
+ * @param string $descfile name of channel xml file
+ * @return bool success of parsing
+ */
+ function fromXmlFile($descfile)
+ {
+ if (!file_exists($descfile) || !is_file($descfile) || !is_readable($descfile) ||
+ (!$fp = fopen($descfile, 'r'))) {
+ require_once 'PEAR.php';
+ return PEAR::raiseError("Unable to open $descfile");
+ }
+
+ // read the whole thing so we only get one cdata callback
+ // for each block of cdata
+ fclose($fp);
+ $data = file_get_contents($descfile);
+ return $this->fromXmlString($data);
+ }
+
+ /**
+ * Parse channel information from different sources
+ *
+ * This method is able to extract information about a channel
+ * from an .xml file or a string
+ *
+ * @access public
+ * @param string Filename of the source or the source itself
+ * @return bool
+ */
+ function fromAny($info)
+ {
+ if (is_string($info) && file_exists($info) && strlen($info) < 255) {
+ $tmp = substr($info, -4);
+ if ($tmp == '.xml') {
+ $info = $this->fromXmlFile($info);
+ } else {
+ $fp = fopen($info, "r");
+ $test = fread($fp, 5);
+ fclose($fp);
+ if ($test == "fromXmlFile($info);
+ }
+ }
+ if (PEAR::isError($info)) {
+ require_once 'PEAR.php';
+ return PEAR::raiseError($info);
+ }
+ }
+ if (is_string($info)) {
+ $info = $this->fromXmlString($info);
+ }
+ return $info;
+ }
+
+ /**
+ * Return an XML document based on previous parsing and modifications
+ *
+ * @return string XML data
+ *
+ * @access public
+ */
+ function toXml()
+ {
+ if (!$this->_isValid && !$this->validate()) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID);
+ return false;
+ }
+ if (!isset($this->_channelInfo['attribs']['version'])) {
+ $this->_channelInfo['attribs']['version'] = '1.0';
+ }
+ $channelInfo = $this->_channelInfo;
+ $ret = "\n";
+ $ret .= "
+ $channelInfo[name]
+ " . htmlspecialchars($channelInfo['summary'])."
+";
+ if (isset($channelInfo['suggestedalias'])) {
+ $ret .= ' ' . $channelInfo['suggestedalias'] . "\n";
+ }
+ if (isset($channelInfo['validatepackage'])) {
+ $ret .= ' ' .
+ htmlspecialchars($channelInfo['validatepackage']['_content']) .
+ "\n";
+ }
+ $ret .= " \n";
+ $ret .= ' _makeRestXml($channelInfo['servers']['primary']['rest'], ' ');
+ }
+ $ret .= " \n";
+ if (isset($channelInfo['servers']['mirror'])) {
+ $ret .= $this->_makeMirrorsXml($channelInfo);
+ }
+ $ret .= " \n";
+ $ret .= "";
+ return str_replace("\r", "\n", str_replace("\r\n", "\n", $ret));
+ }
+
+ /**
+ * Generate the tag
+ * @access private
+ */
+ function _makeRestXml($info, $indent)
+ {
+ $ret = $indent . "\n";
+ if (isset($info['baseurl']) && !isset($info['baseurl'][0])) {
+ $info['baseurl'] = array($info['baseurl']);
+ }
+
+ if (isset($info['baseurl'])) {
+ foreach ($info['baseurl'] as $url) {
+ $ret .= "$indent \n";
+ }
+ }
+ $ret .= $indent . "\n";
+ return $ret;
+ }
+
+ /**
+ * Generate the tag
+ * @access private
+ */
+ function _makeMirrorsXml($channelInfo)
+ {
+ $ret = "";
+ if (!isset($channelInfo['servers']['mirror'][0])) {
+ $channelInfo['servers']['mirror'] = array($channelInfo['servers']['mirror']);
+ }
+ foreach ($channelInfo['servers']['mirror'] as $mirror) {
+ $ret .= ' _makeRestXml($mirror['rest'], ' ');
+ }
+ $ret .= " \n";
+ } else {
+ $ret .= "/>\n";
+ }
+ }
+ return $ret;
+ }
+
+ /**
+ * Generate the tag
+ * @access private
+ */
+ function _makeFunctionsXml($functions, $indent, $rest = false)
+ {
+ $ret = '';
+ if (!isset($functions[0])) {
+ $functions = array($functions);
+ }
+ foreach ($functions as $function) {
+ $ret .= "$indent\n";
+ }
+ return $ret;
+ }
+
+ /**
+ * Validation error. Also marks the object contents as invalid
+ * @param error code
+ * @param array error information
+ * @access private
+ */
+ function _validateError($code, $params = array())
+ {
+ $this->_stack->push($code, 'error', $params);
+ $this->_isValid = false;
+ }
+
+ /**
+ * Validation warning. Does not mark the object contents invalid.
+ * @param error code
+ * @param array error information
+ * @access private
+ */
+ function _validateWarning($code, $params = array())
+ {
+ $this->_stack->push($code, 'warning', $params);
+ }
+
+ /**
+ * Validate parsed file.
+ *
+ * @access public
+ * @return boolean
+ */
+ function validate()
+ {
+ $this->_isValid = true;
+ $info = $this->_channelInfo;
+ if (empty($info['name'])) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_NAME);
+ } elseif (!$this->validChannelServer($info['name'])) {
+ if ($info['name'] != '__uri') {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, array('tag' => 'name',
+ 'name' => $info['name']));
+ }
+ }
+ if (empty($info['summary'])) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY);
+ } elseif (strpos(trim($info['summary']), "\n") !== false) {
+ $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY,
+ array('summary' => $info['summary']));
+ }
+ if (isset($info['suggestedalias'])) {
+ if (!$this->validChannelServer($info['suggestedalias'])) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
+ array('tag' => 'suggestedalias', 'name' =>$info['suggestedalias']));
+ }
+ }
+ if (isset($info['localalias'])) {
+ if (!$this->validChannelServer($info['localalias'])) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
+ array('tag' => 'localalias', 'name' =>$info['localalias']));
+ }
+ }
+ if (isset($info['validatepackage'])) {
+ if (!isset($info['validatepackage']['_content'])) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME);
+ }
+ if (!isset($info['validatepackage']['attribs']['version'])) {
+ $content = isset($info['validatepackage']['_content']) ?
+ $info['validatepackage']['_content'] :
+ null;
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION,
+ array('package' => $content));
+ }
+ }
+
+ if (isset($info['servers']['primary']['attribs'], $info['servers']['primary']['attribs']['port']) &&
+ !is_numeric($info['servers']['primary']['attribs']['port'])) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_PORT,
+ array('port' => $info['servers']['primary']['attribs']['port']));
+ }
+
+ if (isset($info['servers']['primary']['attribs'], $info['servers']['primary']['attribs']['ssl']) &&
+ $info['servers']['primary']['attribs']['ssl'] != 'yes') {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL,
+ array('ssl' => $info['servers']['primary']['attribs']['ssl'],
+ 'server' => $info['name']));
+ }
+
+ if (isset($info['servers']['primary']['rest']) &&
+ isset($info['servers']['primary']['rest']['baseurl'])) {
+ $this->_validateFunctions('rest', $info['servers']['primary']['rest']['baseurl']);
+ }
+ if (isset($info['servers']['mirror'])) {
+ if ($this->_channelInfo['name'] == '__uri') {
+ $this->_validateError(PEAR_CHANNELFILE_URI_CANT_MIRROR);
+ }
+ if (!isset($info['servers']['mirror'][0])) {
+ $info['servers']['mirror'] = array($info['servers']['mirror']);
+ }
+ foreach ($info['servers']['mirror'] as $mirror) {
+ if (!isset($mirror['attribs']['host'])) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_HOST,
+ array('type' => 'mirror'));
+ } elseif (!$this->validChannelServer($mirror['attribs']['host'])) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_HOST,
+ array('server' => $mirror['attribs']['host'], 'type' => 'mirror'));
+ }
+ if (isset($mirror['attribs']['ssl']) && $mirror['attribs']['ssl'] != 'yes') {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL,
+ array('ssl' => $info['ssl'], 'server' => $mirror['attribs']['host']));
+ }
+ if (isset($mirror['rest'])) {
+ $this->_validateFunctions('rest', $mirror['rest']['baseurl'],
+ $mirror['attribs']['host']);
+ }
+ }
+ }
+ return $this->_isValid;
+ }
+
+ /**
+ * @param string rest - protocol name this function applies to
+ * @param array the functions
+ * @param string the name of the parent element (mirror name, for instance)
+ */
+ function _validateFunctions($protocol, $functions, $parent = '')
+ {
+ if (!isset($functions[0])) {
+ $functions = array($functions);
+ }
+
+ foreach ($functions as $function) {
+ if (!isset($function['_content']) || empty($function['_content'])) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME,
+ array('parent' => $parent, 'protocol' => $protocol));
+ }
+
+ if ($protocol == 'rest') {
+ if (!isset($function['attribs']['type']) ||
+ empty($function['attribs']['type'])) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE,
+ array('parent' => $parent, 'protocol' => $protocol));
+ }
+ } else {
+ if (!isset($function['attribs']['version']) ||
+ empty($function['attribs']['version'])) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION,
+ array('parent' => $parent, 'protocol' => $protocol));
+ }
+ }
+ }
+ }
+
+ /**
+ * Test whether a string contains a valid channel server.
+ * @param string $ver the package version to test
+ * @return bool
+ */
+ function validChannelServer($server)
+ {
+ if ($server == '__uri') {
+ return true;
+ }
+ return (bool) preg_match(PEAR_CHANNELS_SERVER_PREG, $server);
+ }
+
+ /**
+ * @return string|false
+ */
+ function getName()
+ {
+ if (isset($this->_channelInfo['name'])) {
+ return $this->_channelInfo['name'];
+ }
+
+ return false;
+ }
+
+ /**
+ * @return string|false
+ */
+ function getServer()
+ {
+ if (isset($this->_channelInfo['name'])) {
+ return $this->_channelInfo['name'];
+ }
+
+ return false;
+ }
+
+ /**
+ * @return int|80 port number to connect to
+ */
+ function getPort($mirror = false)
+ {
+ if ($mirror) {
+ if ($mir = $this->getMirror($mirror)) {
+ if (isset($mir['attribs']['port'])) {
+ return $mir['attribs']['port'];
+ }
+
+ if ($this->getSSL($mirror)) {
+ return 443;
+ }
+
+ return 80;
+ }
+
+ return false;
+ }
+
+ if (isset($this->_channelInfo['servers']['primary']['attribs']['port'])) {
+ return $this->_channelInfo['servers']['primary']['attribs']['port'];
+ }
+
+ if ($this->getSSL()) {
+ return 443;
+ }
+
+ return 80;
+ }
+
+ /**
+ * @return bool Determines whether secure sockets layer (SSL) is used to connect to this channel
+ */
+ function getSSL($mirror = false)
+ {
+ if ($mirror) {
+ if ($mir = $this->getMirror($mirror)) {
+ if (isset($mir['attribs']['ssl'])) {
+ return true;
+ }
+
+ return false;
+ }
+
+ return false;
+ }
+
+ if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @return string|false
+ */
+ function getSummary()
+ {
+ if (isset($this->_channelInfo['summary'])) {
+ return $this->_channelInfo['summary'];
+ }
+
+ return false;
+ }
+
+ /**
+ * @param string protocol type
+ * @param string Mirror name
+ * @return array|false
+ */
+ function getFunctions($protocol, $mirror = false)
+ {
+ if ($this->getName() == '__uri') {
+ return false;
+ }
+
+ $function = $protocol == 'rest' ? 'baseurl' : 'function';
+ if ($mirror) {
+ if ($mir = $this->getMirror($mirror)) {
+ if (isset($mir[$protocol][$function])) {
+ return $mir[$protocol][$function];
+ }
+ }
+
+ return false;
+ }
+
+ if (isset($this->_channelInfo['servers']['primary'][$protocol][$function])) {
+ return $this->_channelInfo['servers']['primary'][$protocol][$function];
+ }
+
+ return false;
+ }
+
+ /**
+ * @param string Protocol type
+ * @param string Function name (null to return the
+ * first protocol of the type requested)
+ * @param string Mirror name, if any
+ * @return array
+ */
+ function getFunction($type, $name = null, $mirror = false)
+ {
+ $protocols = $this->getFunctions($type, $mirror);
+ if (!$protocols) {
+ return false;
+ }
+
+ foreach ($protocols as $protocol) {
+ if ($name === null) {
+ return $protocol;
+ }
+
+ if ($protocol['_content'] != $name) {
+ continue;
+ }
+
+ return $protocol;
+ }
+
+ return false;
+ }
+
+ /**
+ * @param string protocol type
+ * @param string protocol name
+ * @param string version
+ * @param string mirror name
+ * @return boolean
+ */
+ function supports($type, $name = null, $mirror = false, $version = '1.0')
+ {
+ $protocols = $this->getFunctions($type, $mirror);
+ if (!$protocols) {
+ return false;
+ }
+
+ foreach ($protocols as $protocol) {
+ if ($protocol['attribs']['version'] != $version) {
+ continue;
+ }
+
+ if ($name === null) {
+ return true;
+ }
+
+ if ($protocol['_content'] != $name) {
+ continue;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Determines whether a channel supports Representational State Transfer (REST) protocols
+ * for retrieving channel information
+ * @param string
+ * @return bool
+ */
+ function supportsREST($mirror = false)
+ {
+ if ($mirror == $this->_channelInfo['name']) {
+ $mirror = false;
+ }
+
+ if ($mirror) {
+ if ($mir = $this->getMirror($mirror)) {
+ return isset($mir['rest']);
+ }
+
+ return false;
+ }
+
+ return isset($this->_channelInfo['servers']['primary']['rest']);
+ }
+
+ /**
+ * Get the URL to access a base resource.
+ *
+ * Hyperlinks in the returned xml will be used to retrieve the proper information
+ * needed. This allows extreme extensibility and flexibility in implementation
+ * @param string Resource Type to retrieve
+ */
+ function getBaseURL($resourceType, $mirror = false)
+ {
+ if ($mirror == $this->_channelInfo['name']) {
+ $mirror = false;
+ }
+
+ if ($mirror) {
+ $mir = $this->getMirror($mirror);
+ if (!$mir) {
+ return false;
+ }
+
+ $rest = $mir['rest'];
+ } else {
+ $rest = $this->_channelInfo['servers']['primary']['rest'];
+ }
+
+ if (!isset($rest['baseurl'][0])) {
+ $rest['baseurl'] = array($rest['baseurl']);
+ }
+
+ foreach ($rest['baseurl'] as $baseurl) {
+ if (strtolower($baseurl['attribs']['type']) == strtolower($resourceType)) {
+ return $baseurl['_content'];
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Since REST does not implement RPC, provide this as a logical wrapper around
+ * resetFunctions for REST
+ * @param string|false mirror name, if any
+ */
+ function resetREST($mirror = false)
+ {
+ return $this->resetFunctions('rest', $mirror);
+ }
+
+ /**
+ * Empty all protocol definitions
+ * @param string protocol type
+ * @param string|false mirror name, if any
+ */
+ function resetFunctions($type, $mirror = false)
+ {
+ if ($mirror) {
+ if (isset($this->_channelInfo['servers']['mirror'])) {
+ $mirrors = $this->_channelInfo['servers']['mirror'];
+ if (!isset($mirrors[0])) {
+ $mirrors = array($mirrors);
+ }
+
+ foreach ($mirrors as $i => $mir) {
+ if ($mir['attribs']['host'] == $mirror) {
+ if (isset($this->_channelInfo['servers']['mirror'][$i][$type])) {
+ unset($this->_channelInfo['servers']['mirror'][$i][$type]);
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ return false;
+ }
+
+ if (isset($this->_channelInfo['servers']['primary'][$type])) {
+ unset($this->_channelInfo['servers']['primary'][$type]);
+ }
+
+ return true;
+ }
+
+ /**
+ * Set a channel's protocols to the protocols supported by pearweb
+ */
+ function setDefaultPEARProtocols($version = '1.0', $mirror = false)
+ {
+ switch ($version) {
+ case '1.0' :
+ $this->resetREST($mirror);
+
+ if (!isset($this->_channelInfo['servers'])) {
+ $this->_channelInfo['servers'] = array('primary' =>
+ array('rest' => array()));
+ } elseif (!isset($this->_channelInfo['servers']['primary'])) {
+ $this->_channelInfo['servers']['primary'] = array('rest' => array());
+ }
+
+ return true;
+ break;
+ default :
+ return false;
+ break;
+ }
+ }
+
+ /**
+ * @return array
+ */
+ function getMirrors()
+ {
+ if (isset($this->_channelInfo['servers']['mirror'])) {
+ $mirrors = $this->_channelInfo['servers']['mirror'];
+ if (!isset($mirrors[0])) {
+ $mirrors = array($mirrors);
+ }
+
+ return $mirrors;
+ }
+
+ return array();
+ }
+
+ /**
+ * Get the unserialized XML representing a mirror
+ * @return array|false
+ */
+ function getMirror($server)
+ {
+ foreach ($this->getMirrors() as $mirror) {
+ if ($mirror['attribs']['host'] == $server) {
+ return $mirror;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * @param string
+ * @return string|false
+ * @error PEAR_CHANNELFILE_ERROR_NO_NAME
+ * @error PEAR_CHANNELFILE_ERROR_INVALID_NAME
+ */
+ function setName($name)
+ {
+ return $this->setServer($name);
+ }
+
+ /**
+ * Set the socket number (port) that is used to connect to this channel
+ * @param integer
+ * @param string|false name of the mirror server, or false for the primary
+ */
+ function setPort($port, $mirror = false)
+ {
+ if ($mirror) {
+ if (!isset($this->_channelInfo['servers']['mirror'])) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
+ array('mirror' => $mirror));
+ return false;
+ }
+
+ if (isset($this->_channelInfo['servers']['mirror'][0])) {
+ foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
+ if ($mirror == $mir['attribs']['host']) {
+ $this->_channelInfo['servers']['mirror'][$i]['attribs']['port'] = $port;
+ return true;
+ }
+ }
+
+ return false;
+ } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
+ $this->_channelInfo['servers']['mirror']['attribs']['port'] = $port;
+ $this->_isValid = false;
+ return true;
+ }
+ }
+
+ $this->_channelInfo['servers']['primary']['attribs']['port'] = $port;
+ $this->_isValid = false;
+ return true;
+ }
+
+ /**
+ * Set the socket number (port) that is used to connect to this channel
+ * @param bool Determines whether to turn on SSL support or turn it off
+ * @param string|false name of the mirror server, or false for the primary
+ */
+ function setSSL($ssl = true, $mirror = false)
+ {
+ if ($mirror) {
+ if (!isset($this->_channelInfo['servers']['mirror'])) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
+ array('mirror' => $mirror));
+ return false;
+ }
+
+ if (isset($this->_channelInfo['servers']['mirror'][0])) {
+ foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
+ if ($mirror == $mir['attribs']['host']) {
+ if (!$ssl) {
+ if (isset($this->_channelInfo['servers']['mirror'][$i]
+ ['attribs']['ssl'])) {
+ unset($this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl']);
+ }
+ } else {
+ $this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl'] = 'yes';
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+ } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
+ if (!$ssl) {
+ if (isset($this->_channelInfo['servers']['mirror']['attribs']['ssl'])) {
+ unset($this->_channelInfo['servers']['mirror']['attribs']['ssl']);
+ }
+ } else {
+ $this->_channelInfo['servers']['mirror']['attribs']['ssl'] = 'yes';
+ }
+
+ $this->_isValid = false;
+ return true;
+ }
+ }
+
+ if ($ssl) {
+ $this->_channelInfo['servers']['primary']['attribs']['ssl'] = 'yes';
+ } else {
+ if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) {
+ unset($this->_channelInfo['servers']['primary']['attribs']['ssl']);
+ }
+ }
+
+ $this->_isValid = false;
+ return true;
+ }
+
+ /**
+ * @param string
+ * @return string|false
+ * @error PEAR_CHANNELFILE_ERROR_NO_SERVER
+ * @error PEAR_CHANNELFILE_ERROR_INVALID_SERVER
+ */
+ function setServer($server, $mirror = false)
+ {
+ if (empty($server)) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SERVER);
+ return false;
+ } elseif (!$this->validChannelServer($server)) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
+ array('tag' => 'name', 'name' => $server));
+ return false;
+ }
+
+ if ($mirror) {
+ $found = false;
+ foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
+ if ($mirror == $mir['attribs']['host']) {
+ $found = true;
+ break;
+ }
+ }
+
+ if (!$found) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
+ array('mirror' => $mirror));
+ return false;
+ }
+
+ $this->_channelInfo['mirror'][$i]['attribs']['host'] = $server;
+ return true;
+ }
+
+ $this->_channelInfo['name'] = $server;
+ return true;
+ }
+
+ /**
+ * @param string
+ * @return boolean success
+ * @error PEAR_CHANNELFILE_ERROR_NO_SUMMARY
+ * @warning PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY
+ */
+ function setSummary($summary)
+ {
+ if (empty($summary)) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY);
+ return false;
+ } elseif (strpos(trim($summary), "\n") !== false) {
+ $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY,
+ array('summary' => $summary));
+ }
+
+ $this->_channelInfo['summary'] = $summary;
+ return true;
+ }
+
+ /**
+ * @param string
+ * @param boolean determines whether the alias is in channel.xml or local
+ * @return boolean success
+ */
+ function setAlias($alias, $local = false)
+ {
+ if (!$this->validChannelServer($alias)) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
+ array('tag' => 'suggestedalias', 'name' => $alias));
+ return false;
+ }
+
+ if ($local) {
+ $this->_channelInfo['localalias'] = $alias;
+ } else {
+ $this->_channelInfo['suggestedalias'] = $alias;
+ }
+
+ return true;
+ }
+
+ /**
+ * @return string
+ */
+ function getAlias()
+ {
+ if (isset($this->_channelInfo['localalias'])) {
+ return $this->_channelInfo['localalias'];
+ }
+ if (isset($this->_channelInfo['suggestedalias'])) {
+ return $this->_channelInfo['suggestedalias'];
+ }
+ if (isset($this->_channelInfo['name'])) {
+ return $this->_channelInfo['name'];
+ }
+ return '';
+ }
+
+ /**
+ * Set the package validation object if it differs from PEAR's default
+ * The class must be includeable via changing _ in the classname to path separator,
+ * but no checking of this is made.
+ * @param string|false pass in false to reset to the default packagename regex
+ * @return boolean success
+ */
+ function setValidationPackage($validateclass, $version)
+ {
+ if (empty($validateclass)) {
+ unset($this->_channelInfo['validatepackage']);
+ }
+ $this->_channelInfo['validatepackage'] = array('_content' => $validateclass);
+ $this->_channelInfo['validatepackage']['attribs'] = array('version' => $version);
+ }
+
+ /**
+ * Add a protocol to the provides section
+ * @param string protocol type
+ * @param string protocol version
+ * @param string protocol name, if any
+ * @param string mirror name, if this is a mirror's protocol
+ * @return bool
+ */
+ function addFunction($type, $version, $name = '', $mirror = false)
+ {
+ if ($mirror) {
+ return $this->addMirrorFunction($mirror, $type, $version, $name);
+ }
+
+ $set = array('attribs' => array('version' => $version), '_content' => $name);
+ if (!isset($this->_channelInfo['servers']['primary'][$type]['function'])) {
+ if (!isset($this->_channelInfo['servers'])) {
+ $this->_channelInfo['servers'] = array('primary' =>
+ array($type => array()));
+ } elseif (!isset($this->_channelInfo['servers']['primary'])) {
+ $this->_channelInfo['servers']['primary'] = array($type => array());
+ }
+
+ $this->_channelInfo['servers']['primary'][$type]['function'] = $set;
+ $this->_isValid = false;
+ return true;
+ } elseif (!isset($this->_channelInfo['servers']['primary'][$type]['function'][0])) {
+ $this->_channelInfo['servers']['primary'][$type]['function'] = array(
+ $this->_channelInfo['servers']['primary'][$type]['function']);
+ }
+
+ $this->_channelInfo['servers']['primary'][$type]['function'][] = $set;
+ return true;
+ }
+ /**
+ * Add a protocol to a mirror's provides section
+ * @param string mirror name (server)
+ * @param string protocol type
+ * @param string protocol version
+ * @param string protocol name, if any
+ */
+ function addMirrorFunction($mirror, $type, $version, $name = '')
+ {
+ if (!isset($this->_channelInfo['servers']['mirror'])) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
+ array('mirror' => $mirror));
+ return false;
+ }
+
+ $setmirror = false;
+ if (isset($this->_channelInfo['servers']['mirror'][0])) {
+ foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
+ if ($mirror == $mir['attribs']['host']) {
+ $setmirror = &$this->_channelInfo['servers']['mirror'][$i];
+ break;
+ }
+ }
+ } else {
+ if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
+ $setmirror = &$this->_channelInfo['servers']['mirror'];
+ }
+ }
+
+ if (!$setmirror) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
+ array('mirror' => $mirror));
+ return false;
+ }
+
+ $set = array('attribs' => array('version' => $version), '_content' => $name);
+ if (!isset($setmirror[$type]['function'])) {
+ $setmirror[$type]['function'] = $set;
+ $this->_isValid = false;
+ return true;
+ } elseif (!isset($setmirror[$type]['function'][0])) {
+ $setmirror[$type]['function'] = array($setmirror[$type]['function']);
+ }
+
+ $setmirror[$type]['function'][] = $set;
+ $this->_isValid = false;
+ return true;
+ }
+
+ /**
+ * @param string Resource Type this url links to
+ * @param string URL
+ * @param string|false mirror name, if this is not a primary server REST base URL
+ */
+ function setBaseURL($resourceType, $url, $mirror = false)
+ {
+ if ($mirror) {
+ if (!isset($this->_channelInfo['servers']['mirror'])) {
+ $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
+ array('mirror' => $mirror));
+ return false;
+ }
+
+ $setmirror = false;
+ if (isset($this->_channelInfo['servers']['mirror'][0])) {
+ foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
+ if ($mirror == $mir['attribs']['host']) {
+ $setmirror = &$this->_channelInfo['servers']['mirror'][$i];
+ break;
+ }
+ }
+ } else {
+ if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
+ $setmirror = &$this->_channelInfo['servers']['mirror'];
+ }
+ }
+ } else {
+ $setmirror = &$this->_channelInfo['servers']['primary'];
+ }
+
+ $set = array('attribs' => array('type' => $resourceType), '_content' => $url);
+ if (!isset($setmirror['rest'])) {
+ $setmirror['rest'] = array();
+ }
+
+ if (!isset($setmirror['rest']['baseurl'])) {
+ $setmirror['rest']['baseurl'] = $set;
+ $this->_isValid = false;
+ return true;
+ } elseif (!isset($setmirror['rest']['baseurl'][0])) {
+ $setmirror['rest']['baseurl'] = array($setmirror['rest']['baseurl']);
+ }
+
+ foreach ($setmirror['rest']['baseurl'] as $i => $url) {
+ if ($url['attribs']['type'] == $resourceType) {
+ $this->_isValid = false;
+ $setmirror['rest']['baseurl'][$i] = $set;
+ return true;
+ }
+ }
+
+ $setmirror['rest']['baseurl'][] = $set;
+ $this->_isValid = false;
+ return true;
+ }
+
+ /**
+ * @param string mirror server
+ * @param int mirror http port
+ * @return boolean
+ */
+ function addMirror($server, $port = null)
+ {
+ if ($this->_channelInfo['name'] == '__uri') {
+ return false; // the __uri channel cannot have mirrors by definition
+ }
+
+ $set = array('attribs' => array('host' => $server));
+ if (is_numeric($port)) {
+ $set['attribs']['port'] = $port;
+ }
+
+ if (!isset($this->_channelInfo['servers']['mirror'])) {
+ $this->_channelInfo['servers']['mirror'] = $set;
+ return true;
+ }
+
+ if (!isset($this->_channelInfo['servers']['mirror'][0])) {
+ $this->_channelInfo['servers']['mirror'] =
+ array($this->_channelInfo['servers']['mirror']);
+ }
+
+ $this->_channelInfo['servers']['mirror'][] = $set;
+ return true;
+ }
+
+ /**
+ * Retrieve the name of the validation package for this channel
+ * @return string|false
+ */
+ function getValidationPackage()
+ {
+ if (!$this->_isValid && !$this->validate()) {
+ return false;
+ }
+
+ if (!isset($this->_channelInfo['validatepackage'])) {
+ return array('attribs' => array('version' => 'default'),
+ '_content' => 'PEAR_Validate');
+ }
+
+ return $this->_channelInfo['validatepackage'];
+ }
+
+ /**
+ * Retrieve the object that can be used for custom validation
+ * @param string|false the name of the package to validate. If the package is
+ * the channel validation package, PEAR_Validate is returned
+ * @return PEAR_Validate|false false is returned if the validation package
+ * cannot be located
+ */
+ function &getValidationObject($package = false)
+ {
+ if (!class_exists('PEAR_Validate')) {
+ require_once 'PEAR/Validate.php';
+ }
+
+ if (!$this->_isValid) {
+ if (!$this->validate()) {
+ $a = false;
+ return $a;
+ }
+ }
+
+ if (isset($this->_channelInfo['validatepackage'])) {
+ if ($package == $this->_channelInfo['validatepackage']) {
+ // channel validation packages are always validated by PEAR_Validate
+ $val = new PEAR_Validate;
+ return $val;
+ }
+
+ if (!class_exists(str_replace('.', '_',
+ $this->_channelInfo['validatepackage']['_content']))) {
+ if ($this->isIncludeable(str_replace('_', '/',
+ $this->_channelInfo['validatepackage']['_content']) . '.php')) {
+ include_once str_replace('_', '/',
+ $this->_channelInfo['validatepackage']['_content']) . '.php';
+ $vclass = str_replace('.', '_',
+ $this->_channelInfo['validatepackage']['_content']);
+ $val = new $vclass;
+ } else {
+ $a = false;
+ return $a;
+ }
+ } else {
+ $vclass = str_replace('.', '_',
+ $this->_channelInfo['validatepackage']['_content']);
+ $val = new $vclass;
+ }
+ } else {
+ $val = new PEAR_Validate;
+ }
+
+ return $val;
+ }
+
+ function isIncludeable($path)
+ {
+ $possibilities = explode(PATH_SEPARATOR, ini_get('include_path'));
+ foreach ($possibilities as $dir) {
+ if (file_exists($dir . DIRECTORY_SEPARATOR . $path)
+ && is_readable($dir . DIRECTORY_SEPARATOR . $path)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * This function is used by the channel updater and retrieves a value set by
+ * the registry, or the current time if it has not been set
+ * @return string
+ */
+ function lastModified()
+ {
+ if (isset($this->_channelInfo['_lastmodified'])) {
+ return $this->_channelInfo['_lastmodified'];
+ }
+
+ return time();
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/ChannelFile/Parser.php b/vendor/pear-pear.php.net/PEAR/PEAR/ChannelFile/Parser.php
new file mode 100644
index 000000000..56376add6
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/ChannelFile/Parser.php
@@ -0,0 +1,67 @@
+
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+
+/**
+ * base xml parser class
+ */
+require_once 'PEAR/XMLParser.php';
+require_once 'PEAR/ChannelFile.php';
+/**
+ * Parser for channel.xml
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_ChannelFile_Parser extends PEAR_XMLParser
+{
+ var $_config;
+ var $_logger;
+ var $_registry;
+
+ function setConfig(&$c)
+ {
+ $this->_config = &$c;
+ $this->_registry = &$c->getRegistry();
+ }
+
+ function setLogger(&$l)
+ {
+ $this->_logger = &$l;
+ }
+
+ function parse($data, $file)
+ {
+ if (PEAR::isError($err = parent::parse($data, $file))) {
+ return $err;
+ }
+
+ $ret = new PEAR_ChannelFile;
+ $ret->setConfig($this->_config);
+ if (isset($this->_logger)) {
+ $ret->setLogger($this->_logger);
+ }
+
+ $ret->fromArray($this->_unserializedData);
+ // make sure the filelist is in the easy to read format needed
+ $ret->flattenFilelist();
+ $ret->setPackagefile($file, $archive);
+ return $ret;
+ }
+}
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Command.php b/vendor/pear-pear.php.net/PEAR/PEAR/Command.php
new file mode 100644
index 000000000..39823c674
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Command.php
@@ -0,0 +1,389 @@
+
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ */
+
+/**
+ * Needed for error handling
+ */
+require_once 'PEAR.php';
+require_once 'PEAR/Frontend.php';
+require_once 'PEAR/XMLParser.php';
+
+/**
+ * List of commands and what classes they are implemented in.
+ * @var array command => implementing class
+ */
+$GLOBALS['_PEAR_Command_commandlist'] = array();
+
+/**
+ * List of commands and their descriptions
+ * @var array command => description
+ */
+$GLOBALS['_PEAR_Command_commanddesc'] = array();
+
+/**
+ * List of shortcuts to common commands.
+ * @var array shortcut => command
+ */
+$GLOBALS['_PEAR_Command_shortcuts'] = array();
+
+/**
+ * Array of command objects
+ * @var array class => object
+ */
+$GLOBALS['_PEAR_Command_objects'] = array();
+
+/**
+ * PEAR command class, a simple factory class for administrative
+ * commands.
+ *
+ * How to implement command classes:
+ *
+ * - The class must be called PEAR_Command_Nnn, installed in the
+ * "PEAR/Common" subdir, with a method called getCommands() that
+ * returns an array of the commands implemented by the class (see
+ * PEAR/Command/Install.php for an example).
+ *
+ * - The class must implement a run() function that is called with three
+ * params:
+ *
+ * (string) command name
+ * (array) assoc array with options, freely defined by each
+ * command, for example:
+ * array('force' => true)
+ * (array) list of the other parameters
+ *
+ * The run() function returns a PEAR_CommandResponse object. Use
+ * these methods to get information:
+ *
+ * int getStatus() Returns PEAR_COMMAND_(SUCCESS|FAILURE|PARTIAL)
+ * *_PARTIAL means that you need to issue at least
+ * one more command to complete the operation
+ * (used for example for validation steps).
+ *
+ * string getMessage() Returns a message for the user. Remember,
+ * no HTML or other interface-specific markup.
+ *
+ * If something unexpected happens, run() returns a PEAR error.
+ *
+ * - DON'T OUTPUT ANYTHING! Return text for output instead.
+ *
+ * - DON'T USE HTML! The text you return will be used from both Gtk,
+ * web and command-line interfaces, so for now, keep everything to
+ * plain text.
+ *
+ * - DON'T USE EXIT OR DIE! Always use pear errors. From static
+ * classes do PEAR::raiseError(), from other classes do
+ * $this->raiseError().
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 0.1
+ */
+class PEAR_Command
+{
+ // {{{ factory()
+
+ /**
+ * Get the right object for executing a command.
+ *
+ * @param string $command The name of the command
+ * @param object $config Instance of PEAR_Config object
+ *
+ * @return object the command object or a PEAR error
+ */
+ public static function &factory($command, &$config)
+ {
+ if (empty($GLOBALS['_PEAR_Command_commandlist'])) {
+ PEAR_Command::registerCommands();
+ }
+ if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) {
+ $command = $GLOBALS['_PEAR_Command_shortcuts'][$command];
+ }
+ if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) {
+ $a = PEAR::raiseError("unknown command `$command'");
+ return $a;
+ }
+ $class = $GLOBALS['_PEAR_Command_commandlist'][$command];
+ if (!class_exists($class)) {
+ require_once $GLOBALS['_PEAR_Command_objects'][$class];
+ }
+ if (!class_exists($class)) {
+ $a = PEAR::raiseError("unknown command `$command'");
+ return $a;
+ }
+ $ui =& PEAR_Command::getFrontendObject();
+ $obj = new $class($ui, $config);
+ return $obj;
+ }
+
+ // }}}
+ // {{{ & getObject()
+ public static function &getObject($command)
+ {
+ $class = $GLOBALS['_PEAR_Command_commandlist'][$command];
+ if (!class_exists($class)) {
+ require_once $GLOBALS['_PEAR_Command_objects'][$class];
+ }
+ if (!class_exists($class)) {
+ return PEAR::raiseError("unknown command `$command'");
+ }
+ $ui =& PEAR_Command::getFrontendObject();
+ $config = &PEAR_Config::singleton();
+ $obj = new $class($ui, $config);
+ return $obj;
+ }
+
+ // }}}
+ // {{{ & getFrontendObject()
+
+ /**
+ * Get instance of frontend object.
+ *
+ * @return object|PEAR_Error
+ */
+ public static function &getFrontendObject()
+ {
+ $a = &PEAR_Frontend::singleton();
+ return $a;
+ }
+
+ // }}}
+ // {{{ & setFrontendClass()
+
+ /**
+ * Load current frontend class.
+ *
+ * @param string $uiclass Name of class implementing the frontend
+ *
+ * @return object the frontend object, or a PEAR error
+ */
+ public static function &setFrontendClass($uiclass)
+ {
+ $a = &PEAR_Frontend::setFrontendClass($uiclass);
+ return $a;
+ }
+
+ // }}}
+ // {{{ setFrontendType()
+
+ /**
+ * Set current frontend.
+ *
+ * @param string $uitype Name of the frontend type (for example "CLI")
+ *
+ * @return object the frontend object, or a PEAR error
+ */
+ public 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
+ */
+ public static function registerCommands($merge = false, $dir = null)
+ {
+ $parser = new PEAR_XMLParser;
+ if ($dir === null) {
+ $dir = dirname(__FILE__) . '/Command';
+ }
+ if (!is_dir($dir)) {
+ return PEAR::raiseError("registerCommands: opendir($dir) '$dir' does not exist or is not a directory");
+ }
+ $dp = @opendir($dir);
+ if (empty($dp)) {
+ return PEAR::raiseError("registerCommands: opendir($dir) failed");
+ }
+ if (!$merge) {
+ $GLOBALS['_PEAR_Command_commandlist'] = array();
+ }
+
+ while ($file = readdir($dp)) {
+ if ($file{0} == '.' || substr($file, -4) != '.xml') {
+ continue;
+ }
+
+ $f = substr($file, 0, -4);
+ $class = "PEAR_Command_" . $f;
+ // List of commands
+ if (empty($GLOBALS['_PEAR_Command_objects'][$class])) {
+ $GLOBALS['_PEAR_Command_objects'][$class] = "$dir/" . $f . '.php';
+ }
+
+ $parser->parse(file_get_contents("$dir/$file"));
+ $implements = $parser->getData();
+ foreach ($implements as $command => $desc) {
+ if ($command == 'attribs') {
+ continue;
+ }
+
+ if (isset($GLOBALS['_PEAR_Command_commandlist'][$command])) {
+ return PEAR::raiseError('Command "' . $command . '" already registered in ' .
+ 'class "' . $GLOBALS['_PEAR_Command_commandlist'][$command] . '"');
+ }
+
+ $GLOBALS['_PEAR_Command_commandlist'][$command] = $class;
+ $GLOBALS['_PEAR_Command_commanddesc'][$command] = $desc['summary'];
+ if (isset($desc['shortcut'])) {
+ $shortcut = $desc['shortcut'];
+ if (isset($GLOBALS['_PEAR_Command_shortcuts'][$shortcut])) {
+ return PEAR::raiseError('Command shortcut "' . $shortcut . '" already ' .
+ 'registered to command "' . $command . '" in class "' .
+ $GLOBALS['_PEAR_Command_commandlist'][$command] . '"');
+ }
+ $GLOBALS['_PEAR_Command_shortcuts'][$shortcut] = $command;
+ }
+
+ if (isset($desc['options']) && $desc['options']) {
+ foreach ($desc['options'] as $oname => $option) {
+ if (isset($option['shortopt']) && strlen($option['shortopt']) > 1) {
+ return PEAR::raiseError('Option "' . $oname . '" short option "' .
+ $option['shortopt'] . '" must be ' .
+ 'only 1 character in Command "' . $command . '" in class "' .
+ $class . '"');
+ }
+ }
+ }
+ }
+ }
+
+ ksort($GLOBALS['_PEAR_Command_shortcuts']);
+ ksort($GLOBALS['_PEAR_Command_commandlist']);
+ @closedir($dp);
+ return true;
+ }
+
+ // }}}
+ // {{{ getCommands()
+
+ /**
+ * Get the list of currently supported commands, and what
+ * classes implement them.
+ *
+ * @return array command => implementing class
+ */
+ 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
+ */
+ 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
+ */
+ public static function getGetoptArgs($command, &$short_args, &$long_args)
+ {
+ if (empty($GLOBALS['_PEAR_Command_commandlist'])) {
+ PEAR_Command::registerCommands();
+ }
+ if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) {
+ $command = $GLOBALS['_PEAR_Command_shortcuts'][$command];
+ }
+ if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) {
+ return null;
+ }
+ $obj = &PEAR_Command::getObject($command);
+ return $obj->getGetoptArgs($command, $short_args, $long_args);
+ }
+
+ // }}}
+ // {{{ getDescription()
+
+ /**
+ * Get description for a command.
+ *
+ * @param string $command Name of the command
+ *
+ * @return string command description
+ */
+ 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
+ */
+ public static function getHelp($command)
+ {
+ $cmds = PEAR_Command::getCommands();
+ if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) {
+ $command = $GLOBALS['_PEAR_Command_shortcuts'][$command];
+ }
+ if (isset($cmds[$command])) {
+ $obj = &PEAR_Command::getObject($command);
+ return $obj->getHelp($command);
+ }
+ return false;
+ }
+ // }}}
+}
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Command/Auth.php b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Auth.php
new file mode 100644
index 000000000..fa2b22bf5
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Auth.php
@@ -0,0 +1,80 @@
+
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ * @deprecated since 1.8.0alpha1
+ */
+
+/**
+ * base class
+ */
+require_once 'PEAR/Command/Channels.php';
+
+/**
+ * PEAR commands for login/logout
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 0.1
+ * @deprecated since 1.8.0alpha1
+ */
+class PEAR_Command_Auth extends PEAR_Command_Channels
+{
+ var $commands = array(
+ 'login' => array(
+ 'summary' => 'Connects and authenticates to remote server [Deprecated in favor of channel-login]',
+ 'shortcut' => 'li',
+ 'function' => 'doLogin',
+ 'options' => array(),
+ 'doc' => '
+WARNING: This function is deprecated in favor of using channel-login
+
+Log in to a remote channel server. If is not supplied,
+the default channel is used. To use remote functions in the installer
+that require any kind of privileges, you need to log in first. The
+username and password you enter here will be stored in your per-user
+PEAR configuration (~/.pearrc on Unix-like systems). After logging
+in, your username and password will be sent along in subsequent
+operations on the remote server.',
+ ),
+ 'logout' => array(
+ 'summary' => 'Logs out from the remote server [Deprecated in favor of channel-logout]',
+ 'shortcut' => 'lo',
+ 'function' => 'doLogout',
+ 'options' => array(),
+ 'doc' => '
+WARNING: This function is deprecated in favor of using channel-logout
+
+Logs out from the remote server. This command does not actually
+connect to the remote server, it only deletes the stored username and
+password from your user configuration.',
+ )
+
+ );
+
+ /**
+ * PEAR_Command_Auth constructor.
+ *
+ * @access public
+ */
+ function __construct(&$ui, &$config)
+ {
+ parent::__construct($ui, $config);
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Command/Auth.xml b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Auth.xml
new file mode 100644
index 000000000..590193d14
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Auth.xml
@@ -0,0 +1,30 @@
+
+
+ Connects and authenticates to remote server [Deprecated in favor of channel-login]
+ doLogin
+ li
+
+ <channel name>
+WARNING: This function is deprecated in favor of using channel-login
+
+Log in to a remote channel server. If <channel name> is not supplied,
+the default channel is used. To use remote functions in the installer
+that require any kind of privileges, you need to log in first. The
+username and password you enter here will be stored in your per-user
+PEAR configuration (~/.pearrc on Unix-like systems). After logging
+in, your username and password will be sent along in subsequent
+operations on the remote server.
+
+
+ Logs out from the remote server [Deprecated in favor of channel-logout]
+ doLogout
+ lo
+
+
+WARNING: This function is deprecated in favor of using channel-logout
+
+Logs out from the remote server. This command does not actually
+connect to the remote server, it only deletes the stored username and
+password from your user configuration.
+
+
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Command/Build.php b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Build.php
new file mode 100644
index 000000000..3bb99454d
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Build.php
@@ -0,0 +1,84 @@
+
+ * @author Tomas V.V.Cox
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ */
+
+/**
+ * base class
+ */
+require_once 'PEAR/Command/Common.php';
+
+/**
+ * PEAR commands for building extensions.
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Tomas V.V.Cox
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 0.1
+ */
+class PEAR_Command_Build extends PEAR_Command_Common
+{
+ var $commands = array(
+ 'build' => array(
+ 'summary' => 'Build an Extension From C Source',
+ 'function' => 'doBuild',
+ 'shortcut' => 'b',
+ 'options' => array(),
+ 'doc' => '[package.xml]
+Builds one or more extensions contained in a package.'
+ ),
+ );
+
+ /**
+ * PEAR_Command_Build constructor.
+ *
+ * @access public
+ */
+ function __construct(&$ui, &$config)
+ {
+ parent::__construct($ui, $config);
+ }
+
+ function doBuild($command, $options, $params)
+ {
+ require_once 'PEAR/Builder.php';
+ if (sizeof($params) < 1) {
+ $params[0] = 'package.xml';
+ }
+
+ $builder = new PEAR_Builder($this->ui);
+ $this->debug = $this->config->get('verbose');
+ $err = $builder->build($params[0], array(&$this, 'buildCallback'));
+ if (PEAR::isError($err)) {
+ return $err;
+ }
+
+ return true;
+ }
+
+ function buildCallback($what, $data)
+ {
+ if (($what == 'cmdoutput' && $this->debug > 1) ||
+ ($what == 'output' && $this->debug > 0)) {
+ $this->ui->outputData(rtrim($data), 'build');
+ }
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Command/Build.xml b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Build.xml
new file mode 100644
index 000000000..ec4e6f554
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Build.xml
@@ -0,0 +1,10 @@
+
+
+ Build an Extension From C Source
+ doBuild
+ b
+
+ [package.xml]
+Builds one or more extensions contained in a package.
+
+
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Command/Channels.php b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Channels.php
new file mode 100644
index 000000000..b9286370a
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Channels.php
@@ -0,0 +1,882 @@
+
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+
+/**
+ * base class
+ */
+require_once 'PEAR/Command/Common.php';
+
+define('PEAR_COMMAND_CHANNELS_CHANNEL_EXISTS', -500);
+
+/**
+ * PEAR commands for managing channels.
+ *
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_Command_Channels extends PEAR_Command_Common
+{
+ var $commands = array(
+ 'list-channels' => array(
+ 'summary' => 'List Available Channels',
+ 'function' => 'doList',
+ 'shortcut' => 'lc',
+ 'options' => array(),
+ 'doc' => '
+List all available channels for installation.
+',
+ ),
+ 'update-channels' => array(
+ 'summary' => 'Update the Channel List',
+ 'function' => 'doUpdateAll',
+ 'shortcut' => 'uc',
+ 'options' => array(),
+ 'doc' => '
+List all installed packages in all channels.
+'
+ ),
+ 'channel-delete' => array(
+ 'summary' => 'Remove a Channel From the List',
+ 'function' => 'doDelete',
+ 'shortcut' => 'cde',
+ 'options' => array(),
+ 'doc' => '
+Delete a channel from the registry. You may not
+remove any channel that has installed packages.
+'
+ ),
+ 'channel-add' => array(
+ 'summary' => 'Add a Channel',
+ 'function' => 'doAdd',
+ 'shortcut' => 'ca',
+ 'options' => array(),
+ 'doc' => '
+Add a private channel to the channel list. Note that all
+public channels should be synced using "update-channels".
+Parameter may be either a local file or remote URL to a
+channel.xml.
+'
+ ),
+ 'channel-update' => array(
+ 'summary' => 'Update an Existing Channel',
+ 'function' => 'doUpdate',
+ 'shortcut' => 'cu',
+ 'options' => array(
+ 'force' => array(
+ 'shortopt' => 'f',
+ 'doc' => 'will force download of new channel.xml if an existing channel name is used',
+ ),
+ 'channel' => array(
+ 'shortopt' => 'c',
+ 'arg' => 'CHANNEL',
+ 'doc' => 'will force download of new channel.xml if an existing channel name is used',
+ ),
+),
+ 'doc' => '[|]
+Update a channel in the channel list directly. Note that all
+public channels can be synced using "update-channels".
+Parameter may be a local or remote channel.xml, or the name of
+an existing channel.
+'
+ ),
+ 'channel-info' => array(
+ 'summary' => 'Retrieve Information on a Channel',
+ 'function' => 'doInfo',
+ 'shortcut' => 'ci',
+ 'options' => array(),
+ 'doc' => '
+List the files in an installed package.
+'
+ ),
+ 'channel-alias' => array(
+ 'summary' => 'Specify an alias to a channel name',
+ 'function' => 'doAlias',
+ 'shortcut' => 'cha',
+ 'options' => array(),
+ 'doc' => '
+Specify a specific alias to use for a channel name.
+The alias may not be an existing channel name or
+alias.
+'
+ ),
+ 'channel-discover' => array(
+ 'summary' => 'Initialize a Channel from its server',
+ 'function' => 'doDiscover',
+ 'shortcut' => 'di',
+ 'options' => array(),
+ 'doc' => '[|]
+Initialize a channel from its server and create a local channel.xml.
+If is in the format ":@" then
+ and will be set as the login username/password for
+. Use caution when passing the username/password in this way, as
+it may allow other users on your computer to briefly view your username/
+password via the system\'s process list.
+'
+ ),
+ 'channel-login' => array(
+ 'summary' => 'Connects and authenticates to remote channel server',
+ 'shortcut' => 'cli',
+ 'function' => 'doLogin',
+ 'options' => array(),
+ 'doc' => '
+Log in to a remote channel server. If is not supplied,
+the default channel is used. To use remote functions in the installer
+that require any kind of privileges, you need to log in first. The
+username and password you enter here will be stored in your per-user
+PEAR configuration (~/.pearrc on Unix-like systems). After logging
+in, your username and password will be sent along in subsequent
+operations on the remote server.',
+ ),
+ 'channel-logout' => array(
+ 'summary' => 'Logs out from the remote channel server',
+ 'shortcut' => 'clo',
+ 'function' => 'doLogout',
+ 'options' => array(),
+ 'doc' => '
+Logs out from a remote channel server. If is not supplied,
+the default channel is used. This command does not actually connect to the
+remote server, it only deletes the stored username and password from your user
+configuration.',
+ ),
+ );
+
+ /**
+ * PEAR_Command_Registry constructor.
+ *
+ * @access public
+ */
+ function __construct(&$ui, &$config)
+ {
+ parent::__construct($ui, $config);
+ }
+
+ function _sortChannels($a, $b)
+ {
+ return strnatcasecmp($a->getName(), $b->getName());
+ }
+
+ function doList($command, $options, $params)
+ {
+ $reg = &$this->config->getRegistry();
+ $registered = $reg->getChannels();
+ usort($registered, array(&$this, '_sortchannels'));
+ $i = $j = 0;
+ $data = array(
+ 'caption' => 'Registered Channels:',
+ 'border' => true,
+ 'headline' => array('Channel', 'Alias', 'Summary')
+ );
+ foreach ($registered as $channel) {
+ $data['data'][] = array($channel->getName(),
+ $channel->getAlias(),
+ $channel->getSummary());
+ }
+
+ if (count($registered) === 0) {
+ $data = '(no registered channels)';
+ }
+ $this->ui->outputData($data, $command);
+ return true;
+ }
+
+ function doUpdateAll($command, $options, $params)
+ {
+ $reg = &$this->config->getRegistry();
+ $channels = $reg->getChannels();
+
+ $success = true;
+ foreach ($channels as $channel) {
+ if ($channel->getName() != '__uri') {
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $err = $this->doUpdate('channel-update',
+ $options,
+ array($channel->getName()));
+ if (PEAR::isError($err)) {
+ $this->ui->outputData($err->getMessage(), $command);
+ $success = false;
+ } else {
+ $success &= $err;
+ }
+ }
+ }
+ return $success;
+ }
+
+ function doInfo($command, $options, $params)
+ {
+ if (count($params) !== 1) {
+ return $this->raiseError("No channel specified");
+ }
+
+ $reg = &$this->config->getRegistry();
+ $channel = strtolower($params[0]);
+ if ($reg->channelExists($channel)) {
+ $chan = $reg->getChannel($channel);
+ if (PEAR::isError($chan)) {
+ return $this->raiseError($chan);
+ }
+ } else {
+ if (strpos($channel, '://')) {
+ $downloader = &$this->getDownloader();
+ $tmpdir = $this->config->get('temp_dir');
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $loc = $downloader->downloadHttp($channel, $this->ui, $tmpdir);
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($loc)) {
+ return $this->raiseError('Cannot open "' . $channel .
+ '" (' . $loc->getMessage() . ')');
+ } else {
+ $contents = implode('', file($loc));
+ }
+ } else {
+ if (!file_exists($params[0])) {
+ return $this->raiseError('Unknown channel "' . $channel . '"');
+ }
+
+ $fp = fopen($params[0], 'r');
+ if (!$fp) {
+ return $this->raiseError('Cannot open "' . $params[0] . '"');
+ }
+
+ $contents = '';
+ while (!feof($fp)) {
+ $contents .= fread($fp, 1024);
+ }
+ fclose($fp);
+ }
+
+ if (!class_exists('PEAR_ChannelFile')) {
+ require_once 'PEAR/ChannelFile.php';
+ }
+
+ $chan = new PEAR_ChannelFile;
+ $chan->fromXmlString($contents);
+ $chan->validate();
+ if ($errs = $chan->getErrors(true)) {
+ foreach ($errs as $err) {
+ $this->ui->outputData($err['level'] . ': ' . $err['message']);
+ }
+ return $this->raiseError('Channel file "' . $params[0] . '" is not valid');
+ }
+ }
+
+ if (!$chan) {
+ return $this->raiseError('Serious error: Channel "' . $params[0] .
+ '" has a corrupted registry entry');
+ }
+
+ $channel = $chan->getName();
+ $caption = 'Channel ' . $channel . ' Information:';
+ $data1 = array(
+ 'caption' => $caption,
+ 'border' => true);
+ $data1['data']['server'] = array('Name and Server', $chan->getName());
+ if ($chan->getAlias() != $chan->getName()) {
+ $data1['data']['alias'] = array('Alias', $chan->getAlias());
+ }
+
+ $data1['data']['summary'] = array('Summary', $chan->getSummary());
+ $validate = $chan->getValidationPackage();
+ $data1['data']['vpackage'] = array('Validation Package Name', $validate['_content']);
+ $data1['data']['vpackageversion'] =
+ array('Validation Package Version', $validate['attribs']['version']);
+ $d = array();
+ $d['main'] = $data1;
+
+ $data['data'] = array();
+ $data['caption'] = 'Server Capabilities';
+ $data['headline'] = array('Type', 'Version/REST type', 'Function Name/REST base');
+ if ($chan->supportsREST()) {
+ if ($chan->supportsREST()) {
+ $funcs = $chan->getFunctions('rest');
+ if (!isset($funcs[0])) {
+ $funcs = array($funcs);
+ }
+ foreach ($funcs as $protocol) {
+ $data['data'][] = array('rest', $protocol['attribs']['type'],
+ $protocol['_content']);
+ }
+ }
+ } else {
+ $data['data'][] = array('No supported protocols');
+ }
+
+ $d['protocols'] = $data;
+ $data['data'] = array();
+ $mirrors = $chan->getMirrors();
+ if ($mirrors) {
+ $data['caption'] = 'Channel ' . $channel . ' Mirrors:';
+ unset($data['headline']);
+ foreach ($mirrors as $mirror) {
+ $data['data'][] = array($mirror['attribs']['host']);
+ $d['mirrors'] = $data;
+ }
+
+ foreach ($mirrors as $i => $mirror) {
+ $data['data'] = array();
+ $data['caption'] = 'Mirror ' . $mirror['attribs']['host'] . ' Capabilities';
+ $data['headline'] = array('Type', 'Version/REST type', 'Function Name/REST base');
+ if ($chan->supportsREST($mirror['attribs']['host'])) {
+ if ($chan->supportsREST($mirror['attribs']['host'])) {
+ $funcs = $chan->getFunctions('rest', $mirror['attribs']['host']);
+ if (!isset($funcs[0])) {
+ $funcs = array($funcs);
+ }
+
+ foreach ($funcs as $protocol) {
+ $data['data'][] = array('rest', $protocol['attribs']['type'],
+ $protocol['_content']);
+ }
+ }
+ } else {
+ $data['data'][] = array('No supported protocols');
+ }
+ $d['mirrorprotocols' . $i] = $data;
+ }
+ }
+ $this->ui->outputData($d, 'channel-info');
+ }
+
+ // }}}
+
+ function doDelete($command, $options, $params)
+ {
+ if (count($params) !== 1) {
+ return $this->raiseError('channel-delete: no channel specified');
+ }
+
+ $reg = &$this->config->getRegistry();
+ if (!$reg->channelExists($params[0])) {
+ return $this->raiseError('channel-delete: channel "' . $params[0] . '" does not exist');
+ }
+
+ $channel = $reg->channelName($params[0]);
+ if ($channel == 'pear.php.net') {
+ return $this->raiseError('Cannot delete the pear.php.net channel');
+ }
+
+ if ($channel == 'pecl.php.net') {
+ return $this->raiseError('Cannot delete the pecl.php.net channel');
+ }
+
+ if ($channel == 'doc.php.net') {
+ return $this->raiseError('Cannot delete the doc.php.net channel');
+ }
+
+ if ($channel == '__uri') {
+ return $this->raiseError('Cannot delete the __uri pseudo-channel');
+ }
+
+ if (PEAR::isError($err = $reg->listPackages($channel))) {
+ return $err;
+ }
+
+ if (count($err)) {
+ return $this->raiseError('Channel "' . $channel .
+ '" has installed packages, cannot delete');
+ }
+
+ if (!$reg->deleteChannel($channel)) {
+ return $this->raiseError('Channel "' . $channel . '" deletion failed');
+ } else {
+ $this->config->deleteChannel($channel);
+ $this->ui->outputData('Channel "' . $channel . '" deleted', $command);
+ }
+ }
+
+ function doAdd($command, $options, $params)
+ {
+ if (count($params) !== 1) {
+ return $this->raiseError('channel-add: no channel file specified');
+ }
+
+ if (strpos($params[0], '://')) {
+ $downloader = &$this->getDownloader();
+ $tmpdir = $this->config->get('temp_dir');
+ if (!file_exists($tmpdir)) {
+ require_once 'System.php';
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $err = System::mkdir(array('-p', $tmpdir));
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($err)) {
+ return $this->raiseError('channel-add: temp_dir does not exist: "' .
+ $tmpdir .
+ '" - You can change this location with "pear config-set temp_dir"');
+ }
+ }
+
+ if (!is_writable($tmpdir)) {
+ return $this->raiseError('channel-add: temp_dir is not writable: "' .
+ $tmpdir .
+ '" - You can change this location with "pear config-set temp_dir"');
+ }
+
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $loc = $downloader->downloadHttp($params[0], $this->ui, $tmpdir, null, false);
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($loc)) {
+ return $this->raiseError('channel-add: Cannot open "' . $params[0] .
+ '" (' . $loc->getMessage() . ')');
+ }
+
+ list($loc, $lastmodified) = $loc;
+ $contents = implode('', file($loc));
+ } else {
+ $lastmodified = $fp = false;
+ if (file_exists($params[0])) {
+ $fp = fopen($params[0], 'r');
+ }
+
+ if (!$fp) {
+ return $this->raiseError('channel-add: cannot open "' . $params[0] . '"');
+ }
+
+ $contents = '';
+ while (!feof($fp)) {
+ $contents .= fread($fp, 1024);
+ }
+ fclose($fp);
+ }
+
+ if (!class_exists('PEAR_ChannelFile')) {
+ require_once 'PEAR/ChannelFile.php';
+ }
+
+ $channel = new PEAR_ChannelFile;
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $result = $channel->fromXmlString($contents);
+ PEAR::staticPopErrorHandling();
+ if (!$result) {
+ $exit = false;
+ if (count($errors = $channel->getErrors(true))) {
+ foreach ($errors as $error) {
+ $this->ui->outputData(ucfirst($error['level'] . ': ' . $error['message']));
+ if (!$exit) {
+ $exit = $error['level'] == 'error' ? true : false;
+ }
+ }
+ if ($exit) {
+ return $this->raiseError('channel-add: invalid channel.xml file');
+ }
+ }
+ }
+
+ $reg = &$this->config->getRegistry();
+ if ($reg->channelExists($channel->getName())) {
+ return $this->raiseError('channel-add: Channel "' . $channel->getName() .
+ '" exists, use channel-update to update entry', PEAR_COMMAND_CHANNELS_CHANNEL_EXISTS);
+ }
+
+ $ret = $reg->addChannel($channel, $lastmodified);
+ if (PEAR::isError($ret)) {
+ return $ret;
+ }
+
+ if (!$ret) {
+ return $this->raiseError('channel-add: adding Channel "' . $channel->getName() .
+ '" to registry failed');
+ }
+
+ $this->config->setChannels($reg->listChannels());
+ $this->config->writeConfigFile();
+ $this->ui->outputData('Adding Channel "' . $channel->getName() . '" succeeded', $command);
+ }
+
+ function doUpdate($command, $options, $params)
+ {
+ if (count($params) !== 1) {
+ return $this->raiseError("No channel file specified");
+ }
+
+ $tmpdir = $this->config->get('temp_dir');
+ if (!file_exists($tmpdir)) {
+ require_once 'System.php';
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $err = System::mkdir(array('-p', $tmpdir));
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($err)) {
+ return $this->raiseError('channel-add: temp_dir does not exist: "' .
+ $tmpdir .
+ '" - You can change this location with "pear config-set temp_dir"');
+ }
+ }
+
+ if (!is_writable($tmpdir)) {
+ return $this->raiseError('channel-add: temp_dir is not writable: "' .
+ $tmpdir .
+ '" - You can change this location with "pear config-set temp_dir"');
+ }
+
+ $reg = &$this->config->getRegistry();
+ $lastmodified = false;
+ if ((!file_exists($params[0]) || is_dir($params[0]))
+ && $reg->channelExists(strtolower($params[0]))) {
+ $c = $reg->getChannel(strtolower($params[0]));
+ if (PEAR::isError($c)) {
+ return $this->raiseError($c);
+ }
+
+ $this->ui->outputData("Updating channel \"$params[0]\"", $command);
+ $dl = &$this->getDownloader(array());
+ // if force is specified, use a timestamp of "1" to force retrieval
+ $lastmodified = isset($options['force']) ? false : $c->lastModified();
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $contents = $dl->downloadHttp('http://' . $c->getName() . '/channel.xml',
+ $this->ui, $tmpdir, null, $lastmodified);
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($contents)) {
+ // Attempt to fall back to https
+ $this->ui->outputData("Channel \"$params[0]\" is not responding over http://, failed with message: " . $contents->getMessage());
+ $this->ui->outputData("Trying channel \"$params[0]\" over https:// instead");
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $contents = $dl->downloadHttp('https://' . $c->getName() . '/channel.xml',
+ $this->ui, $tmpdir, null, $lastmodified);
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($contents)) {
+ return $this->raiseError('Cannot retrieve channel.xml for channel "' .
+ $c->getName() . '" (' . $contents->getMessage() . ')');
+ }
+ }
+
+ list($contents, $lastmodified) = $contents;
+ if (!$contents) {
+ $this->ui->outputData("Channel \"$params[0]\" is up to date");
+ return;
+ }
+
+ $contents = implode('', file($contents));
+ if (!class_exists('PEAR_ChannelFile')) {
+ require_once 'PEAR/ChannelFile.php';
+ }
+
+ $channel = new PEAR_ChannelFile;
+ $channel->fromXmlString($contents);
+ if (!$channel->getErrors()) {
+ // security check: is the downloaded file for the channel we got it from?
+ if (strtolower($channel->getName()) != strtolower($c->getName())) {
+ if (!isset($options['force'])) {
+ return $this->raiseError('ERROR: downloaded channel definition file' .
+ ' for channel "' . $channel->getName() . '" from channel "' .
+ strtolower($c->getName()) . '"');
+ }
+
+ $this->ui->log(0, 'WARNING: downloaded channel definition file' .
+ ' for channel "' . $channel->getName() . '" from channel "' .
+ strtolower($c->getName()) . '"');
+ }
+ }
+ } else {
+ if (strpos($params[0], '://')) {
+ $dl = &$this->getDownloader();
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $loc = $dl->downloadHttp($params[0],
+ $this->ui, $tmpdir, null, $lastmodified);
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($loc)) {
+ return $this->raiseError("Cannot open " . $params[0] .
+ ' (' . $loc->getMessage() . ')');
+ }
+
+ list($loc, $lastmodified) = $loc;
+ $contents = implode('', file($loc));
+ } else {
+ $fp = false;
+ if (file_exists($params[0])) {
+ $fp = fopen($params[0], 'r');
+ }
+
+ if (!$fp) {
+ return $this->raiseError("Cannot open " . $params[0]);
+ }
+
+ $contents = '';
+ while (!feof($fp)) {
+ $contents .= fread($fp, 1024);
+ }
+ fclose($fp);
+ }
+
+ if (!class_exists('PEAR_ChannelFile')) {
+ require_once 'PEAR/ChannelFile.php';
+ }
+
+ $channel = new PEAR_ChannelFile;
+ $channel->fromXmlString($contents);
+ }
+
+ $exit = false;
+ if (count($errors = $channel->getErrors(true))) {
+ foreach ($errors as $error) {
+ $this->ui->outputData(ucfirst($error['level'] . ': ' . $error['message']));
+ if (!$exit) {
+ $exit = $error['level'] == 'error' ? true : false;
+ }
+ }
+ if ($exit) {
+ return $this->raiseError('Invalid channel.xml file');
+ }
+ }
+
+ if (!$reg->channelExists($channel->getName())) {
+ return $this->raiseError('Error: Channel "' . $channel->getName() .
+ '" does not exist, use channel-add to add an entry');
+ }
+
+ $ret = $reg->updateChannel($channel, $lastmodified);
+ if (PEAR::isError($ret)) {
+ return $ret;
+ }
+
+ if (!$ret) {
+ return $this->raiseError('Updating Channel "' . $channel->getName() .
+ '" in registry failed');
+ }
+
+ $this->config->setChannels($reg->listChannels());
+ $this->config->writeConfigFile();
+ $this->ui->outputData('Update of Channel "' . $channel->getName() . '" succeeded');
+ }
+
+ function &getDownloader()
+ {
+ if (!class_exists('PEAR_Downloader')) {
+ require_once 'PEAR/Downloader.php';
+ }
+ $a = new PEAR_Downloader($this->ui, array(), $this->config);
+ return $a;
+ }
+
+ function doAlias($command, $options, $params)
+ {
+ if (count($params) === 1) {
+ return $this->raiseError('No channel alias specified');
+ }
+
+ if (count($params) !== 2 || (!empty($params[1]) && $params[1]{0} == '-')) {
+ return $this->raiseError(
+ 'Invalid format, correct is: channel-alias channel alias');
+ }
+
+ $reg = &$this->config->getRegistry();
+ if (!$reg->channelExists($params[0], true)) {
+ $extra = '';
+ if ($reg->isAlias($params[0])) {
+ $extra = ' (use "channel-alias ' . $reg->channelName($params[0]) . ' ' .
+ strtolower($params[1]) . '")';
+ }
+
+ return $this->raiseError('"' . $params[0] . '" is not a valid channel' . $extra);
+ }
+
+ if ($reg->isAlias($params[1])) {
+ return $this->raiseError('Channel "' . $reg->channelName($params[1]) . '" is ' .
+ 'already aliased to "' . strtolower($params[1]) . '", cannot re-alias');
+ }
+
+ $chan = $reg->getChannel($params[0]);
+ if (PEAR::isError($chan)) {
+ return $this->raiseError('Corrupt registry? Error retrieving channel "' . $params[0] .
+ '" information (' . $chan->getMessage() . ')');
+ }
+
+ // make it a local alias
+ if (!$chan->setAlias(strtolower($params[1]), true)) {
+ return $this->raiseError('Alias "' . strtolower($params[1]) .
+ '" is not a valid channel alias');
+ }
+
+ $reg->updateChannel($chan);
+ $this->ui->outputData('Channel "' . $chan->getName() . '" aliased successfully to "' .
+ strtolower($params[1]) . '"');
+ }
+
+ /**
+ * The channel-discover command
+ *
+ * @param string $command command name
+ * @param array $options option_name => value
+ * @param array $params list of additional parameters.
+ * $params[0] should contain a string with either:
+ * - or
+ * - :@
+ * @return null|PEAR_Error
+ */
+ function doDiscover($command, $options, $params)
+ {
+ if (count($params) !== 1) {
+ return $this->raiseError("No channel server specified");
+ }
+
+ // Look for the possible input format ":@"
+ if (preg_match('/^(.+):(.+)@(.+)\\z/', $params[0], $matches)) {
+ $username = $matches[1];
+ $password = $matches[2];
+ $channel = $matches[3];
+ } else {
+ $channel = $params[0];
+ }
+
+ $reg = &$this->config->getRegistry();
+ if ($reg->channelExists($channel)) {
+ if (!$reg->isAlias($channel)) {
+ return $this->raiseError("Channel \"$channel\" is already initialized", PEAR_COMMAND_CHANNELS_CHANNEL_EXISTS);
+ }
+
+ return $this->raiseError("A channel alias named \"$channel\" " .
+ 'already exists, aliasing channel "' . $reg->channelName($channel)
+ . '"');
+ }
+
+ $this->pushErrorHandling(PEAR_ERROR_RETURN);
+ $err = $this->doAdd($command, $options, array('http://' . $channel . '/channel.xml'));
+ $this->popErrorHandling();
+ if (PEAR::isError($err)) {
+ if ($err->getCode() === PEAR_COMMAND_CHANNELS_CHANNEL_EXISTS) {
+ return $this->raiseError("Discovery of channel \"$channel\" failed (" .
+ $err->getMessage() . ')');
+ }
+ // Attempt fetch via https
+ $this->ui->outputData("Discovering channel $channel over http:// failed with message: " . $err->getMessage());
+ $this->ui->outputData("Trying to discover channel $channel over https:// instead");
+ $this->pushErrorHandling(PEAR_ERROR_RETURN);
+ $err = $this->doAdd($command, $options, array('https://' . $channel . '/channel.xml'));
+ $this->popErrorHandling();
+ if (PEAR::isError($err)) {
+ return $this->raiseError("Discovery of channel \"$channel\" failed (" .
+ $err->getMessage() . ')');
+ }
+ }
+
+ // Store username/password if they were given
+ // Arguably we should do a logintest on the channel here, but since
+ // that's awkward on a REST-based channel (even "pear login" doesn't
+ // do it for those), and XML-RPC is deprecated, it's fairly pointless.
+ if (isset($username)) {
+ $this->config->set('username', $username, 'user', $channel);
+ $this->config->set('password', $password, 'user', $channel);
+ $this->config->store();
+ $this->ui->outputData("Stored login for channel \"$channel\" using username \"$username\"", $command);
+ }
+
+ $this->ui->outputData("Discovery of channel \"$channel\" succeeded", $command);
+ }
+
+ /**
+ * Execute the 'login' command.
+ *
+ * @param string $command command name
+ * @param array $options option_name => value
+ * @param array $params list of additional parameters
+ *
+ * @return bool TRUE on success or
+ * a PEAR error on failure
+ *
+ * @access public
+ */
+ function doLogin($command, $options, $params)
+ {
+ $reg = &$this->config->getRegistry();
+
+ // If a parameter is supplied, use that as the channel to log in to
+ $channel = isset($params[0]) ? $params[0] : $this->config->get('default_channel');
+
+ $chan = $reg->getChannel($channel);
+ if (PEAR::isError($chan)) {
+ return $this->raiseError($chan);
+ }
+
+ $server = $this->config->get('preferred_mirror', null, $channel);
+ $username = $this->config->get('username', null, $channel);
+ if (empty($username)) {
+ $username = isset($_ENV['USER']) ? $_ENV['USER'] : null;
+ }
+ $this->ui->outputData("Logging in to $server.", $command);
+
+ list($username, $password) = $this->ui->userDialog(
+ $command,
+ array('Username', 'Password'),
+ array('text', 'password'),
+ array($username, '')
+ );
+ $username = trim($username);
+ $password = trim($password);
+
+ $ourfile = $this->config->getConfFile('user');
+ if (!$ourfile) {
+ $ourfile = $this->config->getConfFile('system');
+ }
+
+ $this->config->set('username', $username, 'user', $channel);
+ $this->config->set('password', $password, 'user', $channel);
+
+ if ($chan->supportsREST()) {
+ $ok = true;
+ }
+
+ if ($ok !== true) {
+ return $this->raiseError('Login failed!');
+ }
+
+ $this->ui->outputData("Logged in.", $command);
+ // avoid changing any temporary settings changed with -d
+ $ourconfig = new PEAR_Config($ourfile, $ourfile);
+ $ourconfig->set('username', $username, 'user', $channel);
+ $ourconfig->set('password', $password, 'user', $channel);
+ $ourconfig->store();
+
+ return true;
+ }
+
+ /**
+ * Execute the 'logout' command.
+ *
+ * @param string $command command name
+ * @param array $options option_name => value
+ * @param array $params list of additional parameters
+ *
+ * @return bool TRUE on success or
+ * a PEAR error on failure
+ *
+ * @access public
+ */
+ function doLogout($command, $options, $params)
+ {
+ $reg = &$this->config->getRegistry();
+
+ // If a parameter is supplied, use that as the channel to log in to
+ $channel = isset($params[0]) ? $params[0] : $this->config->get('default_channel');
+
+ $chan = $reg->getChannel($channel);
+ if (PEAR::isError($chan)) {
+ return $this->raiseError($chan);
+ }
+
+ $server = $this->config->get('preferred_mirror', null, $channel);
+ $this->ui->outputData("Logging out from $server.", $command);
+ $this->config->remove('username', 'user', $channel);
+ $this->config->remove('password', 'user', $channel);
+ $this->config->store();
+ return true;
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Command/Channels.xml b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Channels.xml
new file mode 100644
index 000000000..47b72066a
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Channels.xml
@@ -0,0 +1,123 @@
+
+
+ List Available Channels
+ doList
+ lc
+
+
+List all available channels for installation.
+
+
+
+ Update the Channel List
+ doUpdateAll
+ uc
+
+
+List all installed packages in all channels.
+
+
+
+ Remove a Channel From the List
+ doDelete
+ cde
+
+ <channel name>
+Delete a channel from the registry. You may not
+remove any channel that has installed packages.
+
+
+
+ Add a Channel
+ doAdd
+ ca
+
+ <channel.xml>
+Add a private channel to the channel list. Note that all
+public channels should be synced using "update-channels".
+Parameter may be either a local file or remote URL to a
+channel.xml.
+
+
+
+ Update an Existing Channel
+ doUpdate
+ cu
+
+
+ f
+ will force download of new channel.xml if an existing channel name is used
+
+
+ c
+ will force download of new channel.xml if an existing channel name is used
+ CHANNEL
+
+
+ [<channel.xml>|<channel name>]
+Update a channel in the channel list directly. Note that all
+public channels can be synced using "update-channels".
+Parameter may be a local or remote channel.xml, or the name of
+an existing channel.
+
+
+
+ Retrieve Information on a Channel
+ doInfo
+ ci
+
+ <package>
+List the files in an installed package.
+
+
+
+ Specify an alias to a channel name
+ doAlias
+ cha
+
+ <channel> <alias>
+Specify a specific alias to use for a channel name.
+The alias may not be an existing channel name or
+alias.
+
+
+
+ Initialize a Channel from its server
+ doDiscover
+ di
+
+ [<channel.xml>|<channel name>]
+Initialize a channel from its server and create a local channel.xml.
+If <channel name> is in the format "<username>:<password>@<channel>" then
+<username> and <password> will be set as the login username/password for
+<channel>. Use caution when passing the username/password in this way, as
+it may allow other users on your computer to briefly view your username/
+password via the system's process list.
+
+
+
+ Connects and authenticates to remote channel server
+ doLogin
+ cli
+
+ <channel name>
+Log in to a remote channel server. If <channel name> is not supplied,
+the default channel is used. To use remote functions in the installer
+that require any kind of privileges, you need to log in first. The
+username and password you enter here will be stored in your per-user
+PEAR configuration (~/.pearrc on Unix-like systems). After logging
+in, your username and password will be sent along in subsequent
+operations on the remote server.
+
+
+ Logs out from the remote channel server
+ doLogout
+ clo
+
+ <channel name>
+Logs out from a remote channel server. If <channel name> is not supplied,
+the default channel is used. This command does not actually connect to the
+remote server, it only deletes the stored username and password from your user
+configuration.
+
+
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Command/Common.php b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Common.php
new file mode 100644
index 000000000..41384ef0b
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Common.php
@@ -0,0 +1,272 @@
+
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ */
+
+/**
+ * base class
+ */
+require_once 'PEAR.php';
+
+/**
+ * PEAR commands base class
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 0.1
+ */
+class PEAR_Command_Common extends PEAR
+{
+ /**
+ * PEAR_Config object used to pass user system and configuration
+ * on when executing commands
+ *
+ * @var PEAR_Config
+ */
+ var $config;
+ /**
+ * @var PEAR_Registry
+ * @access protected
+ */
+ var $_registry;
+
+ /**
+ * User Interface object, for all interaction with the user.
+ * @var object
+ */
+ var $ui;
+
+ var $_deps_rel_trans = array(
+ 'lt' => '<',
+ 'le' => '<=',
+ 'eq' => '=',
+ 'ne' => '!=',
+ 'gt' => '>',
+ 'ge' => '>=',
+ 'has' => '=='
+ );
+
+ var $_deps_type_trans = array(
+ 'pkg' => 'package',
+ 'ext' => 'extension',
+ 'php' => 'PHP',
+ 'prog' => 'external program',
+ 'ldlib' => 'external library for linking',
+ 'rtlib' => 'external runtime library',
+ 'os' => 'operating system',
+ 'websrv' => 'web server',
+ 'sapi' => 'SAPI backend'
+ );
+
+ /**
+ * PEAR_Command_Common constructor.
+ *
+ * @access public
+ */
+ function __construct(&$ui, &$config)
+ {
+ parent::__construct();
+ $this->config = &$config;
+ $this->ui = &$ui;
+ }
+
+ /**
+ * Return a list of all the commands defined by this class.
+ * @return array list of commands
+ * @access public
+ */
+ function getCommands()
+ {
+ $ret = array();
+ foreach (array_keys($this->commands) as $command) {
+ $ret[$command] = $this->commands[$command]['summary'];
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Return a list of all the command shortcuts defined by this class.
+ * @return array shortcut => command
+ * @access public
+ */
+ function getShortcuts()
+ {
+ $ret = array();
+ foreach (array_keys($this->commands) as $command) {
+ if (isset($this->commands[$command]['shortcut'])) {
+ $ret[$this->commands[$command]['shortcut']] = $command;
+ }
+ }
+
+ return $ret;
+ }
+
+ function getOptions($command)
+ {
+ $shortcuts = $this->getShortcuts();
+ if (isset($shortcuts[$command])) {
+ $command = $shortcuts[$command];
+ }
+
+ if (isset($this->commands[$command]) &&
+ isset($this->commands[$command]['options'])) {
+ return $this->commands[$command]['options'];
+ }
+
+ return null;
+ }
+
+ function getGetoptArgs($command, &$short_args, &$long_args)
+ {
+ $short_args = '';
+ $long_args = array();
+ if (empty($this->commands[$command]) || empty($this->commands[$command]['options'])) {
+ return;
+ }
+
+ reset($this->commands[$command]['options']);
+ while (list($option, $info) = each($this->commands[$command]['options'])) {
+ $larg = $sarg = '';
+ if (isset($info['arg'])) {
+ if ($info['arg']{0} == '(') {
+ $larg = '==';
+ $sarg = '::';
+ $arg = substr($info['arg'], 1, -1);
+ } else {
+ $larg = '=';
+ $sarg = ':';
+ $arg = $info['arg'];
+ }
+ }
+
+ if (isset($info['shortopt'])) {
+ $short_args .= $info['shortopt'] . $sarg;
+ }
+
+ $long_args[] = $option . $larg;
+ }
+ }
+
+ /**
+ * Returns the help message for the given command
+ *
+ * @param string $command The command
+ * @return mixed A fail string if the command does not have help or
+ * a two elements array containing [0]=>help string,
+ * [1]=> help string for the accepted cmd args
+ */
+ function getHelp($command)
+ {
+ $config = &PEAR_Config::singleton();
+ if (!isset($this->commands[$command])) {
+ return "No such command \"$command\"";
+ }
+
+ $help = null;
+ if (isset($this->commands[$command]['doc'])) {
+ $help = $this->commands[$command]['doc'];
+ }
+
+ if (empty($help)) {
+ // XXX (cox) Fallback to summary if there is no doc (show both?)
+ if (!isset($this->commands[$command]['summary'])) {
+ return "No help for command \"$command\"";
+ }
+ $help = $this->commands[$command]['summary'];
+ }
+
+ if (preg_match_all('/{config\s+([^\}]+)}/e', $help, $matches)) {
+ foreach($matches[0] as $k => $v) {
+ $help = preg_replace("/$v/", $config->get($matches[1][$k]), $help);
+ }
+ }
+
+ return array($help, $this->getHelpArgs($command));
+ }
+
+ /**
+ * Returns the help for the accepted arguments of a command
+ *
+ * @param string $command
+ * @return string The help string
+ */
+ function getHelpArgs($command)
+ {
+ if (isset($this->commands[$command]['options']) &&
+ count($this->commands[$command]['options']))
+ {
+ $help = "Options:\n";
+ foreach ($this->commands[$command]['options'] as $k => $v) {
+ if (isset($v['arg'])) {
+ if ($v['arg'][0] == '(') {
+ $arg = substr($v['arg'], 1, -1);
+ $sapp = " [$arg]";
+ $lapp = "[=$arg]";
+ } else {
+ $sapp = " $v[arg]";
+ $lapp = "=$v[arg]";
+ }
+ } else {
+ $sapp = $lapp = "";
+ }
+
+ if (isset($v['shortopt'])) {
+ $s = $v['shortopt'];
+ $help .= " -$s$sapp, --$k$lapp\n";
+ } else {
+ $help .= " --$k$lapp\n";
+ }
+
+ $p = " ";
+ $doc = rtrim(str_replace("\n", "\n$p", $v['doc']));
+ $help .= " $doc\n";
+ }
+
+ return $help;
+ }
+
+ return null;
+ }
+
+ function run($command, $options, $params)
+ {
+ if (empty($this->commands[$command]['function'])) {
+ // look for shortcuts
+ foreach (array_keys($this->commands) as $cmd) {
+ if (isset($this->commands[$cmd]['shortcut']) && $this->commands[$cmd]['shortcut'] == $command) {
+ if (empty($this->commands[$cmd]['function'])) {
+ return $this->raiseError("unknown command `$command'");
+ } else {
+ $func = $this->commands[$cmd]['function'];
+ }
+ $command = $cmd;
+
+ //$command = $this->commands[$cmd]['function'];
+ break;
+ }
+ }
+ } else {
+ $func = $this->commands[$command]['function'];
+ }
+
+ return $this->$func($command, $options, $params);
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Command/Config.php b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Config.php
new file mode 100644
index 000000000..63efb07be
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Config.php
@@ -0,0 +1,414 @@
+
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ */
+
+/**
+ * base class
+ */
+require_once 'PEAR/Command/Common.php';
+
+/**
+ * PEAR commands for managing configuration data.
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 0.1
+ */
+class PEAR_Command_Config extends PEAR_Command_Common
+{
+ var $commands = array(
+ 'config-show' => array(
+ 'summary' => 'Show All Settings',
+ 'function' => 'doConfigShow',
+ 'shortcut' => 'csh',
+ 'options' => array(
+ 'channel' => array(
+ 'shortopt' => 'c',
+ 'doc' => 'show configuration variables for another channel',
+ 'arg' => 'CHAN',
+ ),
+),
+ 'doc' => '[layer]
+Displays all configuration values. An optional argument
+may be used to tell which configuration layer to display. Valid
+configuration layers are "user", "system" and "default". To display
+configurations for different channels, set the default_channel
+configuration variable and run config-show again.
+',
+ ),
+ 'config-get' => array(
+ 'summary' => 'Show One Setting',
+ 'function' => 'doConfigGet',
+ 'shortcut' => 'cg',
+ 'options' => array(
+ 'channel' => array(
+ 'shortopt' => 'c',
+ 'doc' => 'show configuration variables for another channel',
+ 'arg' => 'CHAN',
+ ),
+),
+ 'doc' => ' [layer]
+Displays the value of one configuration parameter. The
+first argument is the name of the parameter, an optional second argument
+may be used to tell which configuration layer to look in. Valid configuration
+layers are "user", "system" and "default". If no layer is specified, a value
+will be picked from the first layer that defines the parameter, in the order
+just specified. The configuration value will be retrieved for the channel
+specified by the default_channel configuration variable.
+',
+ ),
+ 'config-set' => array(
+ 'summary' => 'Change Setting',
+ 'function' => 'doConfigSet',
+ 'shortcut' => 'cs',
+ 'options' => array(
+ 'channel' => array(
+ 'shortopt' => 'c',
+ 'doc' => 'show configuration variables for another channel',
+ 'arg' => 'CHAN',
+ ),
+),
+ 'doc' => ' [layer]
+Sets the value of one configuration parameter. The first argument is
+the name of the parameter, the second argument is the new value. Some
+parameters are subject to validation, and the command will fail with
+an error message if the new value does not make sense. An optional
+third argument may be used to specify in which layer to set the
+configuration parameter. The default layer is "user". The
+configuration value will be set for the current channel, which
+is controlled by the default_channel configuration variable.
+',
+ ),
+ 'config-help' => array(
+ 'summary' => 'Show Information About Setting',
+ 'function' => 'doConfigHelp',
+ 'shortcut' => 'ch',
+ 'options' => array(),
+ 'doc' => '[parameter]
+Displays help for a configuration parameter. Without arguments it
+displays help for all configuration parameters.
+',
+ ),
+ 'config-create' => array(
+ 'summary' => 'Create a Default configuration file',
+ 'function' => 'doConfigCreate',
+ 'shortcut' => 'coc',
+ 'options' => array(
+ 'windows' => array(
+ 'shortopt' => 'w',
+ 'doc' => 'create a config file for a windows install',
+ ),
+ ),
+ 'doc' => '
+Create a default configuration file with all directory configuration
+variables set to subdirectories of , and save it as .
+This is useful especially for creating a configuration file for a remote
+PEAR installation (using the --remoteconfig option of install, upgrade,
+and uninstall).
+',
+ ),
+ );
+
+ /**
+ * PEAR_Command_Config constructor.
+ *
+ * @access public
+ */
+ function __construct(&$ui, &$config)
+ {
+ parent::__construct($ui, $config);
+ }
+
+ function doConfigShow($command, $options, $params)
+ {
+ $layer = null;
+ if (is_array($params)) {
+ $layer = isset($params[0]) ? $params[0] : null;
+ }
+
+ // $params[0] -> the layer
+ if ($error = $this->_checkLayer($layer)) {
+ return $this->raiseError("config-show:$error");
+ }
+
+ $keys = $this->config->getKeys();
+ sort($keys);
+ $channel = isset($options['channel']) ? $options['channel'] :
+ $this->config->get('default_channel');
+ $reg = &$this->config->getRegistry();
+ if (!$reg->channelExists($channel)) {
+ return $this->raiseError('Channel "' . $channel . '" does not exist');
+ }
+
+ $channel = $reg->channelName($channel);
+ $data = array('caption' => 'Configuration (channel ' . $channel . '):');
+ foreach ($keys as $key) {
+ $type = $this->config->getType($key);
+ $value = $this->config->get($key, $layer, $channel);
+ if ($type == 'password' && $value) {
+ $value = '********';
+ }
+
+ if ($value === false) {
+ $value = 'false';
+ } elseif ($value === true) {
+ $value = 'true';
+ }
+
+ $data['data'][$this->config->getGroup($key)][] = array($this->config->getPrompt($key) , $key, $value);
+ }
+
+ foreach ($this->config->getLayers() as $layer) {
+ $data['data']['Config Files'][] = array(ucfirst($layer) . ' Configuration File', 'Filename' , $this->config->getConfFile($layer));
+ }
+
+ $this->ui->outputData($data, $command);
+ return true;
+ }
+
+ function doConfigGet($command, $options, $params)
+ {
+ $args_cnt = is_array($params) ? count($params) : 0;
+ switch ($args_cnt) {
+ case 1:
+ $config_key = $params[0];
+ $layer = null;
+ break;
+ case 2:
+ $config_key = $params[0];
+ $layer = $params[1];
+ if ($error = $this->_checkLayer($layer)) {
+ return $this->raiseError("config-get:$error");
+ }
+ break;
+ case 0:
+ default:
+ return $this->raiseError("config-get expects 1 or 2 parameters");
+ }
+
+ $reg = &$this->config->getRegistry();
+ $channel = isset($options['channel']) ? $options['channel'] : $this->config->get('default_channel');
+ if (!$reg->channelExists($channel)) {
+ return $this->raiseError('Channel "' . $channel . '" does not exist');
+ }
+
+ $channel = $reg->channelName($channel);
+ $this->ui->outputData($this->config->get($config_key, $layer, $channel), $command);
+ return true;
+ }
+
+ function doConfigSet($command, $options, $params)
+ {
+ // $param[0] -> a parameter to set
+ // $param[1] -> the value for the parameter
+ // $param[2] -> the layer
+ $failmsg = '';
+ if (count($params) < 2 || count($params) > 3) {
+ $failmsg .= "config-set expects 2 or 3 parameters";
+ return PEAR::raiseError($failmsg);
+ }
+
+ if (isset($params[2]) && ($error = $this->_checkLayer($params[2]))) {
+ $failmsg .= $error;
+ return PEAR::raiseError("config-set:$failmsg");
+ }
+
+ $channel = isset($options['channel']) ? $options['channel'] : $this->config->get('default_channel');
+ $reg = &$this->config->getRegistry();
+ if (!$reg->channelExists($channel)) {
+ return $this->raiseError('Channel "' . $channel . '" does not exist');
+ }
+
+ $channel = $reg->channelName($channel);
+ if ($params[0] == 'default_channel' && !$reg->channelExists($params[1])) {
+ return $this->raiseError('Channel "' . $params[1] . '" does not exist');
+ }
+
+ if ($params[0] == 'preferred_mirror'
+ && (
+ !$reg->mirrorExists($channel, $params[1]) &&
+ (!$reg->channelExists($params[1]) || $channel != $params[1])
+ )
+ ) {
+ $msg = 'Channel Mirror "' . $params[1] . '" does not exist';
+ $msg .= ' in your registry for channel "' . $channel . '".';
+ $msg .= "\n" . 'Attempt to run "pear channel-update ' . $channel .'"';
+ $msg .= ' if you believe this mirror should exist as you may';
+ $msg .= ' have outdated channel information.';
+ return $this->raiseError($msg);
+ }
+
+ if (count($params) == 2) {
+ array_push($params, 'user');
+ $layer = 'user';
+ } else {
+ $layer = $params[2];
+ }
+
+ array_push($params, $channel);
+ if (!call_user_func_array(array(&$this->config, 'set'), $params)) {
+ array_pop($params);
+ $failmsg = "config-set (" . implode(", ", $params) . ") failed, channel $channel";
+ } else {
+ $this->config->store($layer);
+ }
+
+ if ($failmsg) {
+ return $this->raiseError($failmsg);
+ }
+
+ $this->ui->outputData('config-set succeeded', $command);
+ return true;
+ }
+
+ function doConfigHelp($command, $options, $params)
+ {
+ if (empty($params)) {
+ $params = $this->config->getKeys();
+ }
+
+ $data['caption'] = "Config help" . ((count($params) == 1) ? " for $params[0]" : '');
+ $data['headline'] = array('Name', 'Type', 'Description');
+ $data['border'] = true;
+ foreach ($params as $name) {
+ $type = $this->config->getType($name);
+ $docs = $this->config->getDocs($name);
+ if ($type == 'set') {
+ $docs = rtrim($docs) . "\nValid set: " .
+ implode(' ', $this->config->getSetValues($name));
+ }
+
+ $data['data'][] = array($name, $type, $docs);
+ }
+
+ $this->ui->outputData($data, $command);
+ }
+
+ function doConfigCreate($command, $options, $params)
+ {
+ if (count($params) != 2) {
+ return PEAR::raiseError('config-create: must have 2 parameters, root path and ' .
+ 'filename to save as');
+ }
+
+ $root = $params[0];
+ // Clean up the DIRECTORY_SEPARATOR mess
+ $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR;
+ $root = preg_replace(array('!\\\\+!', '!/+!', "!$ds2+!"),
+ array('/', '/', '/'),
+ $root);
+ if ($root{0} != '/') {
+ if (!isset($options['windows'])) {
+ return PEAR::raiseError('Root directory must be an absolute path beginning ' .
+ 'with "/", was: "' . $root . '"');
+ }
+
+ if (!preg_match('/^[A-Za-z]:/', $root)) {
+ return PEAR::raiseError('Root directory must be an absolute path beginning ' .
+ 'with "\\" or "C:\\", was: "' . $root . '"');
+ }
+ }
+
+ $windows = isset($options['windows']);
+ if ($windows) {
+ $root = str_replace('/', '\\', $root);
+ }
+
+ if (!file_exists($params[1]) && !@touch($params[1])) {
+ return PEAR::raiseError('Could not create "' . $params[1] . '"');
+ }
+
+ $params[1] = realpath($params[1]);
+ $config = new PEAR_Config($params[1], '#no#system#config#', false, false);
+ if ($root{strlen($root) - 1} == '/') {
+ $root = substr($root, 0, strlen($root) - 1);
+ }
+
+ $config->noRegistry();
+ $config->set('php_dir', $windows ? "$root\\pear\\php" : "$root/pear/php", 'user');
+ $config->set('data_dir', $windows ? "$root\\pear\\data" : "$root/pear/data");
+ $config->set('www_dir', $windows ? "$root\\pear\\www" : "$root/pear/www");
+ $config->set('cfg_dir', $windows ? "$root\\pear\\cfg" : "$root/pear/cfg");
+ $config->set('ext_dir', $windows ? "$root\\pear\\ext" : "$root/pear/ext");
+ $config->set('doc_dir', $windows ? "$root\\pear\\docs" : "$root/pear/docs");
+ $config->set('test_dir', $windows ? "$root\\pear\\tests" : "$root/pear/tests");
+ $config->set('cache_dir', $windows ? "$root\\pear\\cache" : "$root/pear/cache");
+ $config->set('download_dir', $windows ? "$root\\pear\\download" : "$root/pear/download");
+ $config->set('temp_dir', $windows ? "$root\\pear\\temp" : "$root/pear/temp");
+ $config->set('bin_dir', $windows ? "$root\\pear" : "$root/pear");
+ $config->set('man_dir', $windows ? "$root\\pear\\man" : "$root/pear/man");
+ $config->writeConfigFile();
+ $this->_showConfig($config);
+ $this->ui->outputData('Successfully created default configuration file "' . $params[1] . '"',
+ $command);
+ }
+
+ function _showConfig(&$config)
+ {
+ $params = array('user');
+ $keys = $config->getKeys();
+ sort($keys);
+ $channel = 'pear.php.net';
+ $data = array('caption' => 'Configuration (channel ' . $channel . '):');
+ foreach ($keys as $key) {
+ $type = $config->getType($key);
+ $value = $config->get($key, 'user', $channel);
+ if ($type == 'password' && $value) {
+ $value = '********';
+ }
+
+ if ($value === false) {
+ $value = 'false';
+ } elseif ($value === true) {
+ $value = 'true';
+ }
+ $data['data'][$config->getGroup($key)][] =
+ array($config->getPrompt($key) , $key, $value);
+ }
+
+ foreach ($config->getLayers() as $layer) {
+ $data['data']['Config Files'][] =
+ array(ucfirst($layer) . ' Configuration File', 'Filename' ,
+ $config->getConfFile($layer));
+ }
+
+ $this->ui->outputData($data, 'config-show');
+ return true;
+ }
+
+ /**
+ * Checks if a layer is defined or not
+ *
+ * @param string $layer The layer to search for
+ * @return mixed False on no error or the error message
+ */
+ function _checkLayer($layer = null)
+ {
+ if (!empty($layer) && $layer != 'default') {
+ $layers = $this->config->getLayers();
+ if (!in_array($layer, $layers)) {
+ return " only the layers: \"" . implode('" or "', $layers) . "\" are supported";
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Command/Config.xml b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Config.xml
new file mode 100644
index 000000000..f64a925f5
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Config.xml
@@ -0,0 +1,92 @@
+
+
+ Show All Settings
+ doConfigShow
+ csh
+
+
+ c
+ show configuration variables for another channel
+ CHAN
+
+
+ [layer]
+Displays all configuration values. An optional argument
+may be used to tell which configuration layer to display. Valid
+configuration layers are "user", "system" and "default". To display
+configurations for different channels, set the default_channel
+configuration variable and run config-show again.
+
+
+
+ Show One Setting
+ doConfigGet
+ cg
+
+
+ c
+ show configuration variables for another channel
+ CHAN
+
+
+ <parameter> [layer]
+Displays the value of one configuration parameter. The
+first argument is the name of the parameter, an optional second argument
+may be used to tell which configuration layer to look in. Valid configuration
+layers are "user", "system" and "default". If no layer is specified, a value
+will be picked from the first layer that defines the parameter, in the order
+just specified. The configuration value will be retrieved for the channel
+specified by the default_channel configuration variable.
+
+
+
+ Change Setting
+ doConfigSet
+ cs
+
+
+ c
+ show configuration variables for another channel
+ CHAN
+
+
+ <parameter> <value> [layer]
+Sets the value of one configuration parameter. The first argument is
+the name of the parameter, the second argument is the new value. Some
+parameters are subject to validation, and the command will fail with
+an error message if the new value does not make sense. An optional
+third argument may be used to specify in which layer to set the
+configuration parameter. The default layer is "user". The
+configuration value will be set for the current channel, which
+is controlled by the default_channel configuration variable.
+
+
+
+ Show Information About Setting
+ doConfigHelp
+ ch
+
+ [parameter]
+Displays help for a configuration parameter. Without arguments it
+displays help for all configuration parameters.
+
+
+
+ Create a Default configuration file
+ doConfigCreate
+ coc
+
+
+ w
+ create a config file for a windows install
+
+
+ <root path> <filename>
+Create a default configuration file with all directory configuration
+variables set to subdirectories of <root path>, and save it as <filename>.
+This is useful especially for creating a configuration file for a remote
+PEAR installation (using the --remoteconfig option of install, upgrade,
+and uninstall).
+
+
+
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Command/Install.php b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Install.php
new file mode 100644
index 000000000..a1d3a7023
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Install.php
@@ -0,0 +1,1269 @@
+
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ */
+
+/**
+ * base class
+ */
+require_once 'PEAR/Command/Common.php';
+
+/**
+ * PEAR commands for installation or deinstallation/upgrading of
+ * packages.
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 0.1
+ */
+class PEAR_Command_Install extends PEAR_Command_Common
+{
+ // {{{ properties
+
+ var $commands = array(
+ 'install' => array(
+ 'summary' => 'Install Package',
+ 'function' => 'doInstall',
+ 'shortcut' => 'i',
+ 'options' => array(
+ 'force' => array(
+ 'shortopt' => 'f',
+ 'doc' => 'will overwrite newer installed packages',
+ ),
+ 'loose' => array(
+ 'shortopt' => 'l',
+ 'doc' => 'do not check for recommended dependency version',
+ ),
+ 'nodeps' => array(
+ 'shortopt' => 'n',
+ 'doc' => 'ignore dependencies, install anyway',
+ ),
+ 'register-only' => array(
+ 'shortopt' => 'r',
+ 'doc' => 'do not install files, only register the package as installed',
+ ),
+ 'soft' => array(
+ 'shortopt' => 's',
+ 'doc' => 'soft install, fail silently, or upgrade if already installed',
+ ),
+ 'nobuild' => array(
+ 'shortopt' => 'B',
+ 'doc' => 'don\'t build C extensions',
+ ),
+ 'nocompress' => array(
+ 'shortopt' => 'Z',
+ 'doc' => 'request uncompressed files when downloading',
+ ),
+ 'installroot' => array(
+ 'shortopt' => 'R',
+ 'arg' => 'DIR',
+ 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM',
+ ),
+ 'packagingroot' => array(
+ 'shortopt' => 'P',
+ 'arg' => 'DIR',
+ 'doc' => 'root directory used when packaging files, like RPM packaging',
+ ),
+ 'ignore-errors' => array(
+ 'doc' => 'force install even if there were errors',
+ ),
+ 'alldeps' => array(
+ 'shortopt' => 'a',
+ 'doc' => 'install all required and optional dependencies',
+ ),
+ 'onlyreqdeps' => array(
+ 'shortopt' => 'o',
+ 'doc' => 'install all required dependencies',
+ ),
+ 'offline' => array(
+ 'shortopt' => 'O',
+ 'doc' => 'do not attempt to download any urls or contact channels',
+ ),
+ 'pretend' => array(
+ 'shortopt' => 'p',
+ 'doc' => 'Only list the packages that would be downloaded',
+ ),
+ ),
+ 'doc' => '[channel/] ...
+Installs one or more PEAR packages. You can specify a package to
+install in four ways:
+
+"Package-1.0.tgz" : installs from a local file
+
+"http://example.com/Package-1.0.tgz" : installs from
+anywhere on the net.
+
+"package.xml" : installs the package described in
+package.xml. Useful for testing, or for wrapping a PEAR package in
+another package manager such as RPM.
+
+"Package[-version/state][.tar]" : queries your default channel\'s server
+({config master_server}) and downloads the newest package with
+the preferred quality/state ({config preferred_state}).
+
+To retrieve Package version 1.1, use "Package-1.1," to retrieve
+Package state beta, use "Package-beta." To retrieve an uncompressed
+file, append .tar (make sure there is no file by the same name first)
+
+To download a package from another channel, prefix with the channel name like
+"channel/Package"
+
+More than one package may be specified at once. It is ok to mix these
+four ways of specifying packages.
+'),
+ 'upgrade' => array(
+ 'summary' => 'Upgrade Package',
+ 'function' => 'doInstall',
+ 'shortcut' => 'up',
+ 'options' => array(
+ 'channel' => array(
+ 'shortopt' => 'c',
+ 'doc' => 'upgrade packages from a specific channel',
+ 'arg' => 'CHAN',
+ ),
+ 'force' => array(
+ 'shortopt' => 'f',
+ 'doc' => 'overwrite newer installed packages',
+ ),
+ 'loose' => array(
+ 'shortopt' => 'l',
+ 'doc' => 'do not check for recommended dependency version',
+ ),
+ 'nodeps' => array(
+ 'shortopt' => 'n',
+ 'doc' => 'ignore dependencies, upgrade anyway',
+ ),
+ 'register-only' => array(
+ 'shortopt' => 'r',
+ 'doc' => 'do not install files, only register the package as upgraded',
+ ),
+ 'nobuild' => array(
+ 'shortopt' => 'B',
+ 'doc' => 'don\'t build C extensions',
+ ),
+ 'nocompress' => array(
+ 'shortopt' => 'Z',
+ 'doc' => 'request uncompressed files when downloading',
+ ),
+ 'installroot' => array(
+ 'shortopt' => 'R',
+ 'arg' => 'DIR',
+ 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
+ ),
+ 'ignore-errors' => array(
+ 'doc' => 'force install even if there were errors',
+ ),
+ 'alldeps' => array(
+ 'shortopt' => 'a',
+ 'doc' => 'install all required and optional dependencies',
+ ),
+ 'onlyreqdeps' => array(
+ 'shortopt' => 'o',
+ 'doc' => 'install all required dependencies',
+ ),
+ 'offline' => array(
+ 'shortopt' => 'O',
+ 'doc' => 'do not attempt to download any urls or contact channels',
+ ),
+ 'pretend' => array(
+ 'shortopt' => 'p',
+ 'doc' => 'Only list the packages that would be downloaded',
+ ),
+ ),
+ 'doc' => ' ...
+Upgrades one or more PEAR packages. See documentation for the
+"install" command for ways to specify a package.
+
+When upgrading, your package will be updated if the provided new
+package has a higher version number (use the -f option if you need to
+upgrade anyway).
+
+More than one package may be specified at once.
+'),
+ 'upgrade-all' => array(
+ 'summary' => 'Upgrade All Packages [Deprecated in favor of calling upgrade with no parameters]',
+ 'function' => 'doUpgradeAll',
+ 'shortcut' => 'ua',
+ 'options' => array(
+ 'channel' => array(
+ 'shortopt' => 'c',
+ 'doc' => 'upgrade packages from a specific channel',
+ 'arg' => 'CHAN',
+ ),
+ 'nodeps' => array(
+ 'shortopt' => 'n',
+ 'doc' => 'ignore dependencies, upgrade anyway',
+ ),
+ 'register-only' => array(
+ 'shortopt' => 'r',
+ 'doc' => 'do not install files, only register the package as upgraded',
+ ),
+ 'nobuild' => array(
+ 'shortopt' => 'B',
+ 'doc' => 'don\'t build C extensions',
+ ),
+ 'nocompress' => array(
+ 'shortopt' => 'Z',
+ 'doc' => 'request uncompressed files when downloading',
+ ),
+ 'installroot' => array(
+ 'shortopt' => 'R',
+ 'arg' => 'DIR',
+ 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM',
+ ),
+ 'ignore-errors' => array(
+ 'doc' => 'force install even if there were errors',
+ ),
+ 'loose' => array(
+ 'doc' => 'do not check for recommended dependency version',
+ ),
+ ),
+ 'doc' => '
+WARNING: This function is deprecated in favor of using the upgrade command with no params
+
+Upgrades all packages that have a newer release available. Upgrades are
+done only if there is a release available of the state specified in
+"preferred_state" (currently {config preferred_state}), or a state considered
+more stable.
+'),
+ 'uninstall' => array(
+ 'summary' => 'Un-install Package',
+ 'function' => 'doUninstall',
+ 'shortcut' => 'un',
+ 'options' => array(
+ 'nodeps' => array(
+ 'shortopt' => 'n',
+ 'doc' => 'ignore dependencies, uninstall anyway',
+ ),
+ 'register-only' => array(
+ 'shortopt' => 'r',
+ 'doc' => 'do not remove files, only register the packages as not installed',
+ ),
+ 'installroot' => array(
+ 'shortopt' => 'R',
+ 'arg' => 'DIR',
+ 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
+ ),
+ 'ignore-errors' => array(
+ 'doc' => 'force install even if there were errors',
+ ),
+ 'offline' => array(
+ 'shortopt' => 'O',
+ 'doc' => 'do not attempt to uninstall remotely',
+ ),
+ ),
+ 'doc' => '[channel/] ...
+Uninstalls one or more PEAR packages. More than one package may be
+specified at once. Prefix with channel name to uninstall from a
+channel not in your default channel ({config default_channel})
+'),
+ 'bundle' => array(
+ 'summary' => 'Unpacks a Pecl Package',
+ 'function' => 'doBundle',
+ 'shortcut' => 'bun',
+ 'options' => array(
+ 'destination' => array(
+ 'shortopt' => 'd',
+ 'arg' => 'DIR',
+ 'doc' => 'Optional destination directory for unpacking (defaults to current path or "ext" if exists)',
+ ),
+ 'force' => array(
+ 'shortopt' => 'f',
+ 'doc' => 'Force the unpacking even if there were errors in the package',
+ ),
+ ),
+ 'doc' => '
+Unpacks a Pecl Package into the selected location. It will download the
+package if needed.
+'),
+ 'run-scripts' => array(
+ 'summary' => 'Run Post-Install Scripts bundled with a package',
+ 'function' => 'doRunScripts',
+ 'shortcut' => 'rs',
+ 'options' => array(
+ ),
+ 'doc' => '
+Run post-installation scripts in package , if any exist.
+'),
+ );
+
+ // }}}
+ // {{{ constructor
+
+ /**
+ * PEAR_Command_Install constructor.
+ *
+ * @access public
+ */
+ function __construct(&$ui, &$config)
+ {
+ parent::__construct($ui, $config);
+ }
+
+ // }}}
+
+ /**
+ * For unit testing purposes
+ */
+ function &getDownloader(&$ui, $options, &$config)
+ {
+ if (!class_exists('PEAR_Downloader')) {
+ require_once 'PEAR/Downloader.php';
+ }
+ $a = new PEAR_Downloader($ui, $options, $config);
+ return $a;
+ }
+
+ /**
+ * For unit testing purposes
+ */
+ function &getInstaller(&$ui)
+ {
+ if (!class_exists('PEAR_Installer')) {
+ require_once 'PEAR/Installer.php';
+ }
+ $a = new PEAR_Installer($ui);
+ return $a;
+ }
+
+ function enableExtension($binaries, $type)
+ {
+ if (!($phpini = $this->config->get('php_ini', null, 'pear.php.net'))) {
+ return PEAR::raiseError('configuration option "php_ini" is not set to php.ini location');
+ }
+ $ini = $this->_parseIni($phpini);
+ if (PEAR::isError($ini)) {
+ return $ini;
+ }
+ $line = 0;
+ if ($type == 'extsrc' || $type == 'extbin') {
+ $search = 'extensions';
+ $enable = 'extension';
+ } else {
+ $search = 'zend_extensions';
+ ob_start();
+ phpinfo(INFO_GENERAL);
+ $info = ob_get_contents();
+ ob_end_clean();
+ $debug = function_exists('leak') ? '_debug' : '';
+ $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : '';
+ $enable = 'zend_extension' . $debug . $ts;
+ }
+ foreach ($ini[$search] as $line => $extension) {
+ if (in_array($extension, $binaries, true) || in_array(
+ $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) {
+ // already enabled - assume if one is, all are
+ return true;
+ }
+ }
+ if ($line) {
+ $newini = array_slice($ini['all'], 0, $line);
+ } else {
+ $newini = array();
+ }
+ foreach ($binaries as $binary) {
+ if ($ini['extension_dir']) {
+ $binary = basename($binary);
+ }
+ $newini[] = $enable . '="' . $binary . '"' . (OS_UNIX ? "\n" : "\r\n");
+ }
+ $newini = array_merge($newini, array_slice($ini['all'], $line));
+ $fp = @fopen($phpini, 'wb');
+ if (!$fp) {
+ return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing');
+ }
+ foreach ($newini as $line) {
+ fwrite($fp, $line);
+ }
+ fclose($fp);
+ return true;
+ }
+
+ function disableExtension($binaries, $type)
+ {
+ if (!($phpini = $this->config->get('php_ini', null, 'pear.php.net'))) {
+ return PEAR::raiseError('configuration option "php_ini" is not set to php.ini location');
+ }
+ $ini = $this->_parseIni($phpini);
+ if (PEAR::isError($ini)) {
+ return $ini;
+ }
+ $line = 0;
+ if ($type == 'extsrc' || $type == 'extbin') {
+ $search = 'extensions';
+ $enable = 'extension';
+ } else {
+ $search = 'zend_extensions';
+ ob_start();
+ phpinfo(INFO_GENERAL);
+ $info = ob_get_contents();
+ ob_end_clean();
+ $debug = function_exists('leak') ? '_debug' : '';
+ $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : '';
+ $enable = 'zend_extension' . $debug . $ts;
+ }
+ $found = false;
+ foreach ($ini[$search] as $line => $extension) {
+ if (in_array($extension, $binaries, true) || in_array(
+ $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) {
+ $found = true;
+ break;
+ }
+ }
+ if (!$found) {
+ // not enabled
+ return true;
+ }
+ $fp = @fopen($phpini, 'wb');
+ if (!$fp) {
+ return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing');
+ }
+ if ($line) {
+ $newini = array_slice($ini['all'], 0, $line);
+ // delete the enable line
+ $newini = array_merge($newini, array_slice($ini['all'], $line + 1));
+ } else {
+ $newini = array_slice($ini['all'], 1);
+ }
+ foreach ($newini as $line) {
+ fwrite($fp, $line);
+ }
+ fclose($fp);
+ return true;
+ }
+
+ function _parseIni($filename)
+ {
+ if (!file_exists($filename)) {
+ return PEAR::raiseError('php.ini "' . $filename . '" does not exist');
+ }
+
+ if (filesize($filename) > 300000) {
+ return PEAR::raiseError('php.ini "' . $filename . '" is too large, aborting');
+ }
+
+ ob_start();
+ phpinfo(INFO_GENERAL);
+ $info = ob_get_contents();
+ ob_end_clean();
+ $debug = function_exists('leak') ? '_debug' : '';
+ $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : '';
+ $zend_extension_line = 'zend_extension' . $debug . $ts;
+ $all = @file($filename);
+ if ($all === false) {
+ return PEAR::raiseError('php.ini "' . $filename .'" could not be read');
+ }
+ $zend_extensions = $extensions = array();
+ // assume this is right, but pull from the php.ini if it is found
+ $extension_dir = ini_get('extension_dir');
+ foreach ($all as $linenum => $line) {
+ $line = trim($line);
+ if (!$line) {
+ continue;
+ }
+ if ($line[0] == ';') {
+ continue;
+ }
+ if (strtolower(substr($line, 0, 13)) == 'extension_dir') {
+ $line = trim(substr($line, 13));
+ if ($line[0] == '=') {
+ $x = trim(substr($line, 1));
+ $x = explode(';', $x);
+ $extension_dir = str_replace('"', '', array_shift($x));
+ continue;
+ }
+ }
+ if (strtolower(substr($line, 0, 9)) == 'extension') {
+ $line = trim(substr($line, 9));
+ if ($line[0] == '=') {
+ $x = trim(substr($line, 1));
+ $x = explode(';', $x);
+ $extensions[$linenum] = str_replace('"', '', array_shift($x));
+ continue;
+ }
+ }
+ if (strtolower(substr($line, 0, strlen($zend_extension_line))) ==
+ $zend_extension_line) {
+ $line = trim(substr($line, strlen($zend_extension_line)));
+ if ($line[0] == '=') {
+ $x = trim(substr($line, 1));
+ $x = explode(';', $x);
+ $zend_extensions[$linenum] = str_replace('"', '', array_shift($x));
+ continue;
+ }
+ }
+ }
+ return array(
+ 'extensions' => $extensions,
+ 'zend_extensions' => $zend_extensions,
+ 'extension_dir' => $extension_dir,
+ 'all' => $all,
+ );
+ }
+
+ // {{{ doInstall()
+
+ function doInstall($command, $options, $params)
+ {
+ if (!class_exists('PEAR_PackageFile')) {
+ require_once 'PEAR/PackageFile.php';
+ }
+
+ if (isset($options['installroot']) && isset($options['packagingroot'])) {
+ return $this->raiseError('ERROR: cannot use both --installroot and --packagingroot');
+ }
+
+ $reg = &$this->config->getRegistry();
+ $channel = isset($options['channel']) ? $options['channel'] : $this->config->get('default_channel');
+ if (!$reg->channelExists($channel)) {
+ return $this->raiseError('Channel "' . $channel . '" does not exist');
+ }
+
+ if (empty($this->installer)) {
+ $this->installer = &$this->getInstaller($this->ui);
+ }
+
+ if ($command == 'upgrade' || $command == 'upgrade-all') {
+ // If people run the upgrade command but pass nothing, emulate a upgrade-all
+ if ($command == 'upgrade' && empty($params)) {
+ return $this->doUpgradeAll($command, $options, $params);
+ }
+ $options['upgrade'] = true;
+ } else {
+ $packages = $params;
+ }
+
+ $instreg = &$reg; // instreg used to check if package is installed
+ if (isset($options['packagingroot']) && !isset($options['upgrade'])) {
+ $packrootphp_dir = $this->installer->_prependPath(
+ $this->config->get('php_dir', null, 'pear.php.net'),
+ $options['packagingroot']);
+ $metadata_dir = $this->config->get('metadata_dir', null, 'pear.php.net');
+ if ($metadata_dir) {
+ $metadata_dir = $this->installer->_prependPath(
+ $metadata_dir,
+ $options['packagingroot']);
+ }
+ $instreg = new PEAR_Registry($packrootphp_dir, false, false, $metadata_dir); // other instreg!
+
+ if ($this->config->get('verbose') > 2) {
+ $this->ui->outputData('using package root: ' . $options['packagingroot']);
+ }
+ }
+
+ $abstractpackages = $otherpackages = array();
+ // parse params
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+
+ foreach ($params as $param) {
+ if (strpos($param, 'http://') === 0) {
+ $otherpackages[] = $param;
+ continue;
+ }
+
+ if (strpos($param, 'channel://') === false && @file_exists($param)) {
+ if (isset($options['force'])) {
+ $otherpackages[] = $param;
+ continue;
+ }
+
+ $pkg = new PEAR_PackageFile($this->config);
+ $pf = $pkg->fromAnyFile($param, PEAR_VALIDATE_DOWNLOADING);
+ if (PEAR::isError($pf)) {
+ $otherpackages[] = $param;
+ continue;
+ }
+
+ $exists = $reg->packageExists($pf->getPackage(), $pf->getChannel());
+ $pversion = $reg->packageInfo($pf->getPackage(), 'version', $pf->getChannel());
+ $version_compare = version_compare($pf->getVersion(), $pversion, '<=');
+ if ($exists && $version_compare) {
+ if ($this->config->get('verbose')) {
+ $this->ui->outputData('Ignoring installed package ' .
+ $reg->parsedPackageNameToString(
+ array('package' => $pf->getPackage(),
+ 'channel' => $pf->getChannel()), true));
+ }
+ continue;
+ }
+ $otherpackages[] = $param;
+ continue;
+ }
+
+ $e = $reg->parsePackageName($param, $channel);
+ if (PEAR::isError($e)) {
+ $otherpackages[] = $param;
+ } else {
+ $abstractpackages[] = $e;
+ }
+ }
+ PEAR::staticPopErrorHandling();
+
+ // if there are any local package .tgz or remote static url, we can't
+ // filter. The filter only works for abstract packages
+ if (count($abstractpackages) && !isset($options['force'])) {
+ // when not being forced, only do necessary upgrades/installs
+ if (isset($options['upgrade'])) {
+ $abstractpackages = $this->_filterUptodatePackages($abstractpackages, $command);
+ } else {
+ $count = count($abstractpackages);
+ foreach ($abstractpackages as $i => $package) {
+ if (isset($package['group'])) {
+ // do not filter out install groups
+ continue;
+ }
+
+ if ($instreg->packageExists($package['package'], $package['channel'])) {
+ if ($count > 1) {
+ if ($this->config->get('verbose')) {
+ $this->ui->outputData('Ignoring installed package ' .
+ $reg->parsedPackageNameToString($package, true));
+ }
+ unset($abstractpackages[$i]);
+ } elseif ($count === 1) {
+ // Lets try to upgrade it since it's already installed
+ $options['upgrade'] = true;
+ }
+ }
+ }
+ }
+ $abstractpackages =
+ array_map(array($reg, 'parsedPackageNameToString'), $abstractpackages);
+ } elseif (count($abstractpackages)) {
+ $abstractpackages =
+ array_map(array($reg, 'parsedPackageNameToString'), $abstractpackages);
+ }
+
+ $packages = array_merge($abstractpackages, $otherpackages);
+ if (!count($packages)) {
+ $c = '';
+ if (isset($options['channel'])){
+ $c .= ' in channel "' . $options['channel'] . '"';
+ }
+ $this->ui->outputData('Nothing to ' . $command . $c);
+ return true;
+ }
+
+ $this->downloader = &$this->getDownloader($this->ui, $options, $this->config);
+ $errors = $downloaded = $binaries = array();
+ $downloaded = &$this->downloader->download($packages);
+ if (PEAR::isError($downloaded)) {
+ return $this->raiseError($downloaded);
+ }
+
+ $errors = $this->downloader->getErrorMsgs();
+ if (count($errors)) {
+ $err = array();
+ $err['data'] = array();
+ foreach ($errors as $error) {
+ if ($error !== null) {
+ $err['data'][] = array($error);
+ }
+ }
+
+ if (!empty($err['data'])) {
+ $err['headline'] = 'Install Errors';
+ $this->ui->outputData($err);
+ }
+
+ if (!count($downloaded)) {
+ return $this->raiseError("$command failed");
+ }
+ }
+
+ $data = array(
+ 'headline' => 'Packages that would be Installed'
+ );
+
+ if (isset($options['pretend'])) {
+ foreach ($downloaded as $package) {
+ $data['data'][] = array($reg->parsedPackageNameToString($package->getParsedPackage()));
+ }
+ $this->ui->outputData($data, 'pretend');
+ return true;
+ }
+
+ $this->installer->setOptions($options);
+ $this->installer->sortPackagesForInstall($downloaded);
+ if (PEAR::isError($err = $this->installer->setDownloadedPackages($downloaded))) {
+ $this->raiseError($err->getMessage());
+ return true;
+ }
+
+ $binaries = $extrainfo = array();
+ foreach ($downloaded as $param) {
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $info = $this->installer->install($param, $options);
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($info)) {
+ $oldinfo = $info;
+ $pkg = &$param->getPackageFile();
+ if ($info->getCode() != PEAR_INSTALLER_NOBINARY) {
+ if (!($info = $pkg->installBinary($this->installer))) {
+ $this->ui->outputData('ERROR: ' .$oldinfo->getMessage());
+ continue;
+ }
+
+ // we just installed a different package than requested,
+ // let's change the param and info so that the rest of this works
+ $param = $info[0];
+ $info = $info[1];
+ }
+ }
+
+ if (!is_array($info)) {
+ return $this->raiseError("$command failed");
+ }
+
+ if ($param->getPackageType() == 'extsrc' ||
+ $param->getPackageType() == 'extbin' ||
+ $param->getPackageType() == 'zendextsrc' ||
+ $param->getPackageType() == 'zendextbin'
+ ) {
+ $pkg = &$param->getPackageFile();
+ if ($instbin = $pkg->getInstalledBinary()) {
+ $instpkg = &$instreg->getPackage($instbin, $pkg->getChannel());
+ } else {
+ $instpkg = &$instreg->getPackage($pkg->getPackage(), $pkg->getChannel());
+ }
+
+ foreach ($instpkg->getFilelist() as $name => $atts) {
+ $pinfo = pathinfo($atts['installed_as']);
+ if (!isset($pinfo['extension']) ||
+ in_array($pinfo['extension'], array('c', 'h'))
+ ) {
+ continue; // make sure we don't match php_blah.h
+ }
+
+ if ((strpos($pinfo['basename'], 'php_') === 0 &&
+ $pinfo['extension'] == 'dll') ||
+ // most unices
+ $pinfo['extension'] == 'so' ||
+ // hp-ux
+ $pinfo['extension'] == 'sl') {
+ $binaries[] = array($atts['installed_as'], $pinfo);
+ break;
+ }
+ }
+
+ if (count($binaries)) {
+ foreach ($binaries as $pinfo) {
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $ret = $this->enableExtension(array($pinfo[0]), $param->getPackageType());
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($ret)) {
+ $extrainfo[] = $ret->getMessage();
+ if ($param->getPackageType() == 'extsrc' ||
+ $param->getPackageType() == 'extbin') {
+ $exttype = 'extension';
+ $extpath = $pinfo[1]['basename'];
+ } else {
+ $exttype = 'zend_extension';
+ $extpath = $atts['installed_as'];
+ }
+ $extrainfo[] = 'You should add "' . $exttype . '=' .
+ $extpath . '" to php.ini';
+ } else {
+ $extrainfo[] = 'Extension ' . $instpkg->getProvidesExtension() .
+ ' enabled in php.ini';
+ }
+ }
+ }
+ }
+
+ if ($this->config->get('verbose') > 0) {
+ $chan = $param->getChannel();
+ $label = $reg->parsedPackageNameToString(
+ array(
+ 'channel' => $chan,
+ 'package' => $param->getPackage(),
+ 'version' => $param->getVersion(),
+ ));
+ $out = array('data' => "$command ok: $label");
+ if (isset($info['release_warnings'])) {
+ $out['release_warnings'] = $info['release_warnings'];
+ }
+ $this->ui->outputData($out, $command);
+
+ if (!isset($options['register-only']) && !isset($options['offline'])) {
+ if ($this->config->isDefinedLayer('ftp')) {
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $info = $this->installer->ftpInstall($param);
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($info)) {
+ $this->ui->outputData($info->getMessage());
+ $this->ui->outputData("remote install failed: $label");
+ } else {
+ $this->ui->outputData("remote install ok: $label");
+ }
+ }
+ }
+ }
+
+ $deps = $param->getDeps();
+ if ($deps) {
+ if (isset($deps['group'])) {
+ $groups = $deps['group'];
+ if (!isset($groups[0])) {
+ $groups = array($groups);
+ }
+
+ foreach ($groups as $group) {
+ if ($group['attribs']['name'] == 'default') {
+ // default group is always installed, unless the user
+ // explicitly chooses to install another group
+ continue;
+ }
+ $extrainfo[] = $param->getPackage() . ': Optional feature ' .
+ $group['attribs']['name'] . ' available (' .
+ $group['attribs']['hint'] . ')';
+ }
+
+ $extrainfo[] = $param->getPackage() .
+ ': To install optional features use "pear install ' .
+ $reg->parsedPackageNameToString(
+ array('package' => $param->getPackage(),
+ 'channel' => $param->getChannel()), true) .
+ '#featurename"';
+ }
+ }
+
+ $pkg = &$instreg->getPackage($param->getPackage(), $param->getChannel());
+ // $pkg may be NULL if install is a 'fake' install via --packagingroot
+ if (is_object($pkg)) {
+ $pkg->setConfig($this->config);
+ if ($list = $pkg->listPostinstallScripts()) {
+ $pn = $reg->parsedPackageNameToString(array('channel' =>
+ $param->getChannel(), 'package' => $param->getPackage()), true);
+ $extrainfo[] = $pn . ' has post-install scripts:';
+ foreach ($list as $file) {
+ $extrainfo[] = $file;
+ }
+ $extrainfo[] = $param->getPackage() .
+ ': Use "pear run-scripts ' . $pn . '" to finish setup.';
+ $extrainfo[] = 'DO NOT RUN SCRIPTS FROM UNTRUSTED SOURCES';
+ }
+ }
+ }
+
+ if (count($extrainfo)) {
+ foreach ($extrainfo as $info) {
+ $this->ui->outputData($info);
+ }
+ }
+
+ return true;
+ }
+
+ // }}}
+ // {{{ doUpgradeAll()
+
+ function doUpgradeAll($command, $options, $params)
+ {
+ $reg = &$this->config->getRegistry();
+ $upgrade = array();
+
+ if (isset($options['channel'])) {
+ $channels = array($options['channel']);
+ } else {
+ $channels = $reg->listChannels();
+ }
+
+ foreach ($channels as $channel) {
+ if ($channel == '__uri') {
+ continue;
+ }
+
+ // parse name with channel
+ foreach ($reg->listPackages($channel) as $name) {
+ $upgrade[] = $reg->parsedPackageNameToString(array(
+ 'channel' => $channel,
+ 'package' => $name
+ ));
+ }
+ }
+
+ $err = $this->doInstall($command, $options, $upgrade);
+ if (PEAR::isError($err)) {
+ $this->ui->outputData($err->getMessage(), $command);
+ }
+ }
+
+ // }}}
+ // {{{ doUninstall()
+
+ function doUninstall($command, $options, $params)
+ {
+ if (count($params) < 1) {
+ return $this->raiseError("Please supply the package(s) you want to uninstall");
+ }
+
+ if (empty($this->installer)) {
+ $this->installer = &$this->getInstaller($this->ui);
+ }
+
+ if (isset($options['remoteconfig'])) {
+ $e = $this->config->readFTPConfigFile($options['remoteconfig']);
+ if (!PEAR::isError($e)) {
+ $this->installer->setConfig($this->config);
+ }
+ }
+
+ $reg = &$this->config->getRegistry();
+ $newparams = array();
+ $binaries = array();
+ $badparams = array();
+ foreach ($params as $pkg) {
+ $channel = $this->config->get('default_channel');
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $parsed = $reg->parsePackageName($pkg, $channel);
+ PEAR::staticPopErrorHandling();
+ if (!$parsed || PEAR::isError($parsed)) {
+ $badparams[] = $pkg;
+ continue;
+ }
+ $package = $parsed['package'];
+ $channel = $parsed['channel'];
+ $info = &$reg->getPackage($package, $channel);
+ if ($info === null &&
+ ($channel == 'pear.php.net' || $channel == 'pecl.php.net')) {
+ // make sure this isn't a package that has flipped from pear to pecl but
+ // used a package.xml 1.0
+ $testc = ($channel == 'pear.php.net') ? 'pecl.php.net' : 'pear.php.net';
+ $info = &$reg->getPackage($package, $testc);
+ if ($info !== null) {
+ $channel = $testc;
+ }
+ }
+ if ($info === null) {
+ $badparams[] = $pkg;
+ } else {
+ $newparams[] = &$info;
+ // check for binary packages (this is an alias for those packages if so)
+ if ($installedbinary = $info->getInstalledBinary()) {
+ $this->ui->log('adding binary package ' .
+ $reg->parsedPackageNameToString(array('channel' => $channel,
+ 'package' => $installedbinary), true));
+ $newparams[] = &$reg->getPackage($installedbinary, $channel);
+ }
+ // add the contents of a dependency group to the list of installed packages
+ if (isset($parsed['group'])) {
+ $group = $info->getDependencyGroup($parsed['group']);
+ if ($group) {
+ $installed = $reg->getInstalledGroup($group);
+ if ($installed) {
+ foreach ($installed as $i => $p) {
+ $newparams[] = &$installed[$i];
+ }
+ }
+ }
+ }
+ }
+ }
+ $err = $this->installer->sortPackagesForUninstall($newparams);
+ if (PEAR::isError($err)) {
+ $this->ui->outputData($err->getMessage(), $command);
+ return true;
+ }
+ $params = $newparams;
+ // twist this to use it to check on whether dependent packages are also being uninstalled
+ // for circular dependencies like subpackages
+ $this->installer->setUninstallPackages($newparams);
+ $params = array_merge($params, $badparams);
+ $binaries = array();
+ foreach ($params as $pkg) {
+ $this->installer->pushErrorHandling(PEAR_ERROR_RETURN);
+ if ($err = $this->installer->uninstall($pkg, $options)) {
+ $this->installer->popErrorHandling();
+ if (PEAR::isError($err)) {
+ $this->ui->outputData($err->getMessage(), $command);
+ continue;
+ }
+ if ($pkg->getPackageType() == 'extsrc' ||
+ $pkg->getPackageType() == 'extbin' ||
+ $pkg->getPackageType() == 'zendextsrc' ||
+ $pkg->getPackageType() == 'zendextbin') {
+ if ($instbin = $pkg->getInstalledBinary()) {
+ continue; // this will be uninstalled later
+ }
+
+ foreach ($pkg->getFilelist() as $name => $atts) {
+ $pinfo = pathinfo($atts['installed_as']);
+ if (!isset($pinfo['extension']) ||
+ in_array($pinfo['extension'], array('c', 'h'))) {
+ continue; // make sure we don't match php_blah.h
+ }
+ if ((strpos($pinfo['basename'], 'php_') === 0 &&
+ $pinfo['extension'] == 'dll') ||
+ // most unices
+ $pinfo['extension'] == 'so' ||
+ // hp-ux
+ $pinfo['extension'] == 'sl') {
+ $binaries[] = array($atts['installed_as'], $pinfo);
+ break;
+ }
+ }
+ if (count($binaries)) {
+ foreach ($binaries as $pinfo) {
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $ret = $this->disableExtension(array($pinfo[0]), $pkg->getPackageType());
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($ret)) {
+ $extrainfo[] = $ret->getMessage();
+ if ($pkg->getPackageType() == 'extsrc' ||
+ $pkg->getPackageType() == 'extbin') {
+ $exttype = 'extension';
+ } else {
+ ob_start();
+ phpinfo(INFO_GENERAL);
+ $info = ob_get_contents();
+ ob_end_clean();
+ $debug = function_exists('leak') ? '_debug' : '';
+ $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : '';
+ $exttype = 'zend_extension' . $debug . $ts;
+ }
+ $this->ui->outputData('Unable to remove "' . $exttype . '=' .
+ $pinfo[1]['basename'] . '" from php.ini', $command);
+ } else {
+ $this->ui->outputData('Extension ' . $pkg->getProvidesExtension() .
+ ' disabled in php.ini', $command);
+ }
+ }
+ }
+ }
+ $savepkg = $pkg;
+ if ($this->config->get('verbose') > 0) {
+ if (is_object($pkg)) {
+ $pkg = $reg->parsedPackageNameToString($pkg);
+ }
+ $this->ui->outputData("uninstall ok: $pkg", $command);
+ }
+ if (!isset($options['offline']) && is_object($savepkg) &&
+ defined('PEAR_REMOTEINSTALL_OK')) {
+ if ($this->config->isDefinedLayer('ftp')) {
+ $this->installer->pushErrorHandling(PEAR_ERROR_RETURN);
+ $info = $this->installer->ftpUninstall($savepkg);
+ $this->installer->popErrorHandling();
+ if (PEAR::isError($info)) {
+ $this->ui->outputData($info->getMessage());
+ $this->ui->outputData("remote uninstall failed: $pkg");
+ } else {
+ $this->ui->outputData("remote uninstall ok: $pkg");
+ }
+ }
+ }
+ } else {
+ $this->installer->popErrorHandling();
+ if (!is_object($pkg)) {
+ return $this->raiseError("uninstall failed: $pkg");
+ }
+ $pkg = $reg->parsedPackageNameToString($pkg);
+ }
+ }
+
+ return true;
+ }
+
+ // }}}
+
+
+ // }}}
+ // {{{ doBundle()
+ /*
+ (cox) It just downloads and untars the package, does not do
+ any check that the PEAR_Installer::_installFile() does.
+ */
+
+ function doBundle($command, $options, $params)
+ {
+ $opts = array(
+ 'force' => true,
+ 'nodeps' => true,
+ 'soft' => true,
+ 'downloadonly' => true
+ );
+ $downloader = &$this->getDownloader($this->ui, $opts, $this->config);
+ $reg = &$this->config->getRegistry();
+ if (count($params) < 1) {
+ return $this->raiseError("Please supply the package you want to bundle");
+ }
+
+ if (isset($options['destination'])) {
+ if (!is_dir($options['destination'])) {
+ System::mkdir('-p ' . $options['destination']);
+ }
+ $dest = realpath($options['destination']);
+ } else {
+ $pwd = getcwd();
+ $dir = $pwd . DIRECTORY_SEPARATOR . 'ext';
+ $dest = is_dir($dir) ? $dir : $pwd;
+ }
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $err = $downloader->setDownloadDir($dest);
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($err)) {
+ return PEAR::raiseError('download directory "' . $dest .
+ '" is not writeable.');
+ }
+ $result = &$downloader->download(array($params[0]));
+ if (PEAR::isError($result)) {
+ return $result;
+ }
+ if (!isset($result[0])) {
+ return $this->raiseError('unable to unpack ' . $params[0]);
+ }
+ $pkgfile = &$result[0]->getPackageFile();
+ $pkgname = $pkgfile->getName();
+ $pkgversion = $pkgfile->getVersion();
+
+ // Unpacking -------------------------------------------------
+ $dest .= DIRECTORY_SEPARATOR . $pkgname;
+ $orig = $pkgname . '-' . $pkgversion;
+
+ $tar = new Archive_Tar($pkgfile->getArchiveFile());
+ if (!$tar->extractModify($dest, $orig)) {
+ return $this->raiseError('unable to unpack ' . $pkgfile->getArchiveFile());
+ }
+ $this->ui->outputData("Package ready at '$dest'");
+ // }}}
+ }
+
+ // }}}
+
+ function doRunScripts($command, $options, $params)
+ {
+ if (!isset($params[0])) {
+ return $this->raiseError('run-scripts expects 1 parameter: a package name');
+ }
+
+ $reg = &$this->config->getRegistry();
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel'));
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($parsed)) {
+ return $this->raiseError($parsed);
+ }
+
+ $package = &$reg->getPackage($parsed['package'], $parsed['channel']);
+ if (!is_object($package)) {
+ return $this->raiseError('Could not retrieve package "' . $params[0] . '" from registry');
+ }
+
+ $package->setConfig($this->config);
+ $package->runPostinstallScripts();
+ $this->ui->outputData('Install scripts complete', $command);
+ return true;
+ }
+
+ /**
+ * Given a list of packages, filter out those ones that are already up to date
+ *
+ * @param $packages: packages, in parsed array format !
+ * @return list of packages that can be upgraded
+ */
+ function _filterUptodatePackages($packages, $command)
+ {
+ $reg = &$this->config->getRegistry();
+ $latestReleases = array();
+
+ $ret = array();
+ foreach ($packages as $package) {
+ if (isset($package['group'])) {
+ $ret[] = $package;
+ continue;
+ }
+
+ $channel = $package['channel'];
+ $name = $package['package'];
+ if (!$reg->packageExists($name, $channel)) {
+ $ret[] = $package;
+ continue;
+ }
+
+ if (!isset($latestReleases[$channel])) {
+ // fill in cache for this channel
+ $chan = $reg->getChannel($channel);
+ if (PEAR::isError($chan)) {
+ return $this->raiseError($chan);
+ }
+
+ $base2 = false;
+ $preferred_mirror = $this->config->get('preferred_mirror', null, $channel);
+ if ($chan->supportsREST($preferred_mirror) &&
+ (
+ //($base2 = $chan->getBaseURL('REST1.4', $preferred_mirror)) ||
+ ($base = $chan->getBaseURL('REST1.0', $preferred_mirror))
+ )
+ ) {
+ $dorest = true;
+ }
+
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ if (!isset($package['state'])) {
+ $state = $this->config->get('preferred_state', null, $channel);
+ } else {
+ $state = $package['state'];
+ }
+
+ if ($dorest) {
+ if ($base2) {
+ $rest = &$this->config->getREST('1.4', array());
+ $base = $base2;
+ } else {
+ $rest = &$this->config->getREST('1.0', array());
+ }
+
+ $installed = array_flip($reg->listPackages($channel));
+ $latest = $rest->listLatestUpgrades($base, $state, $installed, $channel, $reg);
+ }
+
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($latest)) {
+ $this->ui->outputData('Error getting channel info from ' . $channel .
+ ': ' . $latest->getMessage());
+ continue;
+ }
+
+ $latestReleases[$channel] = array_change_key_case($latest);
+ }
+
+ // check package for latest release
+ $name_lower = strtolower($name);
+ if (isset($latestReleases[$channel][$name_lower])) {
+ // if not set, up to date
+ $inst_version = $reg->packageInfo($name, 'version', $channel);
+ $channel_version = $latestReleases[$channel][$name_lower]['version'];
+ if (version_compare($channel_version, $inst_version, 'le')) {
+ // installed version is up-to-date
+ continue;
+ }
+
+ // maintain BC
+ if ($command == 'upgrade-all') {
+ $this->ui->outputData(array('data' => 'Will upgrade ' .
+ $reg->parsedPackageNameToString($package)), $command);
+ }
+ $ret[] = $package;
+ }
+ }
+
+ return $ret;
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Command/Install.xml b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Install.xml
new file mode 100644
index 000000000..1b1e933c2
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Install.xml
@@ -0,0 +1,276 @@
+
+
+ Install Package
+ doInstall
+ i
+
+
+ f
+ will overwrite newer installed packages
+
+
+ l
+ do not check for recommended dependency version
+
+
+ n
+ ignore dependencies, install anyway
+
+
+ r
+ do not install files, only register the package as installed
+
+
+ s
+ soft install, fail silently, or upgrade if already installed
+
+
+ B
+ don't build C extensions
+
+
+ Z
+ request uncompressed files when downloading
+
+
+ R
+ root directory used when installing files (ala PHP's INSTALL_ROOT), use packagingroot for RPM
+ DIR
+
+
+ P
+ root directory used when packaging files, like RPM packaging
+ DIR
+
+
+
+ force install even if there were errors
+
+
+ a
+ install all required and optional dependencies
+
+
+ o
+ install all required dependencies
+
+
+ O
+ do not attempt to download any urls or contact channels
+
+
+ p
+ Only list the packages that would be downloaded
+
+
+ [channel/]<package> ...
+Installs one or more PEAR packages. You can specify a package to
+install in four ways:
+
+"Package-1.0.tgz" : installs from a local file
+
+"http://example.com/Package-1.0.tgz" : installs from
+anywhere on the net.
+
+"package.xml" : installs the package described in
+package.xml. Useful for testing, or for wrapping a PEAR package in
+another package manager such as RPM.
+
+"Package[-version/state][.tar]" : queries your default channel's server
+({config master_server}) and downloads the newest package with
+the preferred quality/state ({config preferred_state}).
+
+To retrieve Package version 1.1, use "Package-1.1," to retrieve
+Package state beta, use "Package-beta." To retrieve an uncompressed
+file, append .tar (make sure there is no file by the same name first)
+
+To download a package from another channel, prefix with the channel name like
+"channel/Package"
+
+More than one package may be specified at once. It is ok to mix these
+four ways of specifying packages.
+
+
+
+ Upgrade Package
+ doInstall
+ up
+
+
+ c
+ upgrade packages from a specific channel
+ CHAN
+
+
+ f
+ overwrite newer installed packages
+
+
+ l
+ do not check for recommended dependency version
+
+
+ n
+ ignore dependencies, upgrade anyway
+
+
+ r
+ do not install files, only register the package as upgraded
+
+
+ B
+ don't build C extensions
+
+
+ Z
+ request uncompressed files when downloading
+
+
+ R
+ root directory used when installing files (ala PHP's INSTALL_ROOT)
+ DIR
+
+
+
+ force install even if there were errors
+
+
+ a
+ install all required and optional dependencies
+
+
+ o
+ install all required dependencies
+
+
+ O
+ do not attempt to download any urls or contact channels
+
+
+ p
+ Only list the packages that would be downloaded
+
+
+ <package> ...
+Upgrades one or more PEAR packages. See documentation for the
+"install" command for ways to specify a package.
+
+When upgrading, your package will be updated if the provided new
+package has a higher version number (use the -f option if you need to
+upgrade anyway).
+
+More than one package may be specified at once.
+
+
+
+ Upgrade All Packages [Deprecated in favor of calling upgrade with no parameters]
+ doUpgradeAll
+ ua
+
+
+ c
+ upgrade packages from a specific channel
+ CHAN
+
+
+ n
+ ignore dependencies, upgrade anyway
+
+
+ r
+ do not install files, only register the package as upgraded
+
+
+ B
+ don't build C extensions
+
+
+ Z
+ request uncompressed files when downloading
+
+
+ R
+ root directory used when installing files (ala PHP's INSTALL_ROOT), use packagingroot for RPM
+ DIR
+
+
+
+ force install even if there were errors
+
+
+
+ do not check for recommended dependency version
+
+
+
+WARNING: This function is deprecated in favor of using the upgrade command with no params
+
+Upgrades all packages that have a newer release available. Upgrades are
+done only if there is a release available of the state specified in
+"preferred_state" (currently {config preferred_state}), or a state considered
+more stable.
+
+
+
+ Un-install Package
+ doUninstall
+ un
+
+
+ n
+ ignore dependencies, uninstall anyway
+
+
+ r
+ do not remove files, only register the packages as not installed
+
+
+ R
+ root directory used when installing files (ala PHP's INSTALL_ROOT)
+ DIR
+
+
+
+ force install even if there were errors
+
+
+ O
+ do not attempt to uninstall remotely
+
+
+ [channel/]<package> ...
+Uninstalls one or more PEAR packages. More than one package may be
+specified at once. Prefix with channel name to uninstall from a
+channel not in your default channel ({config default_channel})
+
+
+
+ Unpacks a Pecl Package
+ doBundle
+ bun
+
+
+ d
+ Optional destination directory for unpacking (defaults to current path or "ext" if exists)
+ DIR
+
+
+ f
+ Force the unpacking even if there were errors in the package
+
+
+ <package>
+Unpacks a Pecl Package into the selected location. It will download the
+package if needed.
+
+
+
+ Run Post-Install Scripts bundled with a package
+ doRunScripts
+ rs
+
+ <package>
+Run post-installation scripts in package <package>, if any exist.
+
+
+
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Command/Mirror.php b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Mirror.php
new file mode 100644
index 000000000..473c62867
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Mirror.php
@@ -0,0 +1,138 @@
+
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.2.0
+ */
+
+/**
+ * base class
+ */
+require_once 'PEAR/Command/Common.php';
+
+/**
+ * PEAR commands for providing file mirrors
+ *
+ * @category pear
+ * @package PEAR
+ * @author Alexander Merz
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.2.0
+ */
+class PEAR_Command_Mirror extends PEAR_Command_Common
+{
+ var $commands = array(
+ 'download-all' => array(
+ 'summary' => 'Downloads each available package from the default channel',
+ 'function' => 'doDownloadAll',
+ 'shortcut' => 'da',
+ 'options' => array(
+ 'channel' =>
+ array(
+ 'shortopt' => 'c',
+ 'doc' => 'specify a channel other than the default channel',
+ 'arg' => 'CHAN',
+ ),
+ ),
+ 'doc' => '
+Requests a list of available packages from the default channel ({config default_channel})
+and downloads them to current working directory. Note: only
+packages within preferred_state ({config preferred_state}) will be downloaded'
+ ),
+ );
+
+ /**
+ * PEAR_Command_Mirror constructor.
+ *
+ * @access public
+ * @param object PEAR_Frontend a reference to an frontend
+ * @param object PEAR_Config a reference to the configuration data
+ */
+ function __construct(&$ui, &$config)
+ {
+ parent::__construct($ui, $config);
+ }
+
+ /**
+ * For unit-testing
+ */
+ function &factory($a)
+ {
+ $a = &PEAR_Command::factory($a, $this->config);
+ return $a;
+ }
+
+ /**
+ * retrieves a list of avaible Packages from master server
+ * and downloads them
+ *
+ * @access public
+ * @param string $command the command
+ * @param array $options the command options before the command
+ * @param array $params the stuff after the command name
+ * @return bool true if successful
+ * @throw PEAR_Error
+ */
+ function doDownloadAll($command, $options, $params)
+ {
+ $savechannel = $this->config->get('default_channel');
+ $reg = &$this->config->getRegistry();
+ $channel = isset($options['channel']) ? $options['channel'] :
+ $this->config->get('default_channel');
+ if (!$reg->channelExists($channel)) {
+ $this->config->set('default_channel', $savechannel);
+ return $this->raiseError('Channel "' . $channel . '" does not exist');
+ }
+ $this->config->set('default_channel', $channel);
+
+ $this->ui->outputData('Using Channel ' . $this->config->get('default_channel'));
+ $chan = $reg->getChannel($channel);
+ if (PEAR::isError($chan)) {
+ return $this->raiseError($chan);
+ }
+
+ if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
+ $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
+ $rest = &$this->config->getREST('1.0', array());
+ $remoteInfo = array_flip($rest->listPackages($base, $channel));
+ }
+
+ if (PEAR::isError($remoteInfo)) {
+ return $remoteInfo;
+ }
+
+ $cmd = &$this->factory("download");
+ if (PEAR::isError($cmd)) {
+ return $cmd;
+ }
+
+ $this->ui->outputData('Using Preferred State of ' .
+ $this->config->get('preferred_state'));
+ $this->ui->outputData('Gathering release information, please wait...');
+
+ /**
+ * Error handling not necessary, because already done by
+ * the download command
+ */
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $err = $cmd->run('download', array('downloadonly' => true), array_keys($remoteInfo));
+ PEAR::staticPopErrorHandling();
+ $this->config->set('default_channel', $savechannel);
+ if (PEAR::isError($err)) {
+ $this->ui->outputData($err->getMessage());
+ }
+
+ return true;
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Command/Mirror.xml b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Mirror.xml
new file mode 100644
index 000000000..fe8be9d03
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Mirror.xml
@@ -0,0 +1,18 @@
+
+
+ Downloads each available package from the default channel
+ doDownloadAll
+ da
+
+
+ c
+ specify a channel other than the default channel
+ CHAN
+
+
+
+Requests a list of available packages from the default channel ({config default_channel})
+and downloads them to current working directory. Note: only
+packages within preferred_state ({config preferred_state}) will be downloaded
+
+
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Command/Package.php b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Package.php
new file mode 100644
index 000000000..25125fd98
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Package.php
@@ -0,0 +1,1123 @@
+
+ * @author Martin Jansen
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ */
+
+/**
+ * base class
+ */
+require_once 'PEAR/Command/Common.php';
+
+/**
+ * PEAR commands for login/logout
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Martin Jansen
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 0.1
+ */
+
+class PEAR_Command_Package extends PEAR_Command_Common
+{
+ var $commands = array(
+ 'package' => array(
+ 'summary' => 'Build Package',
+ 'function' => 'doPackage',
+ 'shortcut' => 'p',
+ 'options' => array(
+ 'nocompress' => array(
+ 'shortopt' => 'Z',
+ 'doc' => 'Do not gzip the package file'
+ ),
+ 'showname' => array(
+ 'shortopt' => 'n',
+ 'doc' => 'Print the name of the packaged file.',
+ ),
+ ),
+ 'doc' => '[descfile] [descfile2]
+Creates a PEAR package from its description file (usually called
+package.xml). If a second packagefile is passed in, then
+the packager will check to make sure that one is a package.xml
+version 1.0, and the other is a package.xml version 2.0. The
+package.xml version 1.0 will be saved as "package.xml" in the archive,
+and the other as "package2.xml" in the archive"
+'
+ ),
+ 'package-validate' => array(
+ 'summary' => 'Validate Package Consistency',
+ 'function' => 'doPackageValidate',
+ 'shortcut' => 'pv',
+ 'options' => array(),
+ 'doc' => '
+',
+ ),
+ 'cvsdiff' => array(
+ 'summary' => 'Run a "cvs diff" for all files in a package',
+ 'function' => 'doCvsDiff',
+ 'shortcut' => 'cd',
+ 'options' => array(
+ 'quiet' => array(
+ 'shortopt' => 'q',
+ 'doc' => 'Be quiet',
+ ),
+ 'reallyquiet' => array(
+ 'shortopt' => 'Q',
+ 'doc' => 'Be really quiet',
+ ),
+ 'date' => array(
+ 'shortopt' => 'D',
+ 'doc' => 'Diff against revision of DATE',
+ 'arg' => 'DATE',
+ ),
+ 'release' => array(
+ 'shortopt' => 'R',
+ 'doc' => 'Diff against tag for package release REL',
+ 'arg' => 'REL',
+ ),
+ 'revision' => array(
+ 'shortopt' => 'r',
+ 'doc' => 'Diff against revision REV',
+ 'arg' => 'REV',
+ ),
+ 'context' => array(
+ 'shortopt' => 'c',
+ 'doc' => 'Generate context diff',
+ ),
+ 'unified' => array(
+ 'shortopt' => 'u',
+ 'doc' => 'Generate unified diff',
+ ),
+ 'ignore-case' => array(
+ 'shortopt' => 'i',
+ 'doc' => 'Ignore case, consider upper- and lower-case letters equivalent',
+ ),
+ 'ignore-whitespace' => array(
+ 'shortopt' => 'b',
+ 'doc' => 'Ignore changes in amount of white space',
+ ),
+ 'ignore-blank-lines' => array(
+ 'shortopt' => 'B',
+ 'doc' => 'Ignore changes that insert or delete blank lines',
+ ),
+ 'brief' => array(
+ 'doc' => 'Report only whether the files differ, no details',
+ ),
+ 'dry-run' => array(
+ 'shortopt' => 'n',
+ 'doc' => 'Don\'t do anything, just pretend',
+ ),
+ ),
+ 'doc' => '
+Compares all the files in a package. Without any options, this
+command will compare the current code with the last checked-in code.
+Using the -r or -R option you may compare the current code with that
+of a specific release.
+',
+ ),
+ 'svntag' => array(
+ 'summary' => 'Set SVN Release Tag',
+ 'function' => 'doSvnTag',
+ 'shortcut' => 'sv',
+ 'options' => array(
+ 'quiet' => array(
+ 'shortopt' => 'q',
+ 'doc' => 'Be quiet',
+ ),
+ 'slide' => array(
+ 'shortopt' => 'F',
+ 'doc' => 'Move (slide) tag if it exists',
+ ),
+ 'delete' => array(
+ 'shortopt' => 'd',
+ 'doc' => 'Remove tag',
+ ),
+ 'dry-run' => array(
+ 'shortopt' => 'n',
+ 'doc' => 'Don\'t do anything, just pretend',
+ ),
+ ),
+ 'doc' => ' [files...]
+ Sets a SVN tag on all files in a package. Use this command after you have
+ packaged a distribution tarball with the "package" command to tag what
+ revisions of what files were in that release. If need to fix something
+ after running svntag once, but before the tarball is released to the public,
+ use the "slide" option to move the release tag.
+
+ to include files (such as a second package.xml, or tests not included in the
+ release), pass them as additional parameters.
+ ',
+ ),
+ 'cvstag' => array(
+ 'summary' => 'Set CVS Release Tag',
+ 'function' => 'doCvsTag',
+ 'shortcut' => 'ct',
+ 'options' => array(
+ 'quiet' => array(
+ 'shortopt' => 'q',
+ 'doc' => 'Be quiet',
+ ),
+ 'reallyquiet' => array(
+ 'shortopt' => 'Q',
+ 'doc' => 'Be really quiet',
+ ),
+ 'slide' => array(
+ 'shortopt' => 'F',
+ 'doc' => 'Move (slide) tag if it exists',
+ ),
+ 'delete' => array(
+ 'shortopt' => 'd',
+ 'doc' => 'Remove tag',
+ ),
+ 'dry-run' => array(
+ 'shortopt' => 'n',
+ 'doc' => 'Don\'t do anything, just pretend',
+ ),
+ ),
+ 'doc' => ' [files...]
+Sets a CVS tag on all files in a package. Use this command after you have
+packaged a distribution tarball with the "package" command to tag what
+revisions of what files were in that release. If need to fix something
+after running cvstag once, but before the tarball is released to the public,
+use the "slide" option to move the release tag.
+
+to include files (such as a second package.xml, or tests not included in the
+release), pass them as additional parameters.
+',
+ ),
+ 'package-dependencies' => array(
+ 'summary' => 'Show package dependencies',
+ 'function' => 'doPackageDependencies',
+ 'shortcut' => 'pd',
+ 'options' => array(),
+ 'doc' => ' or or
+List all dependencies the package has.
+Can take a tgz / tar file, package.xml or a package name of an installed package.'
+ ),
+ 'sign' => array(
+ 'summary' => 'Sign a package distribution file',
+ 'function' => 'doSign',
+ 'shortcut' => 'si',
+ 'options' => array(
+ 'verbose' => array(
+ 'shortopt' => 'v',
+ 'doc' => 'Display GnuPG output',
+ ),
+ ),
+ 'doc' => '
+Signs a package distribution (.tar or .tgz) file with GnuPG.',
+ ),
+ 'makerpm' => array(
+ 'summary' => 'Builds an RPM spec file from a PEAR package',
+ 'function' => 'doMakeRPM',
+ 'shortcut' => 'rpm',
+ 'options' => array(
+ 'spec-template' => array(
+ 'shortopt' => 't',
+ 'arg' => 'FILE',
+ 'doc' => 'Use FILE as RPM spec file template'
+ ),
+ 'rpm-pkgname' => array(
+ 'shortopt' => 'p',
+ 'arg' => 'FORMAT',
+ 'doc' => 'Use FORMAT as format string for RPM package name, %s is replaced
+by the PEAR package name, defaults to "PEAR::%s".',
+ ),
+ ),
+ 'doc' => '
+
+Creates an RPM .spec file for wrapping a PEAR package inside an RPM
+package. Intended to be used from the SPECS directory, with the PEAR
+package tarball in the SOURCES directory:
+
+$ pear makerpm ../SOURCES/Net_Socket-1.0.tgz
+Wrote RPM spec file PEAR::Net_Geo-1.0.spec
+$ rpm -bb PEAR::Net_Socket-1.0.spec
+...
+Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
+',
+ ),
+ 'convert' => array(
+ 'summary' => 'Convert a package.xml 1.0 to package.xml 2.0 format',
+ 'function' => 'doConvert',
+ 'shortcut' => 'c2',
+ 'options' => array(
+ 'flat' => array(
+ 'shortopt' => 'f',
+ 'doc' => 'do not beautify the filelist.',
+ ),
+ ),
+ 'doc' => '[descfile] [descfile2]
+Converts a package.xml in 1.0 format into a package.xml
+in 2.0 format. The new file will be named package2.xml by default,
+and package.xml will be used as the old file by default.
+This is not the most intelligent conversion, and should only be
+used for automated conversion or learning the format.
+'
+ ),
+ );
+
+ var $output;
+
+ /**
+ * PEAR_Command_Package constructor.
+ *
+ * @access public
+ */
+ function __construct(&$ui, &$config)
+ {
+ parent::__construct($ui, $config);
+ }
+
+ function _displayValidationResults($err, $warn, $strict = false)
+ {
+ foreach ($err as $e) {
+ $this->output .= "Error: $e\n";
+ }
+ foreach ($warn as $w) {
+ $this->output .= "Warning: $w\n";
+ }
+ $this->output .= sprintf('Validation: %d error(s), %d warning(s)'."\n",
+ sizeof($err), sizeof($warn));
+ if ($strict && count($err) > 0) {
+ $this->output .= "Fix these errors and try again.";
+ return false;
+ }
+ return true;
+ }
+
+ function &getPackager()
+ {
+ if (!class_exists('PEAR_Packager')) {
+ require_once 'PEAR/Packager.php';
+ }
+ $a = new PEAR_Packager;
+ return $a;
+ }
+
+ function &getPackageFile($config, $debug = false)
+ {
+ if (!class_exists('PEAR_Common')) {
+ require_once 'PEAR/Common.php';
+ }
+ if (!class_exists('PEAR_PackageFile')) {
+ require_once 'PEAR/PackageFile.php';
+ }
+ $a = new PEAR_PackageFile($config, $debug);
+ $common = new PEAR_Common;
+ $common->ui = $this->ui;
+ $a->setLogger($common);
+ return $a;
+ }
+
+ function doPackage($command, $options, $params)
+ {
+ $this->output = '';
+ $pkginfofile = isset($params[0]) ? $params[0] : 'package.xml';
+ $pkg2 = isset($params[1]) ? $params[1] : null;
+ if (!$pkg2 && !isset($params[0]) && file_exists('package2.xml')) {
+ $pkg2 = 'package2.xml';
+ }
+
+ $packager = &$this->getPackager();
+ $compress = empty($options['nocompress']) ? true : false;
+ $result = $packager->package($pkginfofile, $compress, $pkg2);
+ if (PEAR::isError($result)) {
+ return $this->raiseError($result);
+ }
+
+ // Don't want output, only the package file name just created
+ if (isset($options['showname'])) {
+ $this->output = $result;
+ }
+
+ if ($this->output) {
+ $this->ui->outputData($this->output, $command);
+ }
+
+ return true;
+ }
+
+ function doPackageValidate($command, $options, $params)
+ {
+ $this->output = '';
+ if (count($params) < 1) {
+ $params[0] = 'package.xml';
+ }
+
+ $obj = &$this->getPackageFile($this->config, $this->_debug);
+ $obj->rawReturn();
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $info = $obj->fromTgzFile($params[0], PEAR_VALIDATE_NORMAL);
+ if (PEAR::isError($info)) {
+ $info = $obj->fromPackageFile($params[0], PEAR_VALIDATE_NORMAL);
+ } else {
+ $archive = $info->getArchiveFile();
+ $tar = new Archive_Tar($archive);
+ $tar->extract(dirname($info->getPackageFile()));
+ $info->setPackageFile(dirname($info->getPackageFile()) . DIRECTORY_SEPARATOR .
+ $info->getPackage() . '-' . $info->getVersion() . DIRECTORY_SEPARATOR .
+ basename($info->getPackageFile()));
+ }
+
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($info)) {
+ return $this->raiseError($info);
+ }
+
+ $valid = false;
+ if ($info->getPackagexmlVersion() == '2.0') {
+ if ($valid = $info->validate(PEAR_VALIDATE_NORMAL)) {
+ $info->flattenFileList();
+ $valid = $info->validate(PEAR_VALIDATE_PACKAGING);
+ }
+ } else {
+ $valid = $info->validate(PEAR_VALIDATE_PACKAGING);
+ }
+
+ $err = $warn = array();
+ if ($errors = $info->getValidationWarnings()) {
+ foreach ($errors as $error) {
+ if ($error['level'] == 'warning') {
+ $warn[] = $error['message'];
+ } else {
+ $err[] = $error['message'];
+ }
+ }
+ }
+
+ $this->_displayValidationResults($err, $warn);
+ $this->ui->outputData($this->output, $command);
+ return true;
+ }
+
+ function doSvnTag($command, $options, $params)
+ {
+ $this->output = '';
+ $_cmd = $command;
+ if (count($params) < 1) {
+ $help = $this->getHelp($command);
+ return $this->raiseError("$command: missing parameter: $help[0]");
+ }
+
+ $packageFile = realpath($params[0]);
+ $dir = dirname($packageFile);
+ $dir = substr($dir, strrpos($dir, DIRECTORY_SEPARATOR) + 1);
+ $obj = &$this->getPackageFile($this->config, $this->_debug);
+ $info = $obj->fromAnyFile($packageFile, PEAR_VALIDATE_NORMAL);
+ if (PEAR::isError($info)) {
+ return $this->raiseError($info);
+ }
+
+ $err = $warn = array();
+ if (!$info->validate()) {
+ foreach ($info->getValidationWarnings() as $error) {
+ if ($error['level'] == 'warning') {
+ $warn[] = $error['message'];
+ } else {
+ $err[] = $error['message'];
+ }
+ }
+ }
+
+ if (!$this->_displayValidationResults($err, $warn, true)) {
+ $this->ui->outputData($this->output, $command);
+ return $this->raiseError('SVN tag failed');
+ }
+
+ $version = $info->getVersion();
+ $package = $info->getName();
+ $svntag = "$package-$version";
+
+ if (isset($options['delete'])) {
+ return $this->_svnRemoveTag($version, $package, $svntag, $packageFile, $options);
+ }
+
+ $path = $this->_svnFindPath($packageFile);
+
+ // Check if there are any modified files
+ $fp = popen('svn st --xml ' . dirname($packageFile), "r");
+ $out = '';
+ while ($line = fgets($fp, 1024)) {
+ $out .= rtrim($line)."\n";
+ }
+ pclose($fp);
+
+ if (!isset($options['quiet']) && strpos($out, 'item="modified"')) {
+ $params = array(array(
+ 'name' => 'modified',
+ 'type' => 'yesno',
+ 'default' => 'no',
+ 'prompt' => 'You have files in your SVN checkout (' . $path['from'] . ') that have been modified but not committed, do you still want to tag ' . $version . '?',
+ ));
+ $answers = $this->ui->confirmDialog($params);
+
+ if (!in_array($answers['modified'], array('y', 'yes', 'on', '1'))) {
+ return true;
+ }
+ }
+
+ if (isset($options['slide'])) {
+ $this->_svnRemoveTag($version, $package, $svntag, $packageFile, $options);
+ }
+
+ // Check if tag already exists
+ $releaseTag = $path['local']['base'] . 'tags' . DIRECTORY_SEPARATOR . $svntag;
+ $existsCommand = 'svn ls ' . $path['base'] . 'tags/';
+
+ $fp = popen($existsCommand, "r");
+ $out = '';
+ while ($line = fgets($fp, 1024)) {
+ $out .= rtrim($line)."\n";
+ }
+ pclose($fp);
+
+ if (in_array($svntag . DIRECTORY_SEPARATOR, explode("\n", $out))) {
+ $this->ui->outputData($this->output, $command);
+ return $this->raiseError('SVN tag ' . $svntag . ' for ' . $package . ' already exists.');
+ } elseif (file_exists($path['local']['base'] . 'tags') === false) {
+ return $this->raiseError('Can not locate the tags directory at ' . $path['local']['base'] . 'tags');
+ } elseif (is_writeable($path['local']['base'] . 'tags') === false) {
+ return $this->raiseError('Can not write to the tag directory at ' . $path['local']['base'] . 'tags');
+ } else {
+ $makeCommand = 'svn mkdir ' . $releaseTag;
+ $this->output .= "+ $makeCommand\n";
+ if (empty($options['dry-run'])) {
+ // We need to create the tag dir.
+ $fp = popen($makeCommand, "r");
+ $out = '';
+ while ($line = fgets($fp, 1024)) {
+ $out .= rtrim($line)."\n";
+ }
+ pclose($fp);
+ $this->output .= "$out\n";
+ }
+ }
+
+ $command = 'svn';
+ if (isset($options['quiet'])) {
+ $command .= ' -q';
+ }
+
+ $command .= ' copy --parents ';
+
+ $dir = dirname($packageFile);
+ $dir = substr($dir, strrpos($dir, DIRECTORY_SEPARATOR) + 1);
+ $files = array_keys($info->getFilelist());
+ if (!in_array(basename($packageFile), $files)) {
+ $files[] = basename($packageFile);
+ }
+
+ array_shift($params);
+ if (count($params)) {
+ // add in additional files to be tagged (package files and such)
+ $files = array_merge($files, $params);
+ }
+
+ $commands = array();
+ foreach ($files as $file) {
+ if (!file_exists($file)) {
+ $file = $dir . DIRECTORY_SEPARATOR . $file;
+ }
+ $commands[] = $command . ' ' . escapeshellarg($file) . ' ' .
+ escapeshellarg($releaseTag . DIRECTORY_SEPARATOR . $file);
+ }
+
+ $this->output .= implode("\n", $commands) . "\n";
+ if (empty($options['dry-run'])) {
+ foreach ($commands as $command) {
+ $fp = popen($command, "r");
+ while ($line = fgets($fp, 1024)) {
+ $this->output .= rtrim($line)."\n";
+ }
+ pclose($fp);
+ }
+ }
+
+ $command = 'svn ci -m "Tagging the ' . $version . ' release" ' . $releaseTag . "\n";
+ $this->output .= "+ $command\n";
+ if (empty($options['dry-run'])) {
+ $fp = popen($command, "r");
+ while ($line = fgets($fp, 1024)) {
+ $this->output .= rtrim($line)."\n";
+ }
+ pclose($fp);
+ }
+
+ $this->ui->outputData($this->output, $_cmd);
+ return true;
+ }
+
+ function _svnFindPath($file)
+ {
+ $xml = '';
+ $command = "svn info --xml $file";
+ $fp = popen($command, "r");
+ while ($line = fgets($fp, 1024)) {
+ $xml .= rtrim($line)."\n";
+ }
+ pclose($fp);
+ $url_tag = strpos($xml, '');
+ $url = substr($xml, $url_tag + 5, strpos($xml, '', $url_tag + 5) - ($url_tag + 5));
+
+ $path = array();
+ $path['from'] = substr($url, 0, strrpos($url, '/'));
+ $path['base'] = substr($path['from'], 0, strrpos($path['from'], '/') + 1);
+
+ // Figure out the local paths - see http://pear.php.net/bugs/17463
+ $pos = strpos($file, DIRECTORY_SEPARATOR . 'trunk' . DIRECTORY_SEPARATOR);
+ if ($pos === false) {
+ $pos = strpos($file, DIRECTORY_SEPARATOR . 'branches' . DIRECTORY_SEPARATOR);
+ }
+ $path['local']['base'] = substr($file, 0, $pos + 1);
+
+ return $path;
+ }
+
+ function _svnRemoveTag($version, $package, $tag, $packageFile, $options)
+ {
+ $command = 'svn';
+
+ if (isset($options['quiet'])) {
+ $command .= ' -q';
+ }
+
+ $command .= ' remove';
+ $command .= ' -m "Removing tag for the ' . $version . ' release."';
+
+ $path = $this->_svnFindPath($packageFile);
+ $command .= ' ' . $path['base'] . 'tags/' . $tag;
+
+
+ if ($this->config->get('verbose') > 1) {
+ $this->output .= "+ $command\n";
+ }
+
+ $this->output .= "+ $command\n";
+ if (empty($options['dry-run'])) {
+ $fp = popen($command, "r");
+ while ($line = fgets($fp, 1024)) {
+ $this->output .= rtrim($line)."\n";
+ }
+ pclose($fp);
+ }
+
+ $this->ui->outputData($this->output, $command);
+ return true;
+ }
+
+ function doCvsTag($command, $options, $params)
+ {
+ $this->output = '';
+ $_cmd = $command;
+ if (count($params) < 1) {
+ $help = $this->getHelp($command);
+ return $this->raiseError("$command: missing parameter: $help[0]");
+ }
+
+ $packageFile = realpath($params[0]);
+ $obj = &$this->getPackageFile($this->config, $this->_debug);
+ $info = $obj->fromAnyFile($packageFile, PEAR_VALIDATE_NORMAL);
+ if (PEAR::isError($info)) {
+ return $this->raiseError($info);
+ }
+
+ $err = $warn = array();
+ if (!$info->validate()) {
+ foreach ($info->getValidationWarnings() as $error) {
+ if ($error['level'] == 'warning') {
+ $warn[] = $error['message'];
+ } else {
+ $err[] = $error['message'];
+ }
+ }
+ }
+
+ if (!$this->_displayValidationResults($err, $warn, true)) {
+ $this->ui->outputData($this->output, $command);
+ return $this->raiseError('CVS tag failed');
+ }
+
+ $version = $info->getVersion();
+ $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $version);
+ $cvstag = "RELEASE_$cvsversion";
+ $files = array_keys($info->getFilelist());
+ $command = 'cvs';
+ if (isset($options['quiet'])) {
+ $command .= ' -q';
+ }
+
+ if (isset($options['reallyquiet'])) {
+ $command .= ' -Q';
+ }
+
+ $command .= ' tag';
+ if (isset($options['slide'])) {
+ $command .= ' -F';
+ }
+
+ if (isset($options['delete'])) {
+ $command .= ' -d';
+ }
+
+ $command .= ' ' . $cvstag . ' ' . escapeshellarg($params[0]);
+ array_shift($params);
+ if (count($params)) {
+ // add in additional files to be tagged
+ $files = array_merge($files, $params);
+ }
+
+ $dir = dirname($packageFile);
+ $dir = substr($dir, strrpos($dir, '/') + 1);
+ foreach ($files as $file) {
+ if (!file_exists($file)) {
+ $file = $dir . DIRECTORY_SEPARATOR . $file;
+ }
+ $command .= ' ' . escapeshellarg($file);
+ }
+
+ if ($this->config->get('verbose') > 1) {
+ $this->output .= "+ $command\n";
+ }
+
+ $this->output .= "+ $command\n";
+ if (empty($options['dry-run'])) {
+ $fp = popen($command, "r");
+ while ($line = fgets($fp, 1024)) {
+ $this->output .= rtrim($line)."\n";
+ }
+ pclose($fp);
+ }
+
+ $this->ui->outputData($this->output, $_cmd);
+ return true;
+ }
+
+ function doCvsDiff($command, $options, $params)
+ {
+ $this->output = '';
+ if (sizeof($params) < 1) {
+ $help = $this->getHelp($command);
+ return $this->raiseError("$command: missing parameter: $help[0]");
+ }
+
+ $file = realpath($params[0]);
+ $obj = &$this->getPackageFile($this->config, $this->_debug);
+ $info = $obj->fromAnyFile($file, PEAR_VALIDATE_NORMAL);
+ if (PEAR::isError($info)) {
+ return $this->raiseError($info);
+ }
+
+ $err = $warn = array();
+ if (!$info->validate()) {
+ foreach ($info->getValidationWarnings() as $error) {
+ if ($error['level'] == 'warning') {
+ $warn[] = $error['message'];
+ } else {
+ $err[] = $error['message'];
+ }
+ }
+ }
+
+ if (!$this->_displayValidationResults($err, $warn, true)) {
+ $this->ui->outputData($this->output, $command);
+ return $this->raiseError('CVS diff failed');
+ }
+
+ $info1 = $info->getFilelist();
+ $files = $info1;
+ $cmd = "cvs";
+ if (isset($options['quiet'])) {
+ $cmd .= ' -q';
+ unset($options['quiet']);
+ }
+
+ if (isset($options['reallyquiet'])) {
+ $cmd .= ' -Q';
+ unset($options['reallyquiet']);
+ }
+
+ if (isset($options['release'])) {
+ $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $options['release']);
+ $cvstag = "RELEASE_$cvsversion";
+ $options['revision'] = $cvstag;
+ unset($options['release']);
+ }
+
+ $execute = true;
+ if (isset($options['dry-run'])) {
+ $execute = false;
+ unset($options['dry-run']);
+ }
+
+ $cmd .= ' diff';
+ // the rest of the options are passed right on to "cvs diff"
+ foreach ($options as $option => $optarg) {
+ $arg = $short = false;
+ if (isset($this->commands[$command]['options'][$option])) {
+ $arg = $this->commands[$command]['options'][$option]['arg'];
+ $short = $this->commands[$command]['options'][$option]['shortopt'];
+ }
+ $cmd .= $short ? " -$short" : " --$option";
+ if ($arg && $optarg) {
+ $cmd .= ($short ? '' : '=') . escapeshellarg($optarg);
+ }
+ }
+
+ foreach ($files as $file) {
+ $cmd .= ' ' . escapeshellarg($file['name']);
+ }
+
+ if ($this->config->get('verbose') > 1) {
+ $this->output .= "+ $cmd\n";
+ }
+
+ if ($execute) {
+ $fp = popen($cmd, "r");
+ while ($line = fgets($fp, 1024)) {
+ $this->output .= rtrim($line)."\n";
+ }
+ pclose($fp);
+ }
+
+ $this->ui->outputData($this->output, $command);
+ return true;
+ }
+
+ function doPackageDependencies($command, $options, $params)
+ {
+ // $params[0] -> the PEAR package to list its information
+ if (count($params) !== 1) {
+ return $this->raiseError("bad parameter(s), try \"help $command\"");
+ }
+
+ $obj = &$this->getPackageFile($this->config, $this->_debug);
+ if (is_file($params[0]) || strpos($params[0], '.xml') > 0) {
+ $info = $obj->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
+ } else {
+ $reg = $this->config->getRegistry();
+ $info = $obj->fromArray($reg->packageInfo($params[0]));
+ }
+
+ if (PEAR::isError($info)) {
+ return $this->raiseError($info);
+ }
+
+ $deps = $info->getDeps();
+ if (is_array($deps)) {
+ if ($info->getPackagexmlVersion() == '1.0') {
+ $data = array(
+ 'caption' => 'Dependencies for pear/' . $info->getPackage(),
+ 'border' => true,
+ 'headline' => array("Required?", "Type", "Name", "Relation", "Version"),
+ );
+
+ foreach ($deps as $d) {
+ if (isset($d['optional'])) {
+ if ($d['optional'] == 'yes') {
+ $req = 'No';
+ } else {
+ $req = 'Yes';
+ }
+ } else {
+ $req = 'Yes';
+ }
+
+ if (isset($this->_deps_rel_trans[$d['rel']])) {
+ $rel = $this->_deps_rel_trans[$d['rel']];
+ } else {
+ $rel = $d['rel'];
+ }
+
+ if (isset($this->_deps_type_trans[$d['type']])) {
+ $type = ucfirst($this->_deps_type_trans[$d['type']]);
+ } else {
+ $type = $d['type'];
+ }
+
+ if (isset($d['name'])) {
+ $name = $d['name'];
+ } else {
+ $name = '';
+ }
+
+ if (isset($d['version'])) {
+ $version = $d['version'];
+ } else {
+ $version = '';
+ }
+
+ $data['data'][] = array($req, $type, $name, $rel, $version);
+ }
+ } else { // package.xml 2.0 dependencies display
+ require_once 'PEAR/Dependency2.php';
+ $deps = $info->getDependencies();
+ $reg = &$this->config->getRegistry();
+ if (is_array($deps)) {
+ $d = new PEAR_Dependency2($this->config, array(), '');
+ $data = array(
+ 'caption' => 'Dependencies for ' . $info->getPackage(),
+ 'border' => true,
+ 'headline' => array("Required?", "Type", "Name", 'Versioning', 'Group'),
+ );
+ foreach ($deps as $type => $subd) {
+ $req = ($type == 'required') ? 'Yes' : 'No';
+ if ($type == 'group' && isset($subd['attribs']['name'])) {
+ $group = $subd['attribs']['name'];
+ } else {
+ $group = '';
+ }
+
+ if (!isset($subd[0])) {
+ $subd = array($subd);
+ }
+
+ foreach ($subd as $groupa) {
+ foreach ($groupa as $deptype => $depinfo) {
+ if ($deptype == 'attribs') {
+ continue;
+ }
+
+ if ($deptype == 'pearinstaller') {
+ $deptype = 'pear Installer';
+ }
+
+ if (!isset($depinfo[0])) {
+ $depinfo = array($depinfo);
+ }
+
+ foreach ($depinfo as $inf) {
+ $name = '';
+ if (isset($inf['channel'])) {
+ $alias = $reg->channelAlias($inf['channel']);
+ if (!$alias) {
+ $alias = '(channel?) ' .$inf['channel'];
+ }
+ $name = $alias . '/';
+
+ }
+ if (isset($inf['name'])) {
+ $name .= $inf['name'];
+ } elseif (isset($inf['pattern'])) {
+ $name .= $inf['pattern'];
+ } else {
+ $name .= '';
+ }
+
+ if (isset($inf['uri'])) {
+ $name .= ' [' . $inf['uri'] . ']';
+ }
+
+ if (isset($inf['conflicts'])) {
+ $ver = 'conflicts';
+ } else {
+ $ver = $d->_getExtraString($inf);
+ }
+
+ $data['data'][] = array($req, ucfirst($deptype), $name,
+ $ver, $group);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ $this->ui->outputData($data, $command);
+ return true;
+ }
+
+ // Fallback
+ $this->ui->outputData("This package does not have any dependencies.", $command);
+ }
+
+ function doSign($command, $options, $params)
+ {
+ // should move most of this code into PEAR_Packager
+ // so it'll be easy to implement "pear package --sign"
+ if (count($params) !== 1) {
+ return $this->raiseError("bad parameter(s), try \"help $command\"");
+ }
+
+ require_once 'System.php';
+ require_once 'Archive/Tar.php';
+
+ if (!file_exists($params[0])) {
+ return $this->raiseError("file does not exist: $params[0]");
+ }
+
+ $obj = $this->getPackageFile($this->config, $this->_debug);
+ $info = $obj->fromTgzFile($params[0], PEAR_VALIDATE_NORMAL);
+ if (PEAR::isError($info)) {
+ return $this->raiseError($info);
+ }
+
+ $tar = new Archive_Tar($params[0]);
+
+ $tmpdir = $this->config->get('temp_dir');
+ $tmpdir = System::mktemp(' -t "' . $tmpdir . '" -d pearsign');
+ if (!$tar->extractList('package2.xml package.xml package.sig', $tmpdir)) {
+ return $this->raiseError("failed to extract tar file");
+ }
+
+ if (file_exists("$tmpdir/package.sig")) {
+ return $this->raiseError("package already signed");
+ }
+
+ $packagexml = 'package.xml';
+ if (file_exists("$tmpdir/package2.xml")) {
+ $packagexml = 'package2.xml';
+ }
+
+ if (file_exists("$tmpdir/package.sig")) {
+ unlink("$tmpdir/package.sig");
+ }
+
+ if (!file_exists("$tmpdir/$packagexml")) {
+ return $this->raiseError("Extracted file $tmpdir/$packagexml not found.");
+ }
+
+ $input = $this->ui->userDialog($command,
+ array('GnuPG Passphrase'),
+ array('password'));
+ if (!isset($input[0])) {
+ //use empty passphrase
+ $input[0] = '';
+ }
+
+ $devnull = (isset($options['verbose'])) ? '' : ' 2>/dev/null';
+ $gpg = popen("gpg --batch --passphrase-fd 0 --armor --detach-sign --output $tmpdir/package.sig $tmpdir/$packagexml" . $devnull, "w");
+ if (!$gpg) {
+ return $this->raiseError("gpg command failed");
+ }
+
+ fwrite($gpg, "$input[0]\n");
+ if (pclose($gpg) || !file_exists("$tmpdir/package.sig")) {
+ return $this->raiseError("gpg sign failed");
+ }
+
+ if (!$tar->addModify("$tmpdir/package.sig", '', $tmpdir)) {
+ return $this->raiseError('failed adding signature to file');
+ }
+
+ $this->ui->outputData("Package signed.", $command);
+ return true;
+ }
+
+ /**
+ * For unit testing purposes
+ */
+ function &getInstaller(&$ui)
+ {
+ if (!class_exists('PEAR_Installer')) {
+ require_once 'PEAR/Installer.php';
+ }
+ $a = new PEAR_Installer($ui);
+ return $a;
+ }
+
+ /**
+ * For unit testing purposes
+ */
+ function &getCommandPackaging(&$ui, &$config)
+ {
+ if (!class_exists('PEAR_Command_Packaging')) {
+ if ($fp = @fopen('PEAR/Command/Packaging.php', 'r', true)) {
+ fclose($fp);
+ include_once 'PEAR/Command/Packaging.php';
+ }
+ }
+
+ if (class_exists('PEAR_Command_Packaging')) {
+ $a = new PEAR_Command_Packaging($ui, $config);
+ } else {
+ $a = null;
+ }
+
+ return $a;
+ }
+
+ function doMakeRPM($command, $options, $params)
+ {
+
+ // Check to see if PEAR_Command_Packaging is installed, and
+ // transparently switch to use the "make-rpm-spec" command from it
+ // instead, if it does. Otherwise, continue to use the old version
+ // of "makerpm" supplied with this package (PEAR).
+ $packaging_cmd = $this->getCommandPackaging($this->ui, $this->config);
+ if ($packaging_cmd !== null) {
+ $this->ui->outputData('PEAR_Command_Packaging is installed; using '.
+ 'newer "make-rpm-spec" command instead');
+ return $packaging_cmd->run('make-rpm-spec', $options, $params);
+ }
+
+ $this->ui->outputData('WARNING: "pear makerpm" is no longer available; an '.
+ 'improved version is available via "pear make-rpm-spec", which '.
+ 'is available by installing PEAR_Command_Packaging');
+ return true;
+ }
+
+ function doConvert($command, $options, $params)
+ {
+ $packagexml = isset($params[0]) ? $params[0] : 'package.xml';
+ $newpackagexml = isset($params[1]) ? $params[1] : dirname($packagexml) .
+ DIRECTORY_SEPARATOR . 'package2.xml';
+ $pkg = &$this->getPackageFile($this->config, $this->_debug);
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $pf = $pkg->fromPackageFile($packagexml, PEAR_VALIDATE_NORMAL);
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($pf)) {
+ if (is_array($pf->getUserInfo())) {
+ foreach ($pf->getUserInfo() as $warning) {
+ $this->ui->outputData($warning['message']);
+ }
+ }
+ return $this->raiseError($pf);
+ }
+
+ if (is_a($pf, 'PEAR_PackageFile_v2')) {
+ $this->ui->outputData($packagexml . ' is already a package.xml version 2.0');
+ return true;
+ }
+
+ $gen = &$pf->getDefaultGenerator();
+ $newpf = &$gen->toV2();
+ $newpf->setPackagefile($newpackagexml);
+ $gen = &$newpf->getDefaultGenerator();
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $state = (isset($options['flat']) ? PEAR_VALIDATE_PACKAGING : PEAR_VALIDATE_NORMAL);
+ $saved = $gen->toPackageFile(dirname($newpackagexml), $state, basename($newpackagexml));
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($saved)) {
+ if (is_array($saved->getUserInfo())) {
+ foreach ($saved->getUserInfo() as $warning) {
+ $this->ui->outputData($warning['message']);
+ }
+ }
+
+ $this->ui->outputData($saved->getMessage());
+ return true;
+ }
+
+ $this->ui->outputData('Wrote new version 2.0 package.xml to "' . $saved . '"');
+ return true;
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Command/Package.xml b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Package.xml
new file mode 100644
index 000000000..d1aff9d48
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Package.xml
@@ -0,0 +1,237 @@
+
+
+ Build Package
+ doPackage
+ p
+
+
+ Z
+ Do not gzip the package file
+
+
+ n
+ Print the name of the packaged file.
+
+
+ [descfile] [descfile2]
+Creates a PEAR package from its description file (usually called
+package.xml). If a second packagefile is passed in, then
+the packager will check to make sure that one is a package.xml
+version 1.0, and the other is a package.xml version 2.0. The
+package.xml version 1.0 will be saved as "package.xml" in the archive,
+and the other as "package2.xml" in the archive"
+
+
+
+ Validate Package Consistency
+ doPackageValidate
+ pv
+
+
+
+
+
+ Run a "cvs diff" for all files in a package
+ doCvsDiff
+ cd
+
+
+ q
+ Be quiet
+
+
+ Q
+ Be really quiet
+
+
+ D
+ Diff against revision of DATE
+ DATE
+
+
+ R
+ Diff against tag for package release REL
+ REL
+
+
+ r
+ Diff against revision REV
+ REV
+
+
+ c
+ Generate context diff
+
+
+ u
+ Generate unified diff
+
+
+ i
+ Ignore case, consider upper- and lower-case letters equivalent
+
+
+ b
+ Ignore changes in amount of white space
+
+
+ B
+ Ignore changes that insert or delete blank lines
+
+
+
+ Report only whether the files differ, no details
+
+
+ n
+ Don't do anything, just pretend
+
+
+ <package.xml>
+Compares all the files in a package. Without any options, this
+command will compare the current code with the last checked-in code.
+Using the -r or -R option you may compare the current code with that
+of a specific release.
+
+
+
+ Set SVN Release Tag
+ doSvnTag
+ sv
+
+
+ q
+ Be quiet
+
+
+ F
+ Move (slide) tag if it exists
+
+
+ d
+ Remove tag
+
+
+ n
+ Don't do anything, just pretend
+
+
+ <package.xml> [files...]
+ Sets a SVN tag on all files in a package. Use this command after you have
+ packaged a distribution tarball with the "package" command to tag what
+ revisions of what files were in that release. If need to fix something
+ after running svntag once, but before the tarball is released to the public,
+ use the "slide" option to move the release tag.
+
+ to include files (such as a second package.xml, or tests not included in the
+ release), pass them as additional parameters.
+
+
+
+ Set CVS Release Tag
+ doCvsTag
+ ct
+
+
+ q
+ Be quiet
+
+
+ Q
+ Be really quiet
+
+
+ F
+ Move (slide) tag if it exists
+
+
+ d
+ Remove tag
+
+
+ n
+ Don't do anything, just pretend
+
+
+ <package.xml> [files...]
+Sets a CVS tag on all files in a package. Use this command after you have
+packaged a distribution tarball with the "package" command to tag what
+revisions of what files were in that release. If need to fix something
+after running cvstag once, but before the tarball is released to the public,
+use the "slide" option to move the release tag.
+
+to include files (such as a second package.xml, or tests not included in the
+release), pass them as additional parameters.
+
+
+
+ Show package dependencies
+ doPackageDependencies
+ pd
+
+ <package-file> or <package.xml> or <install-package-name>
+List all dependencies the package has.
+Can take a tgz / tar file, package.xml or a package name of an installed package.
+
+
+ Sign a package distribution file
+ doSign
+ si
+
+
+ v
+ Display GnuPG output
+
+
+ <package-file>
+Signs a package distribution (.tar or .tgz) file with GnuPG.
+
+
+ Builds an RPM spec file from a PEAR package
+ doMakeRPM
+ rpm
+
+
+ t
+ Use FILE as RPM spec file template
+ FILE
+
+
+ p
+ Use FORMAT as format string for RPM package name, %s is replaced
+by the PEAR package name, defaults to "PEAR::%s".
+ FORMAT
+
+
+ <package-file>
+
+Creates an RPM .spec file for wrapping a PEAR package inside an RPM
+package. Intended to be used from the SPECS directory, with the PEAR
+package tarball in the SOURCES directory:
+
+$ pear makerpm ../SOURCES/Net_Socket-1.0.tgz
+Wrote RPM spec file PEAR::Net_Geo-1.0.spec
+$ rpm -bb PEAR::Net_Socket-1.0.spec
+...
+Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
+
+
+
+ Convert a package.xml 1.0 to package.xml 2.0 format
+ doConvert
+ c2
+
+
+ f
+ do not beautify the filelist.
+
+
+ [descfile] [descfile2]
+Converts a package.xml in 1.0 format into a package.xml
+in 2.0 format. The new file will be named package2.xml by default,
+and package.xml will be used as the old file by default.
+This is not the most intelligent conversion, and should only be
+used for automated conversion or learning the format.
+
+
+
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Command/Pickle.php b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Pickle.php
new file mode 100644
index 000000000..8ac3fcb6b
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Pickle.php
@@ -0,0 +1,420 @@
+
+ * @copyright 2005-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.1
+ */
+
+/**
+ * base class
+ */
+require_once 'PEAR/Command/Common.php';
+
+/**
+ * PEAR commands for login/logout
+ *
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 2005-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.1
+ */
+
+class PEAR_Command_Pickle extends PEAR_Command_Common
+{
+ var $commands = array(
+ 'pickle' => array(
+ 'summary' => 'Build PECL Package',
+ 'function' => 'doPackage',
+ 'shortcut' => 'pi',
+ 'options' => array(
+ 'nocompress' => array(
+ 'shortopt' => 'Z',
+ 'doc' => 'Do not gzip the package file'
+ ),
+ 'showname' => array(
+ 'shortopt' => 'n',
+ 'doc' => 'Print the name of the packaged file.',
+ ),
+ ),
+ 'doc' => '[descfile]
+Creates a PECL package from its package2.xml file.
+
+An automatic conversion will be made to a package.xml 1.0 and written out to
+disk in the current directory as "package.xml". Note that
+only simple package.xml 2.0 will be converted. package.xml 2.0 with:
+
+ - dependency types other than required/optional PECL package/ext/php/pearinstaller
+ - more than one extsrcrelease or zendextsrcrelease
+ - zendextbinrelease, extbinrelease, phprelease, or bundle release type
+ - dependency groups
+ - ignore tags in release filelist
+ - tasks other than replace
+ - custom roles
+
+will cause pickle to fail, and output an error message. If your package2.xml
+uses any of these features, you are best off using PEAR_PackageFileManager to
+generate both package.xml.
+'
+ ),
+ );
+
+ /**
+ * PEAR_Command_Package constructor.
+ *
+ * @access public
+ */
+ function __construct(&$ui, &$config)
+ {
+ parent::__construct($ui, $config);
+ }
+
+ /**
+ * For unit-testing ease
+ *
+ * @return PEAR_Packager
+ */
+ function &getPackager()
+ {
+ if (!class_exists('PEAR_Packager')) {
+ require_once 'PEAR/Packager.php';
+ }
+
+ $a = new PEAR_Packager;
+ return $a;
+ }
+
+ /**
+ * For unit-testing ease
+ *
+ * @param PEAR_Config $config
+ * @param bool $debug
+ * @param string|null $tmpdir
+ * @return PEAR_PackageFile
+ */
+ function &getPackageFile($config, $debug = false)
+ {
+ if (!class_exists('PEAR_Common')) {
+ require_once 'PEAR/Common.php';
+ }
+
+ if (!class_exists('PEAR_PackageFile')) {
+ require_once 'PEAR/PackageFile.php';
+ }
+
+ $a = new PEAR_PackageFile($config, $debug);
+ $common = new PEAR_Common;
+ $common->ui = $this->ui;
+ $a->setLogger($common);
+ return $a;
+ }
+
+ function doPackage($command, $options, $params)
+ {
+ $this->output = '';
+ $pkginfofile = isset($params[0]) ? $params[0] : 'package2.xml';
+ $packager = &$this->getPackager();
+ if (PEAR::isError($err = $this->_convertPackage($pkginfofile))) {
+ return $err;
+ }
+
+ $compress = empty($options['nocompress']) ? true : false;
+ $result = $packager->package($pkginfofile, $compress, 'package.xml');
+ if (PEAR::isError($result)) {
+ return $this->raiseError($result);
+ }
+
+ // Don't want output, only the package file name just created
+ if (isset($options['showname'])) {
+ $this->ui->outputData($result, $command);
+ }
+
+ return true;
+ }
+
+ function _convertPackage($packagexml)
+ {
+ $pkg = &$this->getPackageFile($this->config);
+ $pf2 = &$pkg->fromPackageFile($packagexml, PEAR_VALIDATE_NORMAL);
+ if (!is_a($pf2, 'PEAR_PackageFile_v2')) {
+ return $this->raiseError('Cannot process "' .
+ $packagexml . '", is not a package.xml 2.0');
+ }
+
+ require_once 'PEAR/PackageFile/v1.php';
+ $pf = new PEAR_PackageFile_v1;
+ $pf->setConfig($this->config);
+ if ($pf2->getPackageType() != 'extsrc' && $pf2->getPackageType() != 'zendextsrc') {
+ return $this->raiseError('Cannot safely convert "' . $packagexml .
+ '", is not an extension source package. Using a PEAR_PackageFileManager-based ' .
+ 'script is an option');
+ }
+
+ if (is_array($pf2->getUsesRole())) {
+ return $this->raiseError('Cannot safely convert "' . $packagexml .
+ '", contains custom roles. Using a PEAR_PackageFileManager-based script or ' .
+ 'the convert command is an option');
+ }
+
+ if (is_array($pf2->getUsesTask())) {
+ return $this->raiseError('Cannot safely convert "' . $packagexml .
+ '", contains custom tasks. Using a PEAR_PackageFileManager-based script or ' .
+ 'the convert command is an option');
+ }
+
+ $deps = $pf2->getDependencies();
+ if (isset($deps['group'])) {
+ return $this->raiseError('Cannot safely convert "' . $packagexml .
+ '", contains dependency groups. Using a PEAR_PackageFileManager-based script ' .
+ 'or the convert command is an option');
+ }
+
+ if (isset($deps['required']['subpackage']) ||
+ isset($deps['optional']['subpackage'])) {
+ return $this->raiseError('Cannot safely convert "' . $packagexml .
+ '", contains subpackage dependencies. Using a PEAR_PackageFileManager-based '.
+ 'script is an option');
+ }
+
+ if (isset($deps['required']['os'])) {
+ return $this->raiseError('Cannot safely convert "' . $packagexml .
+ '", contains os dependencies. Using a PEAR_PackageFileManager-based '.
+ 'script is an option');
+ }
+
+ if (isset($deps['required']['arch'])) {
+ return $this->raiseError('Cannot safely convert "' . $packagexml .
+ '", contains arch dependencies. Using a PEAR_PackageFileManager-based '.
+ 'script is an option');
+ }
+
+ $pf->setPackage($pf2->getPackage());
+ $pf->setSummary($pf2->getSummary());
+ $pf->setDescription($pf2->getDescription());
+ foreach ($pf2->getMaintainers() as $maintainer) {
+ $pf->addMaintainer($maintainer['role'], $maintainer['handle'],
+ $maintainer['name'], $maintainer['email']);
+ }
+
+ $pf->setVersion($pf2->getVersion());
+ $pf->setDate($pf2->getDate());
+ $pf->setLicense($pf2->getLicense());
+ $pf->setState($pf2->getState());
+ $pf->setNotes($pf2->getNotes());
+ $pf->addPhpDep($deps['required']['php']['min'], 'ge');
+ if (isset($deps['required']['php']['max'])) {
+ $pf->addPhpDep($deps['required']['php']['max'], 'le');
+ }
+
+ if (isset($deps['required']['package'])) {
+ if (!isset($deps['required']['package'][0])) {
+ $deps['required']['package'] = array($deps['required']['package']);
+ }
+
+ foreach ($deps['required']['package'] as $dep) {
+ if (!isset($dep['channel'])) {
+ return $this->raiseError('Cannot safely convert "' . $packagexml . '"' .
+ ' contains uri-based dependency on a package. Using a ' .
+ 'PEAR_PackageFileManager-based script is an option');
+ }
+
+ if ($dep['channel'] != 'pear.php.net'
+ && $dep['channel'] != 'pecl.php.net'
+ && $dep['channel'] != 'doc.php.net') {
+ return $this->raiseError('Cannot safely convert "' . $packagexml . '"' .
+ ' contains dependency on a non-standard channel package. Using a ' .
+ 'PEAR_PackageFileManager-based script is an option');
+ }
+
+ if (isset($dep['conflicts'])) {
+ return $this->raiseError('Cannot safely convert "' . $packagexml . '"' .
+ ' contains conflicts dependency. Using a ' .
+ 'PEAR_PackageFileManager-based script is an option');
+ }
+
+ if (isset($dep['exclude'])) {
+ $this->ui->outputData('WARNING: exclude tags are ignored in conversion');
+ }
+
+ if (isset($dep['min'])) {
+ $pf->addPackageDep($dep['name'], $dep['min'], 'ge');
+ }
+
+ if (isset($dep['max'])) {
+ $pf->addPackageDep($dep['name'], $dep['max'], 'le');
+ }
+ }
+ }
+
+ if (isset($deps['required']['extension'])) {
+ if (!isset($deps['required']['extension'][0])) {
+ $deps['required']['extension'] = array($deps['required']['extension']);
+ }
+
+ foreach ($deps['required']['extension'] as $dep) {
+ if (isset($dep['conflicts'])) {
+ return $this->raiseError('Cannot safely convert "' . $packagexml . '"' .
+ ' contains conflicts dependency. Using a ' .
+ 'PEAR_PackageFileManager-based script is an option');
+ }
+
+ if (isset($dep['exclude'])) {
+ $this->ui->outputData('WARNING: exclude tags are ignored in conversion');
+ }
+
+ if (isset($dep['min'])) {
+ $pf->addExtensionDep($dep['name'], $dep['min'], 'ge');
+ }
+
+ if (isset($dep['max'])) {
+ $pf->addExtensionDep($dep['name'], $dep['max'], 'le');
+ }
+ }
+ }
+
+ if (isset($deps['optional']['package'])) {
+ if (!isset($deps['optional']['package'][0])) {
+ $deps['optional']['package'] = array($deps['optional']['package']);
+ }
+
+ foreach ($deps['optional']['package'] as $dep) {
+ if (!isset($dep['channel'])) {
+ return $this->raiseError('Cannot safely convert "' . $packagexml . '"' .
+ ' contains uri-based dependency on a package. Using a ' .
+ 'PEAR_PackageFileManager-based script is an option');
+ }
+
+ if ($dep['channel'] != 'pear.php.net'
+ && $dep['channel'] != 'pecl.php.net'
+ && $dep['channel'] != 'doc.php.net') {
+ return $this->raiseError('Cannot safely convert "' . $packagexml . '"' .
+ ' contains dependency on a non-standard channel package. Using a ' .
+ 'PEAR_PackageFileManager-based script is an option');
+ }
+
+ if (isset($dep['exclude'])) {
+ $this->ui->outputData('WARNING: exclude tags are ignored in conversion');
+ }
+
+ if (isset($dep['min'])) {
+ $pf->addPackageDep($dep['name'], $dep['min'], 'ge', 'yes');
+ }
+
+ if (isset($dep['max'])) {
+ $pf->addPackageDep($dep['name'], $dep['max'], 'le', 'yes');
+ }
+ }
+ }
+
+ if (isset($deps['optional']['extension'])) {
+ if (!isset($deps['optional']['extension'][0])) {
+ $deps['optional']['extension'] = array($deps['optional']['extension']);
+ }
+
+ foreach ($deps['optional']['extension'] as $dep) {
+ if (isset($dep['exclude'])) {
+ $this->ui->outputData('WARNING: exclude tags are ignored in conversion');
+ }
+
+ if (isset($dep['min'])) {
+ $pf->addExtensionDep($dep['name'], $dep['min'], 'ge', 'yes');
+ }
+
+ if (isset($dep['max'])) {
+ $pf->addExtensionDep($dep['name'], $dep['max'], 'le', 'yes');
+ }
+ }
+ }
+
+ $contents = $pf2->getContents();
+ $release = $pf2->getReleases();
+ if (isset($releases[0])) {
+ return $this->raiseError('Cannot safely process "' . $packagexml . '" contains '
+ . 'multiple extsrcrelease/zendextsrcrelease tags. Using a PEAR_PackageFileManager-based script ' .
+ 'or the convert command is an option');
+ }
+
+ if ($configoptions = $pf2->getConfigureOptions()) {
+ foreach ($configoptions as $option) {
+ $default = isset($option['default']) ? $option['default'] : false;
+ $pf->addConfigureOption($option['name'], $option['prompt'], $default);
+ }
+ }
+
+ if (isset($release['filelist']['ignore'])) {
+ return $this->raiseError('Cannot safely process "' . $packagexml . '" contains '
+ . 'ignore tags. Using a PEAR_PackageFileManager-based script or the convert' .
+ ' command is an option');
+ }
+
+ if (isset($release['filelist']['install']) &&
+ !isset($release['filelist']['install'][0])) {
+ $release['filelist']['install'] = array($release['filelist']['install']);
+ }
+
+ if (isset($contents['dir']['attribs']['baseinstalldir'])) {
+ $baseinstalldir = $contents['dir']['attribs']['baseinstalldir'];
+ } else {
+ $baseinstalldir = false;
+ }
+
+ if (!isset($contents['dir']['file'][0])) {
+ $contents['dir']['file'] = array($contents['dir']['file']);
+ }
+
+ foreach ($contents['dir']['file'] as $file) {
+ if ($baseinstalldir && !isset($file['attribs']['baseinstalldir'])) {
+ $file['attribs']['baseinstalldir'] = $baseinstalldir;
+ }
+
+ $processFile = $file;
+ unset($processFile['attribs']);
+ if (count($processFile)) {
+ foreach ($processFile as $name => $task) {
+ if ($name != $pf2->getTasksNs() . ':replace') {
+ return $this->raiseError('Cannot safely process "' . $packagexml .
+ '" contains tasks other than replace. Using a ' .
+ 'PEAR_PackageFileManager-based script is an option.');
+ }
+ $file['attribs']['replace'][] = $task;
+ }
+ }
+
+ if (!in_array($file['attribs']['role'], PEAR_Common::getFileRoles())) {
+ return $this->raiseError('Cannot safely convert "' . $packagexml .
+ '", contains custom roles. Using a PEAR_PackageFileManager-based script ' .
+ 'or the convert command is an option');
+ }
+
+ if (isset($release['filelist']['install'])) {
+ foreach ($release['filelist']['install'] as $installas) {
+ if ($installas['attribs']['name'] == $file['attribs']['name']) {
+ $file['attribs']['install-as'] = $installas['attribs']['as'];
+ }
+ }
+ }
+
+ $pf->addFile('/', $file['attribs']['name'], $file['attribs']);
+ }
+
+ if ($pf2->getChangeLog()) {
+ $this->ui->outputData('WARNING: changelog is not translated to package.xml ' .
+ '1.0, use PEAR_PackageFileManager-based script if you need changelog-' .
+ 'translation for package.xml 1.0');
+ }
+
+ $gen = &$pf->getDefaultGenerator();
+ $gen->toPackageFile('.');
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Command/Pickle.xml b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Pickle.xml
new file mode 100644
index 000000000..721ecea99
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Pickle.xml
@@ -0,0 +1,36 @@
+
+
+ Build PECL Package
+ doPackage
+ pi
+
+
+ Z
+ Do not gzip the package file
+
+
+ n
+ Print the name of the packaged file.
+
+
+ [descfile]
+Creates a PECL package from its package2.xml file.
+
+An automatic conversion will be made to a package.xml 1.0 and written out to
+disk in the current directory as "package.xml". Note that
+only simple package.xml 2.0 will be converted. package.xml 2.0 with:
+
+ - dependency types other than required/optional PECL package/ext/php/pearinstaller
+ - more than one extsrcrelease or zendextsrcrelease
+ - zendextbinrelease, extbinrelease, phprelease, or bundle release type
+ - dependency groups
+ - ignore tags in release filelist
+ - tasks other than replace
+ - custom roles
+
+will cause pickle to fail, and output an error message. If your package2.xml
+uses any of these features, you are best off using PEAR_PackageFileManager to
+generate both package.xml.
+
+
+
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Command/Registry.php b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Registry.php
new file mode 100644
index 000000000..3a78b0330
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Registry.php
@@ -0,0 +1,1144 @@
+
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ */
+
+/**
+ * base class
+ */
+require_once 'PEAR/Command/Common.php';
+
+/**
+ * PEAR commands for registry manipulation
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 0.1
+ */
+class PEAR_Command_Registry extends PEAR_Command_Common
+{
+ var $commands = array(
+ 'list' => array(
+ 'summary' => 'List Installed Packages In The Default Channel',
+ 'function' => 'doList',
+ 'shortcut' => 'l',
+ 'options' => array(
+ 'channel' => array(
+ 'shortopt' => 'c',
+ 'doc' => 'list installed packages from this channel',
+ 'arg' => 'CHAN',
+ ),
+ 'allchannels' => array(
+ 'shortopt' => 'a',
+ 'doc' => 'list installed packages from all channels',
+ ),
+ 'channelinfo' => array(
+ 'shortopt' => 'i',
+ 'doc' => 'output fully channel-aware data, even on failure',
+ ),
+ ),
+ 'doc' => '
+If invoked without parameters, this command lists the PEAR packages
+installed in your php_dir ({config php_dir}). With a parameter, it
+lists the files in a package.
+',
+ ),
+ 'list-files' => array(
+ 'summary' => 'List Files In Installed Package',
+ 'function' => 'doFileList',
+ 'shortcut' => 'fl',
+ 'options' => array(),
+ 'doc' => '
+List the files in an installed package.
+'
+ ),
+ 'shell-test' => array(
+ 'summary' => 'Shell Script Test',
+ 'function' => 'doShellTest',
+ 'shortcut' => 'st',
+ 'options' => array(),
+ 'doc' => ' [[relation] version]
+Tests if a package is installed in the system. Will exit(1) if it is not.
+ The version comparison operator. One of:
+ <, lt, <=, le, >, gt, >=, ge, ==, =, eq, !=, <>, ne
+ The version to compare with
+'),
+ 'info' => array(
+ 'summary' => 'Display information about a package',
+ 'function' => 'doInfo',
+ 'shortcut' => 'in',
+ 'options' => array(),
+ 'doc' => '
+Displays information about a package. The package argument may be a
+local package file, an URL to a package file, or the name of an
+installed package.'
+ )
+ );
+
+ /**
+ * PEAR_Command_Registry constructor.
+ *
+ * @access public
+ */
+ function __construct(&$ui, &$config)
+ {
+ parent::__construct($ui, $config);
+ }
+
+ function _sortinfo($a, $b)
+ {
+ $apackage = isset($a['package']) ? $a['package'] : $a['name'];
+ $bpackage = isset($b['package']) ? $b['package'] : $b['name'];
+ return strcmp($apackage, $bpackage);
+ }
+
+ function doList($command, $options, $params)
+ {
+ $reg = &$this->config->getRegistry();
+ $channelinfo = isset($options['channelinfo']);
+ if (isset($options['allchannels']) && !$channelinfo) {
+ return $this->doListAll($command, array(), $params);
+ }
+
+ if (isset($options['allchannels']) && $channelinfo) {
+ // allchannels with $channelinfo
+ unset($options['allchannels']);
+ $channels = $reg->getChannels();
+ $errors = array();
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ foreach ($channels as $channel) {
+ $options['channel'] = $channel->getName();
+ $ret = $this->doList($command, $options, $params);
+
+ if (PEAR::isError($ret)) {
+ $errors[] = $ret;
+ }
+ }
+
+ PEAR::staticPopErrorHandling();
+ if (count($errors)) {
+ // for now, only give first error
+ return PEAR::raiseError($errors[0]);
+ }
+
+ return true;
+ }
+
+ if (count($params) === 1) {
+ return $this->doFileList($command, $options, $params);
+ }
+
+ if (isset($options['channel'])) {
+ if (!$reg->channelExists($options['channel'])) {
+ return $this->raiseError('Channel "' . $options['channel'] .'" does not exist');
+ }
+
+ $channel = $reg->channelName($options['channel']);
+ } else {
+ $channel = $this->config->get('default_channel');
+ }
+
+ $installed = $reg->packageInfo(null, null, $channel);
+ usort($installed, array(&$this, '_sortinfo'));
+
+ $data = array(
+ 'caption' => 'Installed packages, channel ' .
+ $channel . ':',
+ 'border' => true,
+ 'headline' => array('Package', 'Version', 'State'),
+ 'channel' => $channel,
+ );
+ if ($channelinfo) {
+ $data['headline'] = array('Channel', 'Package', 'Version', 'State');
+ }
+
+ if (count($installed) && !isset($data['data'])) {
+ $data['data'] = array();
+ }
+
+ foreach ($installed as $package) {
+ $pobj = $reg->getPackage(isset($package['package']) ?
+ $package['package'] : $package['name'], $channel);
+ if ($channelinfo) {
+ $packageinfo = array($pobj->getChannel(), $pobj->getPackage(), $pobj->getVersion(),
+ $pobj->getState() ? $pobj->getState() : null);
+ } else {
+ $packageinfo = array($pobj->getPackage(), $pobj->getVersion(),
+ $pobj->getState() ? $pobj->getState() : null);
+ }
+ $data['data'][] = $packageinfo;
+ }
+
+ if (count($installed) === 0) {
+ if (!$channelinfo) {
+ $data = '(no packages installed from channel ' . $channel . ')';
+ } else {
+ $data = array(
+ 'caption' => 'Installed packages, channel ' .
+ $channel . ':',
+ 'border' => true,
+ 'channel' => $channel,
+ 'data' => array(array('(no packages installed)')),
+ );
+ }
+ }
+
+ $this->ui->outputData($data, $command);
+ return true;
+ }
+
+ function doListAll($command, $options, $params)
+ {
+ // This duplicate code is deprecated over
+ // list --channelinfo, which gives identical
+ // output for list and list --allchannels.
+ $reg = &$this->config->getRegistry();
+ $installed = $reg->packageInfo(null, null, null);
+ foreach ($installed as $channel => $packages) {
+ usort($packages, array($this, '_sortinfo'));
+ $data = array(
+ 'caption' => 'Installed packages, channel ' . $channel . ':',
+ 'border' => true,
+ 'headline' => array('Package', 'Version', 'State'),
+ 'channel' => $channel
+ );
+
+ foreach ($packages as $package) {
+ $p = isset($package['package']) ? $package['package'] : $package['name'];
+ $pobj = $reg->getPackage($p, $channel);
+ $data['data'][] = array($pobj->getPackage(), $pobj->getVersion(),
+ $pobj->getState() ? $pobj->getState() : null);
+ }
+
+ // Adds a blank line after each section
+ $data['data'][] = array();
+
+ if (count($packages) === 0) {
+ $data = array(
+ 'caption' => 'Installed packages, channel ' . $channel . ':',
+ 'border' => true,
+ 'data' => array(array('(no packages installed)'), array()),
+ 'channel' => $channel
+ );
+ }
+ $this->ui->outputData($data, $command);
+ }
+ return true;
+ }
+
+ function doFileList($command, $options, $params)
+ {
+ if (count($params) !== 1) {
+ return $this->raiseError('list-files expects 1 parameter');
+ }
+
+ $reg = &$this->config->getRegistry();
+ $fp = false;
+ if (!is_dir($params[0]) && (file_exists($params[0]) || $fp = @fopen($params[0], 'r'))) {
+ if ($fp) {
+ fclose($fp);
+ }
+
+ if (!class_exists('PEAR_PackageFile')) {
+ require_once 'PEAR/PackageFile.php';
+ }
+
+ $pkg = new PEAR_PackageFile($this->config, $this->_debug);
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $info = &$pkg->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
+ PEAR::staticPopErrorHandling();
+ $headings = array('Package File', 'Install Path');
+ $installed = false;
+ } else {
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel'));
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($parsed)) {
+ return $this->raiseError($parsed);
+ }
+
+ $info = &$reg->getPackage($parsed['package'], $parsed['channel']);
+ $headings = array('Type', 'Install Path');
+ $installed = true;
+ }
+
+ if (PEAR::isError($info)) {
+ return $this->raiseError($info);
+ }
+
+ if ($info === null) {
+ return $this->raiseError("`$params[0]' not installed");
+ }
+
+ $list = ($info->getPackagexmlVersion() == '1.0' || $installed) ?
+ $info->getFilelist() : $info->getContents();
+ if ($installed) {
+ $caption = 'Installed Files For ' . $params[0];
+ } else {
+ $caption = 'Contents of ' . basename($params[0]);
+ }
+
+ $data = array(
+ 'caption' => $caption,
+ 'border' => true,
+ 'headline' => $headings);
+ if ($info->getPackagexmlVersion() == '1.0' || $installed) {
+ foreach ($list as $file => $att) {
+ if ($installed) {
+ if (empty($att['installed_as'])) {
+ continue;
+ }
+ $data['data'][] = array($att['role'], $att['installed_as']);
+ } else {
+ if (isset($att['baseinstalldir']) && !in_array($att['role'],
+ array('test', 'data', 'doc'))) {
+ $dest = $att['baseinstalldir'] . DIRECTORY_SEPARATOR .
+ $file;
+ } else {
+ $dest = $file;
+ }
+ switch ($att['role']) {
+ case 'test':
+ case 'data':
+ case 'doc':
+ $role = $att['role'];
+ if ($role == 'test') {
+ $role .= 's';
+ }
+ $dest = $this->config->get($role . '_dir') . DIRECTORY_SEPARATOR .
+ $info->getPackage() . DIRECTORY_SEPARATOR . $dest;
+ break;
+ case 'php':
+ default:
+ $dest = $this->config->get('php_dir') . DIRECTORY_SEPARATOR .
+ $dest;
+ }
+ $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR;
+ $dest = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"),
+ array(DIRECTORY_SEPARATOR,
+ DIRECTORY_SEPARATOR,
+ DIRECTORY_SEPARATOR),
+ $dest);
+ $file = preg_replace('!/+!', '/', $file);
+ $data['data'][] = array($file, $dest);
+ }
+ }
+ } else { // package.xml 2.0, not installed
+ if (!isset($list['dir']['file'][0])) {
+ $list['dir']['file'] = array($list['dir']['file']);
+ }
+
+ foreach ($list['dir']['file'] as $att) {
+ $att = $att['attribs'];
+ $file = $att['name'];
+ $role = &PEAR_Installer_Role::factory($info, $att['role'], $this->config);
+ $role->setup($this, $info, $att, $file);
+ if (!$role->isInstallable()) {
+ $dest = '(not installable)';
+ } else {
+ $dest = $role->processInstallation($info, $att, $file, '');
+ if (PEAR::isError($dest)) {
+ $dest = '(Unknown role "' . $att['role'] . ')';
+ } else {
+ list(,, $dest) = $dest;
+ }
+ }
+ $data['data'][] = array($file, $dest);
+ }
+ }
+
+ $this->ui->outputData($data, $command);
+ return true;
+ }
+
+ function doShellTest($command, $options, $params)
+ {
+ if (count($params) < 1) {
+ return PEAR::raiseError('ERROR, usage: pear shell-test packagename [[relation] version]');
+ }
+
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $reg = &$this->config->getRegistry();
+ $info = $reg->parsePackageName($params[0], $this->config->get('default_channel'));
+ if (PEAR::isError($info)) {
+ exit(1); // invalid package name
+ }
+
+ $package = $info['package'];
+ $channel = $info['channel'];
+ // "pear shell-test Foo"
+ if (!$reg->packageExists($package, $channel)) {
+ if ($channel == 'pecl.php.net') {
+ if ($reg->packageExists($package, 'pear.php.net')) {
+ $channel = 'pear.php.net'; // magically change channels for extensions
+ }
+ }
+ }
+
+ if (count($params) === 1) {
+ if (!$reg->packageExists($package, $channel)) {
+ exit(1);
+ }
+ // "pear shell-test Foo 1.0"
+ } elseif (count($params) === 2) {
+ $v = $reg->packageInfo($package, 'version', $channel);
+ if (!$v || !version_compare("$v", "{$params[1]}", "ge")) {
+ exit(1);
+ }
+ // "pear shell-test Foo ge 1.0"
+ } elseif (count($params) === 3) {
+ $v = $reg->packageInfo($package, 'version', $channel);
+ if (!$v || !version_compare("$v", "{$params[2]}", $params[1])) {
+ exit(1);
+ }
+ } else {
+ PEAR::staticPopErrorHandling();
+ $this->raiseError("$command: expects 1 to 3 parameters");
+ exit(1);
+ }
+ }
+
+ function doInfo($command, $options, $params)
+ {
+ if (count($params) !== 1) {
+ return $this->raiseError('pear info expects 1 parameter');
+ }
+
+ $info = $fp = false;
+ $reg = &$this->config->getRegistry();
+ if (is_file($params[0]) && !is_dir($params[0]) &&
+ (file_exists($params[0]) || $fp = @fopen($params[0], 'r'))
+ ) {
+ if ($fp) {
+ fclose($fp);
+ }
+
+ if (!class_exists('PEAR_PackageFile')) {
+ require_once 'PEAR/PackageFile.php';
+ }
+
+ $pkg = new PEAR_PackageFile($this->config, $this->_debug);
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $obj = &$pkg->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($obj)) {
+ $uinfo = $obj->getUserInfo();
+ if (is_array($uinfo)) {
+ foreach ($uinfo as $message) {
+ if (is_array($message)) {
+ $message = $message['message'];
+ }
+ $this->ui->outputData($message);
+ }
+ }
+
+ return $this->raiseError($obj);
+ }
+
+ if ($obj->getPackagexmlVersion() != '1.0') {
+ return $this->_doInfo2($command, $options, $params, $obj, false);
+ }
+
+ $info = $obj->toArray();
+ } else {
+ $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel'));
+ if (PEAR::isError($parsed)) {
+ return $this->raiseError($parsed);
+ }
+
+ $package = $parsed['package'];
+ $channel = $parsed['channel'];
+ $info = $reg->packageInfo($package, null, $channel);
+ if (isset($info['old'])) {
+ $obj = $reg->getPackage($package, $channel);
+ return $this->_doInfo2($command, $options, $params, $obj, true);
+ }
+ }
+
+ if (PEAR::isError($info)) {
+ return $info;
+ }
+
+ if (empty($info)) {
+ $this->raiseError("No information found for `$params[0]'");
+ return;
+ }
+
+ unset($info['filelist']);
+ unset($info['dirtree']);
+ unset($info['changelog']);
+ if (isset($info['xsdversion'])) {
+ $info['package.xml version'] = $info['xsdversion'];
+ unset($info['xsdversion']);
+ }
+
+ if (isset($info['packagerversion'])) {
+ $info['packaged with PEAR version'] = $info['packagerversion'];
+ unset($info['packagerversion']);
+ }
+
+ $keys = array_keys($info);
+ $longtext = array('description', 'summary');
+ foreach ($keys as $key) {
+ if (is_array($info[$key])) {
+ switch ($key) {
+ case 'maintainers': {
+ $i = 0;
+ $mstr = '';
+ foreach ($info[$key] as $m) {
+ if ($i++ > 0) {
+ $mstr .= "\n";
+ }
+ $mstr .= $m['name'] . " <";
+ if (isset($m['email'])) {
+ $mstr .= $m['email'];
+ } else {
+ $mstr .= $m['handle'] . '@php.net';
+ }
+ $mstr .= "> ($m[role])";
+ }
+ $info[$key] = $mstr;
+ break;
+ }
+ case 'release_deps': {
+ $i = 0;
+ $dstr = '';
+ foreach ($info[$key] as $d) {
+ if (isset($this->_deps_rel_trans[$d['rel']])) {
+ $rel = $this->_deps_rel_trans[$d['rel']];
+ } else {
+ $rel = $d['rel'];
+ }
+ if (isset($this->_deps_type_trans[$d['type']])) {
+ $type = ucfirst($this->_deps_type_trans[$d['type']]);
+ } else {
+ $type = $d['type'];
+ }
+ if (isset($d['name'])) {
+ $name = $d['name'] . ' ';
+ } else {
+ $name = '';
+ }
+ if (isset($d['version'])) {
+ $version = $d['version'] . ' ';
+ } else {
+ $version = '';
+ }
+ if (isset($d['optional']) && $d['optional'] == 'yes') {
+ $optional = ' (optional)';
+ } else {
+ $optional = '';
+ }
+ $dstr .= "$type $name$rel $version$optional\n";
+ }
+ $info[$key] = $dstr;
+ break;
+ }
+ case 'provides' : {
+ $debug = $this->config->get('verbose');
+ if ($debug < 2) {
+ $pstr = 'Classes: ';
+ } else {
+ $pstr = '';
+ }
+ $i = 0;
+ foreach ($info[$key] as $p) {
+ if ($debug < 2 && $p['type'] != "class") {
+ continue;
+ }
+ // Only print classes when verbosity mode is < 2
+ if ($debug < 2) {
+ if ($i++ > 0) {
+ $pstr .= ", ";
+ }
+ $pstr .= $p['name'];
+ } else {
+ if ($i++ > 0) {
+ $pstr .= "\n";
+ }
+ $pstr .= ucfirst($p['type']) . " " . $p['name'];
+ if (isset($p['explicit']) && $p['explicit'] == 1) {
+ $pstr .= " (explicit)";
+ }
+ }
+ }
+ $info[$key] = $pstr;
+ break;
+ }
+ case 'configure_options' : {
+ foreach ($info[$key] as $i => $p) {
+ $info[$key][$i] = array_map(null, array_keys($p), array_values($p));
+ $info[$key][$i] = array_map(create_function('$a',
+ 'return join(" = ",$a);'), $info[$key][$i]);
+ $info[$key][$i] = implode(', ', $info[$key][$i]);
+ }
+ $info[$key] = implode("\n", $info[$key]);
+ break;
+ }
+ default: {
+ $info[$key] = implode(", ", $info[$key]);
+ break;
+ }
+ }
+ }
+
+ if ($key == '_lastmodified') {
+ $hdate = date('Y-m-d', $info[$key]);
+ unset($info[$key]);
+ $info['Last Modified'] = $hdate;
+ } elseif ($key == '_lastversion') {
+ $info['Previous Installed Version'] = $info[$key] ? $info[$key] : '- None -';
+ unset($info[$key]);
+ } else {
+ $info[$key] = trim($info[$key]);
+ if (in_array($key, $longtext)) {
+ $info[$key] = preg_replace('/ +/', ' ', $info[$key]);
+ }
+ }
+ }
+
+ $caption = 'About ' . $info['package'] . '-' . $info['version'];
+ $data = array(
+ 'caption' => $caption,
+ 'border' => true);
+ foreach ($info as $key => $value) {
+ $key = ucwords(trim(str_replace('_', ' ', $key)));
+ $data['data'][] = array($key, $value);
+ }
+ $data['raw'] = $info;
+
+ $this->ui->outputData($data, 'package-info');
+ }
+
+ /**
+ * @access private
+ */
+ function _doInfo2($command, $options, $params, &$obj, $installed)
+ {
+ $reg = &$this->config->getRegistry();
+ $caption = 'About ' . $obj->getChannel() . '/' .$obj->getPackage() . '-' .
+ $obj->getVersion();
+ $data = array(
+ 'caption' => $caption,
+ 'border' => true);
+ switch ($obj->getPackageType()) {
+ case 'php' :
+ $release = 'PEAR-style PHP-based Package';
+ break;
+ case 'extsrc' :
+ $release = 'PECL-style PHP extension (source code)';
+ break;
+ case 'zendextsrc' :
+ $release = 'PECL-style Zend extension (source code)';
+ break;
+ case 'extbin' :
+ $release = 'PECL-style PHP extension (binary)';
+ break;
+ case 'zendextbin' :
+ $release = 'PECL-style Zend extension (binary)';
+ break;
+ case 'bundle' :
+ $release = 'Package bundle (collection of packages)';
+ break;
+ }
+ $extends = $obj->getExtends();
+ $extends = $extends ?
+ $obj->getPackage() . ' (extends ' . $extends . ')' : $obj->getPackage();
+ if ($src = $obj->getSourcePackage()) {
+ $extends .= ' (source package ' . $src['channel'] . '/' . $src['package'] . ')';
+ }
+
+ $info = array(
+ 'Release Type' => $release,
+ 'Name' => $extends,
+ 'Channel' => $obj->getChannel(),
+ 'Summary' => preg_replace('/ +/', ' ', $obj->getSummary()),
+ 'Description' => preg_replace('/ +/', ' ', $obj->getDescription()),
+ );
+ $info['Maintainers'] = '';
+ foreach (array('lead', 'developer', 'contributor', 'helper') as $role) {
+ $leads = $obj->{"get{$role}s"}();
+ if (!$leads) {
+ continue;
+ }
+
+ if (isset($leads['active'])) {
+ $leads = array($leads);
+ }
+
+ foreach ($leads as $lead) {
+ if (!empty($info['Maintainers'])) {
+ $info['Maintainers'] .= "\n";
+ }
+
+ $active = $lead['active'] == 'no' ? ', inactive' : '';
+ $info['Maintainers'] .= $lead['name'] . ' <';
+ $info['Maintainers'] .= $lead['email'] . "> ($role$active)";
+ }
+ }
+
+ $info['Release Date'] = $obj->getDate();
+ if ($time = $obj->getTime()) {
+ $info['Release Date'] .= ' ' . $time;
+ }
+
+ $info['Release Version'] = $obj->getVersion() . ' (' . $obj->getState() . ')';
+ $info['API Version'] = $obj->getVersion('api') . ' (' . $obj->getState('api') . ')';
+ $info['License'] = $obj->getLicense();
+ $uri = $obj->getLicenseLocation();
+ if ($uri) {
+ if (isset($uri['uri'])) {
+ $info['License'] .= ' (' . $uri['uri'] . ')';
+ } else {
+ $extra = $obj->getInstalledLocation($info['filesource']);
+ if ($extra) {
+ $info['License'] .= ' (' . $uri['filesource'] . ')';
+ }
+ }
+ }
+
+ $info['Release Notes'] = $obj->getNotes();
+ if ($compat = $obj->getCompatible()) {
+ if (!isset($compat[0])) {
+ $compat = array($compat);
+ }
+
+ $info['Compatible with'] = '';
+ foreach ($compat as $package) {
+ $info['Compatible with'] .= $package['channel'] . '/' . $package['name'] .
+ "\nVersions >= " . $package['min'] . ', <= ' . $package['max'];
+ if (isset($package['exclude'])) {
+ if (is_array($package['exclude'])) {
+ $package['exclude'] = implode(', ', $package['exclude']);
+ }
+
+ if (!isset($info['Not Compatible with'])) {
+ $info['Not Compatible with'] = '';
+ } else {
+ $info['Not Compatible with'] .= "\n";
+ }
+ $info['Not Compatible with'] .= $package['channel'] . '/' .
+ $package['name'] . "\nVersions " . $package['exclude'];
+ }
+ }
+ }
+
+ $usesrole = $obj->getUsesrole();
+ if ($usesrole) {
+ if (!isset($usesrole[0])) {
+ $usesrole = array($usesrole);
+ }
+
+ foreach ($usesrole as $roledata) {
+ if (isset($info['Uses Custom Roles'])) {
+ $info['Uses Custom Roles'] .= "\n";
+ } else {
+ $info['Uses Custom Roles'] = '';
+ }
+
+ if (isset($roledata['package'])) {
+ $rolepackage = $reg->parsedPackageNameToString($roledata, true);
+ } else {
+ $rolepackage = $roledata['uri'];
+ }
+ $info['Uses Custom Roles'] .= $roledata['role'] . ' (' . $rolepackage . ')';
+ }
+ }
+
+ $usestask = $obj->getUsestask();
+ if ($usestask) {
+ if (!isset($usestask[0])) {
+ $usestask = array($usestask);
+ }
+
+ foreach ($usestask as $taskdata) {
+ if (isset($info['Uses Custom Tasks'])) {
+ $info['Uses Custom Tasks'] .= "\n";
+ } else {
+ $info['Uses Custom Tasks'] = '';
+ }
+
+ if (isset($taskdata['package'])) {
+ $taskpackage = $reg->parsedPackageNameToString($taskdata, true);
+ } else {
+ $taskpackage = $taskdata['uri'];
+ }
+ $info['Uses Custom Tasks'] .= $taskdata['task'] . ' (' . $taskpackage . ')';
+ }
+ }
+
+ $deps = $obj->getDependencies();
+ $info['Required Dependencies'] = 'PHP version ' . $deps['required']['php']['min'];
+ if (isset($deps['required']['php']['max'])) {
+ $info['Required Dependencies'] .= '-' . $deps['required']['php']['max'] . "\n";
+ } else {
+ $info['Required Dependencies'] .= "\n";
+ }
+
+ if (isset($deps['required']['php']['exclude'])) {
+ if (!isset($info['Not Compatible with'])) {
+ $info['Not Compatible with'] = '';
+ } else {
+ $info['Not Compatible with'] .= "\n";
+ }
+
+ if (is_array($deps['required']['php']['exclude'])) {
+ $deps['required']['php']['exclude'] =
+ implode(', ', $deps['required']['php']['exclude']);
+ }
+ $info['Not Compatible with'] .= "PHP versions\n " .
+ $deps['required']['php']['exclude'];
+ }
+
+ $info['Required Dependencies'] .= 'PEAR installer version';
+ if (isset($deps['required']['pearinstaller']['max'])) {
+ $info['Required Dependencies'] .= 's ' .
+ $deps['required']['pearinstaller']['min'] . '-' .
+ $deps['required']['pearinstaller']['max'];
+ } else {
+ $info['Required Dependencies'] .= ' ' .
+ $deps['required']['pearinstaller']['min'] . ' or newer';
+ }
+
+ if (isset($deps['required']['pearinstaller']['exclude'])) {
+ if (!isset($info['Not Compatible with'])) {
+ $info['Not Compatible with'] = '';
+ } else {
+ $info['Not Compatible with'] .= "\n";
+ }
+
+ if (is_array($deps['required']['pearinstaller']['exclude'])) {
+ $deps['required']['pearinstaller']['exclude'] =
+ implode(', ', $deps['required']['pearinstaller']['exclude']);
+ }
+ $info['Not Compatible with'] .= "PEAR installer\n Versions " .
+ $deps['required']['pearinstaller']['exclude'];
+ }
+
+ foreach (array('Package', 'Extension') as $type) {
+ $index = strtolower($type);
+ if (isset($deps['required'][$index])) {
+ if (isset($deps['required'][$index]['name'])) {
+ $deps['required'][$index] = array($deps['required'][$index]);
+ }
+
+ foreach ($deps['required'][$index] as $package) {
+ if (isset($package['conflicts'])) {
+ $infoindex = 'Not Compatible with';
+ if (!isset($info['Not Compatible with'])) {
+ $info['Not Compatible with'] = '';
+ } else {
+ $info['Not Compatible with'] .= "\n";
+ }
+ } else {
+ $infoindex = 'Required Dependencies';
+ $info[$infoindex] .= "\n";
+ }
+
+ if ($index == 'extension') {
+ $name = $package['name'];
+ } else {
+ if (isset($package['channel'])) {
+ $name = $package['channel'] . '/' . $package['name'];
+ } else {
+ $name = '__uri/' . $package['name'] . ' (static URI)';
+ }
+ }
+
+ $info[$infoindex] .= "$type $name";
+ if (isset($package['uri'])) {
+ $info[$infoindex] .= "\n Download URI: $package[uri]";
+ continue;
+ }
+
+ if (isset($package['max']) && isset($package['min'])) {
+ $info[$infoindex] .= " \n Versions " .
+ $package['min'] . '-' . $package['max'];
+ } elseif (isset($package['min'])) {
+ $info[$infoindex] .= " \n Version " .
+ $package['min'] . ' or newer';
+ } elseif (isset($package['max'])) {
+ $info[$infoindex] .= " \n Version " .
+ $package['max'] . ' or older';
+ }
+
+ if (isset($package['recommended'])) {
+ $info[$infoindex] .= "\n Recommended version: $package[recommended]";
+ }
+
+ if (isset($package['exclude'])) {
+ if (!isset($info['Not Compatible with'])) {
+ $info['Not Compatible with'] = '';
+ } else {
+ $info['Not Compatible with'] .= "\n";
+ }
+
+ if (is_array($package['exclude'])) {
+ $package['exclude'] = implode(', ', $package['exclude']);
+ }
+
+ $package['package'] = $package['name']; // for parsedPackageNameToString
+ if (isset($package['conflicts'])) {
+ $info['Not Compatible with'] .= '=> except ';
+ }
+ $info['Not Compatible with'] .= 'Package ' .
+ $reg->parsedPackageNameToString($package, true);
+ $info['Not Compatible with'] .= "\n Versions " . $package['exclude'];
+ }
+ }
+ }
+ }
+
+ if (isset($deps['required']['os'])) {
+ if (isset($deps['required']['os']['name'])) {
+ $dep['required']['os']['name'] = array($dep['required']['os']['name']);
+ }
+
+ foreach ($dep['required']['os'] as $os) {
+ if (isset($os['conflicts']) && $os['conflicts'] == 'yes') {
+ if (!isset($info['Not Compatible with'])) {
+ $info['Not Compatible with'] = '';
+ } else {
+ $info['Not Compatible with'] .= "\n";
+ }
+ $info['Not Compatible with'] .= "$os[name] Operating System";
+ } else {
+ $info['Required Dependencies'] .= "\n";
+ $info['Required Dependencies'] .= "$os[name] Operating System";
+ }
+ }
+ }
+
+ if (isset($deps['required']['arch'])) {
+ if (isset($deps['required']['arch']['pattern'])) {
+ $dep['required']['arch']['pattern'] = array($dep['required']['os']['pattern']);
+ }
+
+ foreach ($dep['required']['arch'] as $os) {
+ if (isset($os['conflicts']) && $os['conflicts'] == 'yes') {
+ if (!isset($info['Not Compatible with'])) {
+ $info['Not Compatible with'] = '';
+ } else {
+ $info['Not Compatible with'] .= "\n";
+ }
+ $info['Not Compatible with'] .= "OS/Arch matching pattern '/$os[pattern]/'";
+ } else {
+ $info['Required Dependencies'] .= "\n";
+ $info['Required Dependencies'] .= "OS/Arch matching pattern '/$os[pattern]/'";
+ }
+ }
+ }
+
+ if (isset($deps['optional'])) {
+ foreach (array('Package', 'Extension') as $type) {
+ $index = strtolower($type);
+ if (isset($deps['optional'][$index])) {
+ if (isset($deps['optional'][$index]['name'])) {
+ $deps['optional'][$index] = array($deps['optional'][$index]);
+ }
+
+ foreach ($deps['optional'][$index] as $package) {
+ if (isset($package['conflicts']) && $package['conflicts'] == 'yes') {
+ $infoindex = 'Not Compatible with';
+ if (!isset($info['Not Compatible with'])) {
+ $info['Not Compatible with'] = '';
+ } else {
+ $info['Not Compatible with'] .= "\n";
+ }
+ } else {
+ $infoindex = 'Optional Dependencies';
+ if (!isset($info['Optional Dependencies'])) {
+ $info['Optional Dependencies'] = '';
+ } else {
+ $info['Optional Dependencies'] .= "\n";
+ }
+ }
+
+ if ($index == 'extension') {
+ $name = $package['name'];
+ } else {
+ if (isset($package['channel'])) {
+ $name = $package['channel'] . '/' . $package['name'];
+ } else {
+ $name = '__uri/' . $package['name'] . ' (static URI)';
+ }
+ }
+
+ $info[$infoindex] .= "$type $name";
+ if (isset($package['uri'])) {
+ $info[$infoindex] .= "\n Download URI: $package[uri]";
+ continue;
+ }
+
+ if ($infoindex == 'Not Compatible with') {
+ // conflicts is only used to say that all versions conflict
+ continue;
+ }
+
+ if (isset($package['max']) && isset($package['min'])) {
+ $info[$infoindex] .= " \n Versions " .
+ $package['min'] . '-' . $package['max'];
+ } elseif (isset($package['min'])) {
+ $info[$infoindex] .= " \n Version " .
+ $package['min'] . ' or newer';
+ } elseif (isset($package['max'])) {
+ $info[$infoindex] .= " \n Version " .
+ $package['min'] . ' or older';
+ }
+
+ if (isset($package['recommended'])) {
+ $info[$infoindex] .= "\n Recommended version: $package[recommended]";
+ }
+
+ if (isset($package['exclude'])) {
+ if (!isset($info['Not Compatible with'])) {
+ $info['Not Compatible with'] = '';
+ } else {
+ $info['Not Compatible with'] .= "\n";
+ }
+
+ if (is_array($package['exclude'])) {
+ $package['exclude'] = implode(', ', $package['exclude']);
+ }
+
+ $info['Not Compatible with'] .= "Package $package\n Versions " .
+ $package['exclude'];
+ }
+ }
+ }
+ }
+ }
+
+ if (isset($deps['group'])) {
+ if (!isset($deps['group'][0])) {
+ $deps['group'] = array($deps['group']);
+ }
+
+ foreach ($deps['group'] as $group) {
+ $info['Dependency Group ' . $group['attribs']['name']] = $group['attribs']['hint'];
+ $groupindex = $group['attribs']['name'] . ' Contents';
+ $info[$groupindex] = '';
+ foreach (array('Package', 'Extension') as $type) {
+ $index = strtolower($type);
+ if (isset($group[$index])) {
+ if (isset($group[$index]['name'])) {
+ $group[$index] = array($group[$index]);
+ }
+
+ foreach ($group[$index] as $package) {
+ if (!empty($info[$groupindex])) {
+ $info[$groupindex] .= "\n";
+ }
+
+ if ($index == 'extension') {
+ $name = $package['name'];
+ } else {
+ if (isset($package['channel'])) {
+ $name = $package['channel'] . '/' . $package['name'];
+ } else {
+ $name = '__uri/' . $package['name'] . ' (static URI)';
+ }
+ }
+
+ if (isset($package['uri'])) {
+ if (isset($package['conflicts']) && $package['conflicts'] == 'yes') {
+ $info[$groupindex] .= "Not Compatible with $type $name";
+ } else {
+ $info[$groupindex] .= "$type $name";
+ }
+
+ $info[$groupindex] .= "\n Download URI: $package[uri]";
+ continue;
+ }
+
+ if (isset($package['conflicts']) && $package['conflicts'] == 'yes') {
+ $info[$groupindex] .= "Not Compatible with $type $name";
+ continue;
+ }
+
+ $info[$groupindex] .= "$type $name";
+ if (isset($package['max']) && isset($package['min'])) {
+ $info[$groupindex] .= " \n Versions " .
+ $package['min'] . '-' . $package['max'];
+ } elseif (isset($package['min'])) {
+ $info[$groupindex] .= " \n Version " .
+ $package['min'] . ' or newer';
+ } elseif (isset($package['max'])) {
+ $info[$groupindex] .= " \n Version " .
+ $package['min'] . ' or older';
+ }
+
+ if (isset($package['recommended'])) {
+ $info[$groupindex] .= "\n Recommended version: $package[recommended]";
+ }
+
+ if (isset($package['exclude'])) {
+ if (!isset($info['Not Compatible with'])) {
+ $info['Not Compatible with'] = '';
+ } else {
+ $info[$groupindex] .= "Not Compatible with\n";
+ }
+
+ if (is_array($package['exclude'])) {
+ $package['exclude'] = implode(', ', $package['exclude']);
+ }
+ $info[$groupindex] .= " Package $package\n Versions " .
+ $package['exclude'];
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if ($obj->getPackageType() == 'bundle') {
+ $info['Bundled Packages'] = '';
+ foreach ($obj->getBundledPackages() as $package) {
+ if (!empty($info['Bundled Packages'])) {
+ $info['Bundled Packages'] .= "\n";
+ }
+
+ if (isset($package['uri'])) {
+ $info['Bundled Packages'] .= '__uri/' . $package['name'];
+ $info['Bundled Packages'] .= "\n (URI: $package[uri]";
+ } else {
+ $info['Bundled Packages'] .= $package['channel'] . '/' . $package['name'];
+ }
+ }
+ }
+
+ $info['package.xml version'] = '2.0';
+ if ($installed) {
+ if ($obj->getLastModified()) {
+ $info['Last Modified'] = date('Y-m-d H:i', $obj->getLastModified());
+ }
+
+ $v = $obj->getLastInstalledVersion();
+ $info['Previous Installed Version'] = $v ? $v : '- None -';
+ }
+
+ foreach ($info as $key => $value) {
+ $data['data'][] = array($key, $value);
+ }
+
+ $data['raw'] = $obj->getArray(); // no validation needed
+ $this->ui->outputData($data, 'package-info');
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Command/Registry.xml b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Registry.xml
new file mode 100644
index 000000000..9f4e21496
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Registry.xml
@@ -0,0 +1,58 @@
+
+
+ List Installed Packages In The Default Channel
+ doList
+ l
+
+
+ c
+ list installed packages from this channel
+ CHAN
+
+
+ a
+ list installed packages from all channels
+
+
+ i
+ output fully channel-aware data, even on failure
+
+
+ <package>
+If invoked without parameters, this command lists the PEAR packages
+installed in your php_dir ({config php_dir}). With a parameter, it
+lists the files in a package.
+
+
+
+ List Files In Installed Package
+ doFileList
+ fl
+
+ <package>
+List the files in an installed package.
+
+
+
+ Shell Script Test
+ doShellTest
+ st
+
+ <package> [[relation] version]
+Tests if a package is installed in the system. Will exit(1) if it is not.
+ <relation> The version comparison operator. One of:
+ <, lt, <=, le, >, gt, >=, ge, ==, =, eq, !=, <>, ne
+ <version> The version to compare with
+
+
+
+ Display information about a package
+ doInfo
+ in
+
+ <package>
+Displays information about a package. The package argument may be a
+local package file, an URL to a package file, or the name of an
+installed package.
+
+
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Command/Remote.php b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Remote.php
new file mode 100644
index 000000000..c0a8e92a8
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Remote.php
@@ -0,0 +1,809 @@
+
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ */
+
+/**
+ * base class
+ */
+require_once 'PEAR/Command/Common.php';
+require_once 'PEAR/REST.php';
+
+/**
+ * PEAR commands for remote server querying
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 0.1
+ */
+class PEAR_Command_Remote extends PEAR_Command_Common
+{
+ var $commands = array(
+ 'remote-info' => array(
+ 'summary' => 'Information About Remote Packages',
+ 'function' => 'doRemoteInfo',
+ 'shortcut' => 'ri',
+ 'options' => array(),
+ 'doc' => '
+Get details on a package from the server.',
+ ),
+ 'list-upgrades' => array(
+ 'summary' => 'List Available Upgrades',
+ 'function' => 'doListUpgrades',
+ 'shortcut' => 'lu',
+ 'options' => array(
+ 'channelinfo' => array(
+ 'shortopt' => 'i',
+ 'doc' => 'output fully channel-aware data, even on failure',
+ ),
+ ),
+ 'doc' => '[preferred_state]
+List releases on the server of packages you have installed where
+a newer version is available with the same release state (stable etc.)
+or the state passed as the second parameter.'
+ ),
+ 'remote-list' => array(
+ 'summary' => 'List Remote Packages',
+ 'function' => 'doRemoteList',
+ 'shortcut' => 'rl',
+ 'options' => array(
+ 'channel' =>
+ array(
+ 'shortopt' => 'c',
+ 'doc' => 'specify a channel other than the default channel',
+ 'arg' => 'CHAN',
+ )
+ ),
+ 'doc' => '
+Lists the packages available on the configured server along with the
+latest stable release of each package.',
+ ),
+ 'search' => array(
+ 'summary' => 'Search remote package database',
+ 'function' => 'doSearch',
+ 'shortcut' => 'sp',
+ 'options' => array(
+ 'channel' =>
+ array(
+ 'shortopt' => 'c',
+ 'doc' => 'specify a channel other than the default channel',
+ 'arg' => 'CHAN',
+ ),
+ 'allchannels' => array(
+ 'shortopt' => 'a',
+ 'doc' => 'search packages from all known channels',
+ ),
+ 'channelinfo' => array(
+ 'shortopt' => 'i',
+ 'doc' => 'output fully channel-aware data, even on failure',
+ ),
+ ),
+ 'doc' => '[packagename] [packageinfo]
+Lists all packages which match the search parameters. The first
+parameter is a fragment of a packagename. The default channel
+will be used unless explicitly overridden. The second parameter
+will be used to match any portion of the summary/description',
+ ),
+ 'list-all' => array(
+ 'summary' => 'List All Packages',
+ 'function' => 'doListAll',
+ 'shortcut' => 'la',
+ 'options' => array(
+ 'channel' =>
+ array(
+ 'shortopt' => 'c',
+ 'doc' => 'specify a channel other than the default channel',
+ 'arg' => 'CHAN',
+ ),
+ 'channelinfo' => array(
+ 'shortopt' => 'i',
+ 'doc' => 'output fully channel-aware data, even on failure',
+ ),
+ ),
+ 'doc' => '
+Lists the packages available on the configured server along with the
+latest stable release of each package.',
+ ),
+ 'download' => array(
+ 'summary' => 'Download Package',
+ 'function' => 'doDownload',
+ 'shortcut' => 'd',
+ 'options' => array(
+ 'nocompress' => array(
+ 'shortopt' => 'Z',
+ 'doc' => 'download an uncompressed (.tar) file',
+ ),
+ ),
+ 'doc' => '...
+Download package tarballs. The files will be named as suggested by the
+server, for example if you download the DB package and the latest stable
+version of DB is 1.6.5, the downloaded file will be DB-1.6.5.tgz.',
+ ),
+ 'clear-cache' => array(
+ 'summary' => 'Clear Web Services Cache',
+ 'function' => 'doClearCache',
+ 'shortcut' => 'cc',
+ 'options' => array(),
+ 'doc' => '
+Clear the REST cache. See also the cache_ttl configuration
+parameter.
+',
+ ),
+ );
+
+ /**
+ * PEAR_Command_Remote constructor.
+ *
+ * @access public
+ */
+ function __construct(&$ui, &$config)
+ {
+ parent::__construct($ui, $config);
+ }
+
+ function _checkChannelForStatus($channel, $chan)
+ {
+ if (PEAR::isError($chan)) {
+ $this->raiseError($chan);
+ }
+ if (!is_a($chan, 'PEAR_ChannelFile')) {
+ return $this->raiseError('Internal corruption error: invalid channel "' .
+ $channel . '"');
+ }
+ $rest = new PEAR_REST($this->config);
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $mirror = $this->config->get('preferred_mirror', null,
+ $channel);
+ $a = $rest->downloadHttp('http://' . $channel .
+ '/channel.xml', $chan->lastModified());
+ PEAR::staticPopErrorHandling();
+ if (!PEAR::isError($a) && $a) {
+ $this->ui->outputData('WARNING: channel "' . $channel . '" has ' .
+ 'updated its protocols, use "' . PEAR_RUNTYPE . ' channel-update ' . $channel .
+ '" to update');
+ }
+ }
+
+ function doRemoteInfo($command, $options, $params)
+ {
+ if (sizeof($params) != 1) {
+ return $this->raiseError("$command expects one param: the remote package name");
+ }
+ $savechannel = $channel = $this->config->get('default_channel');
+ $reg = &$this->config->getRegistry();
+ $package = $params[0];
+ $parsed = $reg->parsePackageName($package, $channel);
+ if (PEAR::isError($parsed)) {
+ return $this->raiseError('Invalid package name "' . $package . '"');
+ }
+
+ $channel = $parsed['channel'];
+ $this->config->set('default_channel', $channel);
+ $chan = $reg->getChannel($channel);
+ if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) {
+ return $e;
+ }
+
+ $mirror = $this->config->get('preferred_mirror');
+ if ($chan->supportsREST($mirror) && $base = $chan->getBaseURL('REST1.0', $mirror)) {
+ $rest = &$this->config->getREST('1.0', array());
+ $info = $rest->packageInfo($base, $parsed['package'], $channel);
+ }
+
+ if (!isset($info)) {
+ return $this->raiseError('No supported protocol was found');
+ }
+
+ if (PEAR::isError($info)) {
+ $this->config->set('default_channel', $savechannel);
+ return $this->raiseError($info);
+ }
+
+ if (!isset($info['name'])) {
+ return $this->raiseError('No remote package "' . $package . '" was found');
+ }
+
+ $installed = $reg->packageInfo($info['name'], null, $channel);
+ $info['installed'] = $installed['version'] ? $installed['version'] : '- no -';
+ if (is_array($info['installed'])) {
+ $info['installed'] = $info['installed']['release'];
+ }
+
+ $this->ui->outputData($info, $command);
+ $this->config->set('default_channel', $savechannel);
+
+ return true;
+ }
+
+ function doRemoteList($command, $options, $params)
+ {
+ $savechannel = $channel = $this->config->get('default_channel');
+ $reg = &$this->config->getRegistry();
+ if (isset($options['channel'])) {
+ $channel = $options['channel'];
+ if (!$reg->channelExists($channel)) {
+ return $this->raiseError('Channel "' . $channel . '" does not exist');
+ }
+
+ $this->config->set('default_channel', $channel);
+ }
+
+ $chan = $reg->getChannel($channel);
+ if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) {
+ return $e;
+ }
+
+ $list_options = false;
+ if ($this->config->get('preferred_state') == 'stable') {
+ $list_options = true;
+ }
+
+ $available = array();
+ if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
+ $base = $chan->getBaseURL('REST1.1', $this->config->get('preferred_mirror'))
+ ) {
+ // use faster list-all if available
+ $rest = &$this->config->getREST('1.1', array());
+ $available = $rest->listAll($base, $list_options, true, false, false, $chan->getName());
+ } elseif ($chan->supportsREST($this->config->get('preferred_mirror')) &&
+ $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
+ $rest = &$this->config->getREST('1.0', array());
+ $available = $rest->listAll($base, $list_options, true, false, false, $chan->getName());
+ }
+
+ if (PEAR::isError($available)) {
+ $this->config->set('default_channel', $savechannel);
+ return $this->raiseError($available);
+ }
+
+ $i = $j = 0;
+ $data = array(
+ 'caption' => 'Channel ' . $channel . ' Available packages:',
+ 'border' => true,
+ 'headline' => array('Package', 'Version'),
+ 'channel' => $channel
+ );
+
+ if (count($available) == 0) {
+ $data = '(no packages available yet)';
+ } else {
+ foreach ($available as $name => $info) {
+ $version = (isset($info['stable']) && $info['stable']) ? $info['stable'] : '-n/a-';
+ $data['data'][] = array($name, $version);
+ }
+ }
+ $this->ui->outputData($data, $command);
+ $this->config->set('default_channel', $savechannel);
+ return true;
+ }
+
+ function doListAll($command, $options, $params)
+ {
+ $savechannel = $channel = $this->config->get('default_channel');
+ $reg = &$this->config->getRegistry();
+ if (isset($options['channel'])) {
+ $channel = $options['channel'];
+ if (!$reg->channelExists($channel)) {
+ return $this->raiseError("Channel \"$channel\" does not exist");
+ }
+
+ $this->config->set('default_channel', $channel);
+ }
+
+ $list_options = false;
+ if ($this->config->get('preferred_state') == 'stable') {
+ $list_options = true;
+ }
+
+ $chan = $reg->getChannel($channel);
+ if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) {
+ return $e;
+ }
+
+ if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
+ $base = $chan->getBaseURL('REST1.1', $this->config->get('preferred_mirror'))) {
+ // use faster list-all if available
+ $rest = &$this->config->getREST('1.1', array());
+ $available = $rest->listAll($base, $list_options, false, false, false, $chan->getName());
+ } elseif ($chan->supportsREST($this->config->get('preferred_mirror')) &&
+ $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
+ $rest = &$this->config->getREST('1.0', array());
+ $available = $rest->listAll($base, $list_options, false, false, false, $chan->getName());
+ }
+
+ if (PEAR::isError($available)) {
+ $this->config->set('default_channel', $savechannel);
+ return $this->raiseError('The package list could not be fetched from the remote server. Please try again. (Debug info: "' . $available->getMessage() . '")');
+ }
+
+ $data = array(
+ 'caption' => 'All packages [Channel ' . $channel . ']:',
+ 'border' => true,
+ 'headline' => array('Package', 'Latest', 'Local'),
+ 'channel' => $channel,
+ );
+
+ if (isset($options['channelinfo'])) {
+ // add full channelinfo
+ $data['caption'] = 'Channel ' . $channel . ' All packages:';
+ $data['headline'] = array('Channel', 'Package', 'Latest', 'Local',
+ 'Description', 'Dependencies');
+ }
+ $local_pkgs = $reg->listPackages($channel);
+
+ foreach ($available as $name => $info) {
+ $installed = $reg->packageInfo($name, null, $channel);
+ if (is_array($installed['version'])) {
+ $installed['version'] = $installed['version']['release'];
+ }
+ $desc = $info['summary'];
+ if (isset($params[$name])) {
+ $desc .= "\n\n".$info['description'];
+ }
+ if (isset($options['mode']))
+ {
+ if ($options['mode'] == 'installed' && !isset($installed['version'])) {
+ continue;
+ }
+ if ($options['mode'] == 'notinstalled' && isset($installed['version'])) {
+ continue;
+ }
+ if ($options['mode'] == 'upgrades'
+ && (!isset($installed['version']) || version_compare($installed['version'],
+ $info['stable'], '>='))) {
+ continue;
+ }
+ }
+ $pos = array_search(strtolower($name), $local_pkgs);
+ if ($pos !== false) {
+ unset($local_pkgs[$pos]);
+ }
+
+ if (isset($info['stable']) && !$info['stable']) {
+ $info['stable'] = null;
+ }
+
+ if (isset($options['channelinfo'])) {
+ // add full channelinfo
+ if ($info['stable'] === $info['unstable']) {
+ $state = $info['state'];
+ } else {
+ $state = 'stable';
+ }
+ $latest = $info['stable'].' ('.$state.')';
+ $local = '';
+ if (isset($installed['version'])) {
+ $inst_state = $reg->packageInfo($name, 'release_state', $channel);
+ $local = $installed['version'].' ('.$inst_state.')';
+ }
+
+ $packageinfo = array(
+ $channel,
+ $name,
+ $latest,
+ $local,
+ isset($desc) ? $desc : null,
+ isset($info['deps']) ? $info['deps'] : null,
+ );
+ } else {
+ $packageinfo = array(
+ $reg->channelAlias($channel) . '/' . $name,
+ isset($info['stable']) ? $info['stable'] : null,
+ isset($installed['version']) ? $installed['version'] : null,
+ isset($desc) ? $desc : null,
+ isset($info['deps']) ? $info['deps'] : null,
+ );
+ }
+ $data['data'][$info['category']][] = $packageinfo;
+ }
+
+ if (isset($options['mode']) && in_array($options['mode'], array('notinstalled', 'upgrades'))) {
+ $this->config->set('default_channel', $savechannel);
+ $this->ui->outputData($data, $command);
+ return true;
+ }
+
+ foreach ($local_pkgs as $name) {
+ $info = &$reg->getPackage($name, $channel);
+ $data['data']['Local'][] = array(
+ $reg->channelAlias($channel) . '/' . $info->getPackage(),
+ '',
+ $info->getVersion(),
+ $info->getSummary(),
+ $info->getDeps()
+ );
+ }
+
+ $this->config->set('default_channel', $savechannel);
+ $this->ui->outputData($data, $command);
+ return true;
+ }
+
+ function doSearch($command, $options, $params)
+ {
+ if ((!isset($params[0]) || empty($params[0]))
+ && (!isset($params[1]) || empty($params[1])))
+ {
+ return $this->raiseError('no valid search string supplied');
+ }
+
+ $channelinfo = isset($options['channelinfo']);
+ $reg = &$this->config->getRegistry();
+ if (isset($options['allchannels'])) {
+ // search all channels
+ unset($options['allchannels']);
+ $channels = $reg->getChannels();
+ $errors = array();
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ foreach ($channels as $channel) {
+ if ($channel->getName() != '__uri') {
+ $options['channel'] = $channel->getName();
+ $ret = $this->doSearch($command, $options, $params);
+ if (PEAR::isError($ret)) {
+ $errors[] = $ret;
+ }
+ }
+ }
+
+ PEAR::staticPopErrorHandling();
+ if (count($errors) !== 0) {
+ // for now, only give first error
+ return PEAR::raiseError($errors[0]);
+ }
+
+ return true;
+ }
+
+ $savechannel = $channel = $this->config->get('default_channel');
+ $package = strtolower($params[0]);
+ $summary = isset($params[1]) ? $params[1] : false;
+ if (isset($options['channel'])) {
+ $reg = &$this->config->getRegistry();
+ $channel = $options['channel'];
+ if (!$reg->channelExists($channel)) {
+ return $this->raiseError('Channel "' . $channel . '" does not exist');
+ }
+
+ $this->config->set('default_channel', $channel);
+ }
+
+ $chan = $reg->getChannel($channel);
+ if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) {
+ return $e;
+ }
+
+ if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
+ $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
+ $rest = &$this->config->getREST('1.0', array());
+ $available = $rest->listAll($base, false, false, $package, $summary, $chan->getName());
+ }
+
+ if (PEAR::isError($available)) {
+ $this->config->set('default_channel', $savechannel);
+ return $this->raiseError($available);
+ }
+
+ if (!$available && !$channelinfo) {
+ // clean exit when not found, no error !
+ $data = 'no packages found that match pattern "' . $package . '", for channel '.$channel.'.';
+ $this->ui->outputData($data);
+ $this->config->set('default_channel', $channel);
+ return true;
+ }
+
+ if ($channelinfo) {
+ $data = array(
+ 'caption' => 'Matched packages, channel ' . $channel . ':',
+ 'border' => true,
+ 'headline' => array('Channel', 'Package', 'Stable/(Latest)', 'Local'),
+ 'channel' => $channel
+ );
+ } else {
+ $data = array(
+ 'caption' => 'Matched packages, channel ' . $channel . ':',
+ 'border' => true,
+ 'headline' => array('Package', 'Stable/(Latest)', 'Local'),
+ 'channel' => $channel
+ );
+ }
+
+ if (!$available && $channelinfo) {
+ unset($data['headline']);
+ $data['data'] = 'No packages found that match pattern "' . $package . '".';
+ $available = array();
+ }
+
+ foreach ($available as $name => $info) {
+ $installed = $reg->packageInfo($name, null, $channel);
+ $desc = $info['summary'];
+ if (isset($params[$name]))
+ $desc .= "\n\n".$info['description'];
+
+ if (!isset($info['stable']) || !$info['stable']) {
+ $version_remote = 'none';
+ } else {
+ if ($info['unstable']) {
+ $version_remote = $info['unstable'];
+ } else {
+ $version_remote = $info['stable'];
+ }
+ $version_remote .= ' ('.$info['state'].')';
+ }
+ $version = is_array($installed['version']) ? $installed['version']['release'] :
+ $installed['version'];
+ if ($channelinfo) {
+ $packageinfo = array(
+ $channel,
+ $name,
+ $version_remote,
+ $version,
+ $desc,
+ );
+ } else {
+ $packageinfo = array(
+ $name,
+ $version_remote,
+ $version,
+ $desc,
+ );
+ }
+ $data['data'][$info['category']][] = $packageinfo;
+ }
+
+ $this->ui->outputData($data, $command);
+ $this->config->set('default_channel', $channel);
+ return true;
+ }
+
+ function &getDownloader($options)
+ {
+ if (!class_exists('PEAR_Downloader')) {
+ require_once 'PEAR/Downloader.php';
+ }
+ $a = new PEAR_Downloader($this->ui, $options, $this->config);
+ return $a;
+ }
+
+ function doDownload($command, $options, $params)
+ {
+ // make certain that dependencies are ignored
+ $options['downloadonly'] = 1;
+
+ // eliminate error messages for preferred_state-related errors
+ /* TODO: Should be an option, but until now download does respect
+ preferred state */
+ /* $options['ignorepreferred_state'] = 1; */
+ // eliminate error messages for preferred_state-related errors
+
+ $downloader = &$this->getDownloader($options);
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $e = $downloader->setDownloadDir(getcwd());
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($e)) {
+ return $this->raiseError('Current directory is not writeable, cannot download');
+ }
+
+ $errors = array();
+ $downloaded = array();
+ $err = $downloader->download($params);
+ if (PEAR::isError($err)) {
+ return $err;
+ }
+
+ $errors = $downloader->getErrorMsgs();
+ if (count($errors)) {
+ foreach ($errors as $error) {
+ if ($error !== null) {
+ $this->ui->outputData($error);
+ }
+ }
+
+ return $this->raiseError("$command failed");
+ }
+
+ $downloaded = $downloader->getDownloadedPackages();
+ foreach ($downloaded as $pkg) {
+ $this->ui->outputData("File $pkg[file] downloaded", $command);
+ }
+
+ return true;
+ }
+
+ function downloadCallback($msg, $params = null)
+ {
+ if ($msg == 'done') {
+ $this->bytes_downloaded = $params;
+ }
+ }
+
+ function doListUpgrades($command, $options, $params)
+ {
+ require_once 'PEAR/Common.php';
+ if (isset($params[0]) && !is_array(PEAR_Common::betterStates($params[0]))) {
+ return $this->raiseError($params[0] . ' is not a valid state (stable/beta/alpha/devel/etc.) try "pear help list-upgrades"');
+ }
+
+ $savechannel = $channel = $this->config->get('default_channel');
+ $reg = &$this->config->getRegistry();
+ foreach ($reg->listChannels() as $channel) {
+ $inst = array_flip($reg->listPackages($channel));
+ if (!count($inst)) {
+ continue;
+ }
+
+ if ($channel == '__uri') {
+ continue;
+ }
+
+ $this->config->set('default_channel', $channel);
+ $state = empty($params[0]) ? $this->config->get('preferred_state') : $params[0];
+
+ $caption = $channel . ' Available Upgrades';
+ $chan = $reg->getChannel($channel);
+ if (PEAR::isError($e = $this->_checkChannelForStatus($channel, $chan))) {
+ return $e;
+ }
+
+ $latest = array();
+ $base2 = false;
+ $preferred_mirror = $this->config->get('preferred_mirror');
+ if ($chan->supportsREST($preferred_mirror) &&
+ (
+ ($base2 = $chan->getBaseURL('REST1.3', $preferred_mirror))
+ || ($base = $chan->getBaseURL('REST1.0', $preferred_mirror))
+ )
+
+ ) {
+ if ($base2) {
+ $rest = &$this->config->getREST('1.3', array());
+ $base = $base2;
+ } else {
+ $rest = &$this->config->getREST('1.0', array());
+ }
+
+ if (empty($state) || $state == 'any') {
+ $state = false;
+ } else {
+ $caption .= ' (' . implode(', ', PEAR_Common::betterStates($state, true)) . ')';
+ }
+
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $latest = $rest->listLatestUpgrades($base, $state, $inst, $channel, $reg);
+ PEAR::staticPopErrorHandling();
+ }
+
+ if (PEAR::isError($latest)) {
+ $this->ui->outputData($latest->getMessage());
+ continue;
+ }
+
+ $caption .= ':';
+ if (PEAR::isError($latest)) {
+ $this->config->set('default_channel', $savechannel);
+ return $latest;
+ }
+
+ $data = array(
+ 'caption' => $caption,
+ 'border' => 1,
+ 'headline' => array('Channel', 'Package', 'Local', 'Remote', 'Size'),
+ 'channel' => $channel
+ );
+
+ foreach ((array)$latest as $pkg => $info) {
+ $package = strtolower($pkg);
+ if (!isset($inst[$package])) {
+ // skip packages we don't have installed
+ continue;
+ }
+
+ extract($info);
+ $inst_version = $reg->packageInfo($package, 'version', $channel);
+ $inst_state = $reg->packageInfo($package, 'release_state', $channel);
+ if (version_compare("$version", "$inst_version", "le")) {
+ // installed version is up-to-date
+ continue;
+ }
+
+ if ($filesize >= 20480) {
+ $filesize += 1024 - ($filesize % 1024);
+ $fs = sprintf("%dkB", $filesize / 1024);
+ } elseif ($filesize > 0) {
+ $filesize += 103 - ($filesize % 103);
+ $fs = sprintf("%.1fkB", $filesize / 1024.0);
+ } else {
+ $fs = " -"; // XXX center instead
+ }
+
+ $data['data'][] = array($channel, $pkg, "$inst_version ($inst_state)", "$version ($state)", $fs);
+ }
+
+ if (isset($options['channelinfo'])) {
+ if (empty($data['data'])) {
+ unset($data['headline']);
+ if (count($inst) == 0) {
+ $data['data'] = '(no packages installed)';
+ } else {
+ $data['data'] = '(no upgrades available)';
+ }
+ }
+ $this->ui->outputData($data, $command);
+ } else {
+ if (empty($data['data'])) {
+ $this->ui->outputData('Channel ' . $channel . ': No upgrades available');
+ } else {
+ $this->ui->outputData($data, $command);
+ }
+ }
+ }
+
+ $this->config->set('default_channel', $savechannel);
+ return true;
+ }
+
+ function doClearCache($command, $options, $params)
+ {
+ $cache_dir = $this->config->get('cache_dir');
+ $verbose = $this->config->get('verbose');
+ $output = '';
+ if (!file_exists($cache_dir) || !is_dir($cache_dir)) {
+ return $this->raiseError("$cache_dir does not exist or is not a directory");
+ }
+
+ if (!($dp = @opendir($cache_dir))) {
+ return $this->raiseError("opendir($cache_dir) failed: $php_errormsg");
+ }
+
+ if ($verbose >= 1) {
+ $output .= "reading directory $cache_dir\n";
+ }
+
+ $num = 0;
+ while ($ent = readdir($dp)) {
+ if (preg_match('/rest.cache(file|id)\\z/', $ent)) {
+ $path = $cache_dir . DIRECTORY_SEPARATOR . $ent;
+ if (file_exists($path)) {
+ $ok = @unlink($path);
+ } else {
+ $ok = false;
+ $php_errormsg = '';
+ }
+
+ if ($ok) {
+ if ($verbose >= 2) {
+ $output .= "deleted $path\n";
+ }
+ $num++;
+ } elseif ($verbose >= 1) {
+ $output .= "failed to delete $path $php_errormsg\n";
+ }
+ }
+ }
+
+ closedir($dp);
+ if ($verbose >= 1) {
+ $output .= "$num cache entries cleared\n";
+ }
+
+ $this->ui->outputData(rtrim($output), $command);
+ return $num;
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Command/Remote.xml b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Remote.xml
new file mode 100644
index 000000000..b4f6100c7
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Remote.xml
@@ -0,0 +1,109 @@
+
+
+ Information About Remote Packages
+ doRemoteInfo
+ ri
+
+ <package>
+Get details on a package from the server.
+
+
+ List Available Upgrades
+ doListUpgrades
+ lu
+
+
+ i
+ output fully channel-aware data, even on failure
+
+
+ [preferred_state]
+List releases on the server of packages you have installed where
+a newer version is available with the same release state (stable etc.)
+or the state passed as the second parameter.
+
+
+ List Remote Packages
+ doRemoteList
+ rl
+
+
+ c
+ specify a channel other than the default channel
+ CHAN
+
+
+
+Lists the packages available on the configured server along with the
+latest stable release of each package.
+
+
+ Search remote package database
+ doSearch
+ sp
+
+
+ c
+ specify a channel other than the default channel
+ CHAN
+
+
+ a
+ search packages from all known channels
+
+
+ i
+ output fully channel-aware data, even on failure
+
+
+ [packagename] [packageinfo]
+Lists all packages which match the search parameters. The first
+parameter is a fragment of a packagename. The default channel
+will be used unless explicitly overridden. The second parameter
+will be used to match any portion of the summary/description
+
+
+ List All Packages
+ doListAll
+ la
+
+
+ c
+ specify a channel other than the default channel
+ CHAN
+
+
+ i
+ output fully channel-aware data, even on failure
+
+
+
+Lists the packages available on the configured server along with the
+latest stable release of each package.
+
+
+ Download Package
+ doDownload
+ d
+
+
+ Z
+ download an uncompressed (.tar) file
+
+
+ <package>...
+Download package tarballs. The files will be named as suggested by the
+server, for example if you download the DB package and the latest stable
+version of DB is 1.6.5, the downloaded file will be DB-1.6.5.tgz.
+
+
+ Clear Web Services Cache
+ doClearCache
+ cc
+
+
+Clear the XML-RPC/REST cache. See also the cache_ttl configuration
+parameter.
+
+
+
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Command/Test.php b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Test.php
new file mode 100644
index 000000000..69c72c4aa
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Test.php
@@ -0,0 +1,343 @@
+
+ * @author Martin Jansen
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ */
+
+/**
+ * base class
+ */
+require_once 'PEAR/Command/Common.php';
+
+/**
+ * PEAR commands for login/logout
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Martin Jansen
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 0.1
+ */
+
+class PEAR_Command_Test extends PEAR_Command_Common
+{
+ var $commands = array(
+ 'run-tests' => array(
+ 'summary' => 'Run Regression Tests',
+ 'function' => 'doRunTests',
+ 'shortcut' => 'rt',
+ 'options' => array(
+ 'recur' => array(
+ 'shortopt' => 'r',
+ 'doc' => 'Run tests in child directories, recursively. 4 dirs deep maximum',
+ ),
+ 'ini' => array(
+ 'shortopt' => 'i',
+ 'doc' => 'actual string of settings to pass to php in format " -d setting=blah"',
+ 'arg' => 'SETTINGS'
+ ),
+ 'realtimelog' => array(
+ 'shortopt' => 'l',
+ 'doc' => 'Log test runs/results as they are run',
+ ),
+ 'quiet' => array(
+ 'shortopt' => 'q',
+ 'doc' => 'Only display detail for failed tests',
+ ),
+ 'simple' => array(
+ 'shortopt' => 's',
+ 'doc' => 'Display simple output for all tests',
+ ),
+ 'package' => array(
+ 'shortopt' => 'p',
+ 'doc' => 'Treat parameters as installed packages from which to run tests',
+ ),
+ 'phpunit' => array(
+ 'shortopt' => 'u',
+ 'doc' => 'Search parameters for AllTests.php, and use that to run phpunit-based tests
+If none is found, all .phpt tests will be tried instead.',
+ ),
+ 'tapoutput' => array(
+ 'shortopt' => 't',
+ 'doc' => 'Output run-tests.log in TAP-compliant format',
+ ),
+ 'cgi' => array(
+ 'shortopt' => 'c',
+ 'doc' => 'CGI php executable (needed for tests with POST/GET section)',
+ 'arg' => 'PHPCGI',
+ ),
+ 'coverage' => array(
+ 'shortopt' => 'x',
+ 'doc' => 'Generate a code coverage report (requires Xdebug 2.0.0+)',
+ ),
+ 'showdiff' => array(
+ 'shortopt' => 'd',
+ 'doc' => 'Output diff on test failure',
+ ),
+ ),
+ 'doc' => '[testfile|dir ...]
+Run regression tests with PHP\'s regression testing script (run-tests.php).',
+ ),
+ );
+
+ var $output;
+
+ /**
+ * PEAR_Command_Test constructor.
+ *
+ * @access public
+ */
+ function __construct(&$ui, &$config)
+ {
+ parent::__construct($ui, $config);
+ }
+
+ function doRunTests($command, $options, $params)
+ {
+ if (isset($options['phpunit']) && isset($options['tapoutput'])) {
+ return $this->raiseError('ERROR: cannot use both --phpunit and --tapoutput at the same time');
+ }
+
+ require_once 'PEAR/Common.php';
+ require_once 'System.php';
+ $log = new PEAR_Common;
+ $log->ui = &$this->ui; // slightly hacky, but it will work
+ $tests = array();
+ $depth = isset($options['recur']) ? 14 : 1;
+
+ if (!count($params)) {
+ $params[] = '.';
+ }
+
+ if (isset($options['package'])) {
+ $oldparams = $params;
+ $params = array();
+ $reg = &$this->config->getRegistry();
+ foreach ($oldparams as $param) {
+ $pname = $reg->parsePackageName($param, $this->config->get('default_channel'));
+ if (PEAR::isError($pname)) {
+ return $this->raiseError($pname);
+ }
+
+ $package = &$reg->getPackage($pname['package'], $pname['channel']);
+ if (!$package) {
+ return PEAR::raiseError('Unknown package "' .
+ $reg->parsedPackageNameToString($pname) . '"');
+ }
+
+ $filelist = $package->getFilelist();
+ foreach ($filelist as $name => $atts) {
+ if (isset($atts['role']) && $atts['role'] != 'test') {
+ continue;
+ }
+
+ if (isset($options['phpunit']) && preg_match('/AllTests\.php\\z/i', $name)) {
+ $params[] = $atts['installed_as'];
+ continue;
+ } elseif (!preg_match('/\.phpt\\z/', $name)) {
+ continue;
+ }
+ $params[] = $atts['installed_as'];
+ }
+ }
+ }
+
+ foreach ($params as $p) {
+ if (is_dir($p)) {
+ if (isset($options['phpunit'])) {
+ $dir = System::find(array($p, '-type', 'f',
+ '-maxdepth', $depth,
+ '-name', 'AllTests.php'));
+ if (count($dir)) {
+ foreach ($dir as $p) {
+ $p = realpath($p);
+ if (!count($tests) ||
+ (count($tests) && strlen($p) < strlen($tests[0]))) {
+ // this is in a higher-level directory, use this one instead.
+ $tests = array($p);
+ }
+ }
+ }
+ continue;
+ }
+
+ $args = array($p, '-type', 'f', '-name', '*.phpt');
+ } else {
+ if (isset($options['phpunit'])) {
+ if (preg_match('/AllTests\.php\\z/i', $p)) {
+ $p = realpath($p);
+ if (!count($tests) ||
+ (count($tests) && strlen($p) < strlen($tests[0]))) {
+ // this is in a higher-level directory, use this one instead.
+ $tests = array($p);
+ }
+ }
+ continue;
+ }
+
+ if (file_exists($p) && preg_match('/\.phpt$/', $p)) {
+ $tests[] = $p;
+ continue;
+ }
+
+ if (!preg_match('/\.phpt\\z/', $p)) {
+ $p .= '.phpt';
+ }
+
+ $args = array(dirname($p), '-type', 'f', '-name', $p);
+ }
+
+ if (!isset($options['recur'])) {
+ $args[] = '-maxdepth';
+ $args[] = 1;
+ }
+
+ $dir = System::find($args);
+ $tests = array_merge($tests, $dir);
+ }
+
+ $ini_settings = '';
+ if (isset($options['ini'])) {
+ $ini_settings .= $options['ini'];
+ }
+
+ if (isset($_ENV['TEST_PHP_INCLUDE_PATH'])) {
+ $ini_settings .= " -d include_path={$_ENV['TEST_PHP_INCLUDE_PATH']}";
+ }
+
+ if ($ini_settings) {
+ $this->ui->outputData('Using INI settings: "' . $ini_settings . '"');
+ }
+
+ $skipped = $passed = $failed = array();
+ $tests_count = count($tests);
+ $this->ui->outputData('Running ' . $tests_count . ' tests', $command);
+ $start = time();
+ if (isset($options['realtimelog']) && file_exists('run-tests.log')) {
+ unlink('run-tests.log');
+ }
+
+ if (isset($options['tapoutput'])) {
+ $tap = '1..' . $tests_count . "\n";
+ }
+
+ require_once 'PEAR/RunTest.php';
+ $run = new PEAR_RunTest($log, $options);
+ $run->tests_count = $tests_count;
+
+ if (isset($options['coverage']) && extension_loaded('xdebug')){
+ $run->xdebug_loaded = true;
+ } else {
+ $run->xdebug_loaded = false;
+ }
+
+ $j = $i = 1;
+ foreach ($tests as $t) {
+ if (isset($options['realtimelog'])) {
+ $fp = @fopen('run-tests.log', 'a');
+ if ($fp) {
+ fwrite($fp, "Running test [$i / $tests_count] $t...");
+ fclose($fp);
+ }
+ }
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ if (isset($options['phpunit'])) {
+ $result = $run->runPHPUnit($t, $ini_settings);
+ } else {
+ $result = $run->run($t, $ini_settings, $j);
+ }
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($result)) {
+ $this->ui->log($result->getMessage());
+ continue;
+ }
+
+ if (isset($options['tapoutput'])) {
+ $tap .= $result[0] . ' ' . $i . $result[1] . "\n";
+ continue;
+ }
+
+ if (isset($options['realtimelog'])) {
+ $fp = @fopen('run-tests.log', 'a');
+ if ($fp) {
+ fwrite($fp, "$result\n");
+ fclose($fp);
+ }
+ }
+
+ if ($result == 'FAILED') {
+ $failed[] = $t;
+ }
+ if ($result == 'PASSED') {
+ $passed[] = $t;
+ }
+ if ($result == 'SKIPPED') {
+ $skipped[] = $t;
+ }
+
+ $j++;
+ }
+
+ $total = date('i:s', time() - $start);
+ if (isset($options['tapoutput'])) {
+ $fp = @fopen('run-tests.log', 'w');
+ if ($fp) {
+ fwrite($fp, $tap, strlen($tap));
+ fclose($fp);
+ $this->ui->outputData('wrote TAP-format log to "' .realpath('run-tests.log') .
+ '"', $command);
+ }
+ } else {
+ if (count($failed)) {
+ $output = "TOTAL TIME: $total\n";
+ $output .= count($passed) . " PASSED TESTS\n";
+ $output .= count($skipped) . " SKIPPED TESTS\n";
+ $output .= count($failed) . " FAILED TESTS:\n";
+ foreach ($failed as $failure) {
+ $output .= $failure . "\n";
+ }
+
+ $mode = isset($options['realtimelog']) ? 'a' : 'w';
+ $fp = @fopen('run-tests.log', $mode);
+
+ if ($fp) {
+ fwrite($fp, $output, strlen($output));
+ fclose($fp);
+ $this->ui->outputData('wrote log to "' . realpath('run-tests.log') . '"', $command);
+ }
+ } elseif (file_exists('run-tests.log') && !is_dir('run-tests.log')) {
+ @unlink('run-tests.log');
+ }
+ }
+ $this->ui->outputData('TOTAL TIME: ' . $total);
+ $this->ui->outputData(count($passed) . ' PASSED TESTS', $command);
+ $this->ui->outputData(count($skipped) . ' SKIPPED TESTS', $command);
+ if (count($failed)) {
+ $this->ui->outputData(count($failed) . ' FAILED TESTS:', $command);
+ foreach ($failed as $failure) {
+ $this->ui->outputData($failure, $command);
+ }
+ }
+
+ if (count($failed) == 0) {
+ return true;
+ }
+ return $this->raiseError('Some tests failed');
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Command/Test.xml b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Test.xml
new file mode 100644
index 000000000..bbe9fcccc
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Command/Test.xml
@@ -0,0 +1,54 @@
+
+
+ Run Regression Tests
+ doRunTests
+ rt
+
+
+ r
+ Run tests in child directories, recursively. 4 dirs deep maximum
+
+
+ i
+ actual string of settings to pass to php in format " -d setting=blah"
+ SETTINGS
+
+
+ l
+ Log test runs/results as they are run
+
+
+ q
+ Only display detail for failed tests
+
+
+ s
+ Display simple output for all tests
+
+
+ p
+ Treat parameters as installed packages from which to run tests
+
+
+ u
+ Search parameters for AllTests.php, and use that to run phpunit-based tests
+If none is found, all .phpt tests will be tried instead.
+
+
+ t
+ Output run-tests.log in TAP-compliant format
+
+
+ c
+ CGI php executable (needed for tests with POST/GET section)
+ PHPCGI
+
+
+ x
+ Generate a code coverage report (requires Xdebug 2.0.0+)
+
+
+ [testfile|dir ...]
+Run regression tests with PHP's regression testing script (run-tests.php).
+
+
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Common.php b/vendor/pear-pear.php.net/PEAR/PEAR/Common.php
new file mode 100644
index 000000000..1c4f79ceb
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Common.php
@@ -0,0 +1,838 @@
+
+ * @author Tomas V. V. Cox
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1.0
+ * @deprecated File deprecated since Release 1.4.0a1
+ */
+
+/**
+ * Include error handling
+ */
+require_once 'PEAR.php';
+
+/**
+ * PEAR_Common error when an invalid PHP file is passed to PEAR_Common::analyzeSourceCode()
+ */
+define('PEAR_COMMON_ERROR_INVALIDPHP', 1);
+define('_PEAR_COMMON_PACKAGE_NAME_PREG', '[A-Za-z][a-zA-Z0-9_]+');
+define('PEAR_COMMON_PACKAGE_NAME_PREG', '/^' . _PEAR_COMMON_PACKAGE_NAME_PREG . '\\z/');
+
+// this should allow: 1, 1.0, 1.0RC1, 1.0dev, 1.0dev123234234234, 1.0a1, 1.0b1, 1.0pl1
+define('_PEAR_COMMON_PACKAGE_VERSION_PREG', '\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?');
+define('PEAR_COMMON_PACKAGE_VERSION_PREG', '/^' . _PEAR_COMMON_PACKAGE_VERSION_PREG . '\\z/i');
+
+// XXX far from perfect :-)
+define('_PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '(' . _PEAR_COMMON_PACKAGE_NAME_PREG .
+ ')(-([.0-9a-zA-Z]+))?');
+define('PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_PACKAGE_DOWNLOAD_PREG .
+ '\\z/');
+
+define('_PEAR_CHANNELS_NAME_PREG', '[A-Za-z][a-zA-Z0-9\.]+');
+define('PEAR_CHANNELS_NAME_PREG', '/^' . _PEAR_CHANNELS_NAME_PREG . '\\z/');
+
+// this should allow any dns or IP address, plus a path - NO UNDERSCORES ALLOWED
+define('_PEAR_CHANNELS_SERVER_PREG', '[a-zA-Z0-9\-]+(?:\.[a-zA-Z0-9\-]+)*(\/[a-zA-Z0-9\-]+)*');
+define('PEAR_CHANNELS_SERVER_PREG', '/^' . _PEAR_CHANNELS_SERVER_PREG . '\\z/i');
+
+define('_PEAR_CHANNELS_PACKAGE_PREG', '(' ._PEAR_CHANNELS_SERVER_PREG . ')\/('
+ . _PEAR_COMMON_PACKAGE_NAME_PREG . ')');
+define('PEAR_CHANNELS_PACKAGE_PREG', '/^' . _PEAR_CHANNELS_PACKAGE_PREG . '\\z/i');
+
+define('_PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '(' . _PEAR_CHANNELS_NAME_PREG . ')::('
+ . _PEAR_COMMON_PACKAGE_NAME_PREG . ')(-([.0-9a-zA-Z]+))?');
+define('PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_CHANNEL_DOWNLOAD_PREG . '\\z/');
+
+/**
+ * List of temporary files and directories registered by
+ * PEAR_Common::addTempFile().
+ * @var array
+ */
+$GLOBALS['_PEAR_Common_tempfiles'] = array();
+
+/**
+ * Valid maintainer roles
+ * @var array
+ */
+$GLOBALS['_PEAR_Common_maintainer_roles'] = array('lead','developer','contributor','helper');
+
+/**
+ * Valid release states
+ * @var array
+ */
+$GLOBALS['_PEAR_Common_release_states'] = array('alpha','beta','stable','snapshot','devel');
+
+/**
+ * Valid dependency types
+ * @var array
+ */
+$GLOBALS['_PEAR_Common_dependency_types'] = array('pkg','ext','php','prog','ldlib','rtlib','os','websrv','sapi');
+
+/**
+ * Valid dependency relations
+ * @var array
+ */
+$GLOBALS['_PEAR_Common_dependency_relations'] = array('has','eq','lt','le','gt','ge','not', 'ne');
+
+/**
+ * Valid file roles
+ * @var array
+ */
+$GLOBALS['_PEAR_Common_file_roles'] = array('php','ext','test','doc','data','src','script');
+
+/**
+ * Valid replacement types
+ * @var array
+ */
+$GLOBALS['_PEAR_Common_replacement_types'] = array('php-const', 'pear-config', 'package-info');
+
+/**
+ * Valid "provide" types
+ * @var array
+ */
+$GLOBALS['_PEAR_Common_provide_types'] = array('ext', 'prog', 'class', 'function', 'feature', 'api');
+
+/**
+ * Valid "provide" types
+ * @var array
+ */
+$GLOBALS['_PEAR_Common_script_phases'] = array('pre-install', 'post-install', 'pre-uninstall', 'post-uninstall', 'pre-build', 'post-build', 'pre-configure', 'post-configure', 'pre-setup', 'post-setup');
+
+/**
+ * Class providing common functionality for PEAR administration classes.
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Tomas V. V. Cox
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ * @deprecated This class will disappear, and its components will be spread
+ * into smaller classes, like the AT&T breakup, as of Release 1.4.0a1
+ */
+class PEAR_Common extends PEAR
+{
+ /**
+ * User Interface object (PEAR_Frontend_* class). If null,
+ * the log() method uses print.
+ * @var object
+ */
+ var $ui = null;
+
+ /**
+ * Configuration object (PEAR_Config).
+ * @var PEAR_Config
+ */
+ var $config = null;
+
+ /** stack of elements, gives some sort of XML context */
+ var $element_stack = array();
+
+ /** name of currently parsed XML element */
+ var $current_element;
+
+ /** array of attributes of the currently parsed XML element */
+ var $current_attributes = array();
+
+ /** assoc with information about a package */
+ var $pkginfo = array();
+
+ var $current_path = null;
+
+ /**
+ * Flag variable used to mark a valid package file
+ * @var boolean
+ * @access private
+ */
+ var $_validPackageFile;
+
+ /**
+ * PEAR_Common constructor
+ *
+ * @access public
+ */
+ function __construct()
+ {
+ parent::__construct();
+ $this->config = &PEAR_Config::singleton();
+ $this->debug = $this->config->get('verbose');
+ }
+
+ /**
+ * PEAR_Common destructor
+ *
+ * @access private
+ */
+ function _PEAR_Common()
+ {
+ // doesn't work due to bug #14744
+ //$tempfiles = $this->_tempfiles;
+ $tempfiles =& $GLOBALS['_PEAR_Common_tempfiles'];
+ while ($file = array_shift($tempfiles)) {
+ if (@is_dir($file)) {
+ if (!class_exists('System')) {
+ require_once 'System.php';
+ }
+
+ System::rm(array('-rf', $file));
+ } elseif (file_exists($file)) {
+ unlink($file);
+ }
+ }
+ }
+
+ /**
+ * Register a temporary file or directory. When the destructor is
+ * executed, all registered temporary files and directories are
+ * removed.
+ *
+ * @param string $file name of file or directory
+ *
+ * @return void
+ *
+ * @access public
+ */
+ function addTempFile($file)
+ {
+ if (!class_exists('PEAR_Frontend')) {
+ require_once 'PEAR/Frontend.php';
+ }
+ PEAR_Frontend::addTempFile($file);
+ }
+
+ /**
+ * Wrapper to System::mkDir(), creates a directory as well as
+ * any necessary parent directories.
+ *
+ * @param string $dir directory name
+ *
+ * @return bool TRUE on success, or a PEAR error
+ *
+ * @access public
+ */
+ function mkDirHier($dir)
+ {
+ // Only used in Installer - move it there ?
+ $this->log(2, "+ create dir $dir");
+ if (!class_exists('System')) {
+ require_once 'System.php';
+ }
+ return System::mkDir(array('-p', $dir));
+ }
+
+ /**
+ * Logging method.
+ *
+ * @param int $level log level (0 is quiet, higher is noisier)
+ * @param string $msg message to write to the log
+ *
+ * @return void
+ */
+ public function log($level, $msg, $append_crlf = true)
+ {
+ if ($this->debug >= $level) {
+ if (!class_exists('PEAR_Frontend')) {
+ require_once 'PEAR/Frontend.php';
+ }
+
+ $ui = &PEAR_Frontend::singleton();
+ if (is_a($ui, 'PEAR_Frontend')) {
+ $ui->log($msg, $append_crlf);
+ } else {
+ print "$msg\n";
+ }
+ }
+ }
+
+ /**
+ * Create and register a temporary directory.
+ *
+ * @param string $tmpdir (optional) Directory to use as tmpdir.
+ * Will use system defaults (for example
+ * /tmp or c:\windows\temp) if not specified
+ *
+ * @return string name of created directory
+ *
+ * @access public
+ */
+ function mkTempDir($tmpdir = '')
+ {
+ $topt = $tmpdir ? array('-t', $tmpdir) : array();
+ $topt = array_merge($topt, array('-d', 'pear'));
+ if (!class_exists('System')) {
+ require_once 'System.php';
+ }
+
+ if (!$tmpdir = System::mktemp($topt)) {
+ return false;
+ }
+
+ $this->addTempFile($tmpdir);
+ return $tmpdir;
+ }
+
+ /**
+ * Set object that represents the frontend to be used.
+ *
+ * @param object Reference of the frontend object
+ * @return void
+ * @access public
+ */
+ function setFrontendObject(&$ui)
+ {
+ $this->ui = &$ui;
+ }
+
+ /**
+ * Return an array containing all of the states that are more stable than
+ * or equal to the passed in state
+ *
+ * @param string Release state
+ * @param boolean Determines whether to include $state in the list
+ * @return false|array False if $state is not a valid release state
+ */
+ function betterStates($state, $include = false)
+ {
+ static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable');
+ $i = array_search($state, $states);
+ if ($i === false) {
+ return false;
+ }
+ if ($include) {
+ $i--;
+ }
+ return array_slice($states, $i + 1);
+ }
+
+ /**
+ * Get the valid roles for a PEAR package maintainer
+ *
+ * @return array
+ */
+ public static function getUserRoles()
+ {
+ return $GLOBALS['_PEAR_Common_maintainer_roles'];
+ }
+
+ /**
+ * Get the valid package release states of packages
+ *
+ * @return array
+ */
+ public static function getReleaseStates()
+ {
+ return $GLOBALS['_PEAR_Common_release_states'];
+ }
+
+ /**
+ * Get the implemented dependency types (php, ext, pkg etc.)
+ *
+ * @return array
+ */
+ public static function getDependencyTypes()
+ {
+ return $GLOBALS['_PEAR_Common_dependency_types'];
+ }
+
+ /**
+ * Get the implemented dependency relations (has, lt, ge etc.)
+ *
+ * @return array
+ */
+ public static function getDependencyRelations()
+ {
+ return $GLOBALS['_PEAR_Common_dependency_relations'];
+ }
+
+ /**
+ * Get the implemented file roles
+ *
+ * @return array
+ */
+ public static function getFileRoles()
+ {
+ return $GLOBALS['_PEAR_Common_file_roles'];
+ }
+
+ /**
+ * Get the implemented file replacement types in
+ *
+ * @return array
+ */
+ public static function getReplacementTypes()
+ {
+ return $GLOBALS['_PEAR_Common_replacement_types'];
+ }
+
+ /**
+ * Get the implemented file replacement types in
+ *
+ * @return array
+ */
+ public static function getProvideTypes()
+ {
+ return $GLOBALS['_PEAR_Common_provide_types'];
+ }
+
+ /**
+ * Get the implemented file replacement types in
+ *
+ * @return array
+ */
+ public static function getScriptPhases()
+ {
+ return $GLOBALS['_PEAR_Common_script_phases'];
+ }
+
+ /**
+ * Test whether a string contains a valid package name.
+ *
+ * @param string $name the package name to test
+ *
+ * @return bool
+ *
+ * @access public
+ */
+ function validPackageName($name)
+ {
+ return (bool)preg_match(PEAR_COMMON_PACKAGE_NAME_PREG, $name);
+ }
+
+ /**
+ * Test whether a string contains a valid package version.
+ *
+ * @param string $ver the package version to test
+ *
+ * @return bool
+ *
+ * @access public
+ */
+ function validPackageVersion($ver)
+ {
+ return (bool)preg_match(PEAR_COMMON_PACKAGE_VERSION_PREG, $ver);
+ }
+
+ /**
+ * @param string $path relative or absolute include path
+ * @return boolean
+ */
+ public 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;
+ }
+
+ function _postProcessChecks($pf)
+ {
+ if (!PEAR::isError($pf)) {
+ return $this->_postProcessValidPackagexml($pf);
+ }
+
+ $errs = $pf->getUserinfo();
+ if (is_array($errs)) {
+ foreach ($errs as $error) {
+ $e = $this->raiseError($error['message'], $error['code'], null, null, $error);
+ }
+ }
+
+ return $pf;
+ }
+
+ /**
+ * Returns information about a package file. Expects the name of
+ * a gzipped tar file as input.
+ *
+ * @param string $file name of .tgz file
+ *
+ * @return array array with package information
+ *
+ * @access public
+ * @deprecated use PEAR_PackageFile->fromTgzFile() instead
+ *
+ */
+ function infoFromTgzFile($file)
+ {
+ $packagefile = new PEAR_PackageFile($this->config);
+ $pf = &$packagefile->fromTgzFile($file, PEAR_VALIDATE_NORMAL);
+ return $this->_postProcessChecks($pf);
+ }
+
+ /**
+ * Returns information about a package file. Expects the name of
+ * a package xml file as input.
+ *
+ * @param string $descfile name of package xml file
+ *
+ * @return array array with package information
+ *
+ * @access public
+ * @deprecated use PEAR_PackageFile->fromPackageFile() instead
+ *
+ */
+ function infoFromDescriptionFile($descfile)
+ {
+ $packagefile = new PEAR_PackageFile($this->config);
+ $pf = &$packagefile->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL);
+ return $this->_postProcessChecks($pf);
+ }
+
+ /**
+ * Returns information about a package file. Expects the contents
+ * of a package xml file as input.
+ *
+ * @param string $data contents of package.xml file
+ *
+ * @return array array with package information
+ *
+ * @access public
+ * @deprecated use PEAR_PackageFile->fromXmlstring() instead
+ *
+ */
+ function infoFromString($data)
+ {
+ $packagefile = new PEAR_PackageFile($this->config);
+ $pf = &$packagefile->fromXmlString($data, PEAR_VALIDATE_NORMAL, false);
+ return $this->_postProcessChecks($pf);
+ }
+
+ /**
+ * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+ * @return array
+ */
+ function _postProcessValidPackagexml(&$pf)
+ {
+ if (!is_a($pf, 'PEAR_PackageFile_v2')) {
+ $this->pkginfo = $pf->toArray();
+ return $this->pkginfo;
+ }
+
+ // sort of make this into a package.xml 1.0-style array
+ // changelog is not converted to old format.
+ $arr = $pf->toArray(true);
+ $arr = array_merge($arr, $arr['old']);
+ unset($arr['old'], $arr['xsdversion'], $arr['contents'], $arr['compatible'],
+ $arr['channel'], $arr['uri'], $arr['dependencies'], $arr['phprelease'],
+ $arr['extsrcrelease'], $arr['zendextsrcrelease'], $arr['extbinrelease'],
+ $arr['zendextbinrelease'], $arr['bundle'], $arr['lead'], $arr['developer'],
+ $arr['helper'], $arr['contributor']);
+ $arr['filelist'] = $pf->getFilelist();
+ $this->pkginfo = $arr;
+ return $arr;
+ }
+
+ /**
+ * Returns package information from different sources
+ *
+ * This method is able to extract information about a package
+ * from a .tgz archive or from a XML package definition file.
+ *
+ * @access public
+ * @param string Filename of the source ('package.xml', '.tgz')
+ * @return string
+ * @deprecated use PEAR_PackageFile->fromAnyFile() instead
+ */
+ function infoFromAny($info)
+ {
+ if (is_string($info) && file_exists($info)) {
+ $packagefile = new PEAR_PackageFile($this->config);
+ $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL);
+ if (PEAR::isError($pf)) {
+ $errs = $pf->getUserinfo();
+ if (is_array($errs)) {
+ foreach ($errs as $error) {
+ $e = $this->raiseError($error['message'], $error['code'], null, null, $error);
+ }
+ }
+
+ return $pf;
+ }
+
+ return $this->_postProcessValidPackagexml($pf);
+ }
+
+ return $info;
+ }
+
+ /**
+ * Return an XML document based on the package info (as returned
+ * by the PEAR_Common::infoFrom* methods).
+ *
+ * @param array $pkginfo package info
+ *
+ * @return string XML data
+ *
+ * @access public
+ * @deprecated use a PEAR_PackageFile_v* object's generator instead
+ */
+ function xmlFromInfo($pkginfo)
+ {
+ $config = &PEAR_Config::singleton();
+ $packagefile = new PEAR_PackageFile($config);
+ $pf = &$packagefile->fromArray($pkginfo);
+ $gen = &$pf->getDefaultGenerator();
+ return $gen->toXml(PEAR_VALIDATE_PACKAGING);
+ }
+
+ /**
+ * Validate XML package definition file.
+ *
+ * @param string $info Filename of the package archive or of the
+ * package definition file
+ * @param array $errors Array that will contain the errors
+ * @param array $warnings Array that will contain the warnings
+ * @param string $dir_prefix (optional) directory where source files
+ * may be found, or empty if they are not available
+ * @access public
+ * @return boolean
+ * @deprecated use the validation of PEAR_PackageFile objects
+ */
+ function validatePackageInfo($info, &$errors, &$warnings, $dir_prefix = '')
+ {
+ $config = &PEAR_Config::singleton();
+ $packagefile = new PEAR_PackageFile($config);
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ if (strpos($info, 'fromXmlString($info, PEAR_VALIDATE_NORMAL, '');
+ } else {
+ $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL);
+ }
+
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($pf)) {
+ $errs = $pf->getUserinfo();
+ if (is_array($errs)) {
+ foreach ($errs as $error) {
+ if ($error['level'] == 'error') {
+ $errors[] = $error['message'];
+ } else {
+ $warnings[] = $error['message'];
+ }
+ }
+ }
+
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Build a "provides" array from data returned by
+ * analyzeSourceCode(). The format of the built array is like
+ * this:
+ *
+ * array(
+ * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'),
+ * ...
+ * )
+ *
+ *
+ * @param array $srcinfo array with information about a source file
+ * as returned by the analyzeSourceCode() method.
+ *
+ * @return void
+ *
+ * @access public
+ *
+ */
+ function buildProvidesArray($srcinfo)
+ {
+ $file = basename($srcinfo['source_file']);
+ $pn = '';
+ if (isset($this->_packageName)) {
+ $pn = $this->_packageName;
+ }
+
+ $pnl = strlen($pn);
+ foreach ($srcinfo['declared_classes'] as $class) {
+ $key = "class;$class";
+ if (isset($this->pkginfo['provides'][$key])) {
+ continue;
+ }
+
+ $this->pkginfo['provides'][$key] =
+ array('file'=> $file, 'type' => 'class', 'name' => $class);
+ if (isset($srcinfo['inheritance'][$class])) {
+ $this->pkginfo['provides'][$key]['extends'] =
+ $srcinfo['inheritance'][$class];
+ }
+ }
+
+ foreach ($srcinfo['declared_methods'] as $class => $methods) {
+ foreach ($methods as $method) {
+ $function = "$class::$method";
+ $key = "function;$function";
+ if ($method{0} == '_' || !strcasecmp($method, $class) ||
+ isset($this->pkginfo['provides'][$key])) {
+ continue;
+ }
+
+ $this->pkginfo['provides'][$key] =
+ array('file'=> $file, 'type' => 'function', 'name' => $function);
+ }
+ }
+
+ foreach ($srcinfo['declared_functions'] as $function) {
+ $key = "function;$function";
+ if ($function{0} == '_' || isset($this->pkginfo['provides'][$key])) {
+ continue;
+ }
+
+ if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) {
+ $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\"";
+ }
+
+ $this->pkginfo['provides'][$key] =
+ array('file'=> $file, 'type' => 'function', 'name' => $function);
+ }
+ }
+
+ /**
+ * Analyze the source code of the given PHP file
+ *
+ * @param string Filename of the PHP file
+ * @return mixed
+ * @access public
+ */
+ function analyzeSourceCode($file)
+ {
+ if (!class_exists('PEAR_PackageFile_v2_Validator')) {
+ require_once 'PEAR/PackageFile/v2/Validator.php';
+ }
+
+ $a = new PEAR_PackageFile_v2_Validator;
+ return $a->analyzeSourceCode($file);
+ }
+
+ function detectDependencies($any, $status_callback = null)
+ {
+ if (!function_exists("token_get_all")) {
+ return false;
+ }
+
+ if (PEAR::isError($info = $this->infoFromAny($any))) {
+ return $this->raiseError($info);
+ }
+
+ if (!is_array($info)) {
+ return false;
+ }
+
+ $deps = array();
+ $used_c = $decl_c = $decl_f = $decl_m = array();
+ foreach ($info['filelist'] as $file => $fa) {
+ $tmp = $this->analyzeSourceCode($file);
+ $used_c = @array_merge($used_c, $tmp['used_classes']);
+ $decl_c = @array_merge($decl_c, $tmp['declared_classes']);
+ $decl_f = @array_merge($decl_f, $tmp['declared_functions']);
+ $decl_m = @array_merge($decl_m, $tmp['declared_methods']);
+ $inheri = @array_merge($inheri, $tmp['inheritance']);
+ }
+
+ $used_c = array_unique($used_c);
+ $decl_c = array_unique($decl_c);
+ $undecl_c = array_diff($used_c, $decl_c);
+
+ return array('used_classes' => $used_c,
+ 'declared_classes' => $decl_c,
+ 'declared_methods' => $decl_m,
+ 'declared_functions' => $decl_f,
+ 'undeclared_classes' => $undecl_c,
+ 'inheritance' => $inheri,
+ );
+ }
+
+ /**
+ * Download a file through HTTP. Considers suggested file name in
+ * Content-disposition: header and can run a callback function for
+ * different events. The callback will be called with two
+ * parameters: the callback type, and parameters. The implemented
+ * callback types are:
+ *
+ * 'setup' called at the very beginning, parameter is a UI object
+ * that should be used for all output
+ * 'message' the parameter is a string with an informational message
+ * 'saveas' may be used to save with a different file name, the
+ * parameter is the filename that is about to be used.
+ * If a 'saveas' callback returns a non-empty string,
+ * that file name will be used as the filename instead.
+ * Note that $save_dir will not be affected by this, only
+ * the basename of the file.
+ * 'start' download is starting, parameter is number of bytes
+ * that are expected, or -1 if unknown
+ * 'bytesread' parameter is the number of bytes read so far
+ * 'done' download is complete, parameter is the total number
+ * of bytes read
+ * 'connfailed' if the TCP connection fails, this callback is called
+ * with array(host,port,errno,errmsg)
+ * 'writefailed' if writing to disk fails, this callback is called
+ * with array(destfile,errmsg)
+ *
+ * If an HTTP proxy has been configured (http_proxy PEAR_Config
+ * setting), the proxy will be used.
+ *
+ * @param string $url the URL to download
+ * @param object $ui PEAR_Frontend_* instance
+ * @param object $config PEAR_Config instance
+ * @param string $save_dir (optional) directory to save file in
+ * @param mixed $callback (optional) function/method to call for status
+ * updates
+ * @param false|string|array $lastmodified header values to check against
+ * for caching
+ * use false to return the header
+ * values from this download
+ * @param false|array $accept Accept headers to send
+ * @param false|string $channel Channel to use for retrieving
+ * authentication
+ *
+ * @return mixed Returns the full path of the downloaded file or a PEAR
+ * error on failure. If the error is caused by
+ * socket-related errors, the error object will
+ * have the fsockopen error code available through
+ * getCode(). If caching is requested, then return the header
+ * values.
+ * If $lastmodified was given and the there are no changes,
+ * boolean false is returned.
+ *
+ * @access public
+ */
+ function downloadHttp(
+ $url, &$ui, $save_dir = '.', $callback = null, $lastmodified = null,
+ $accept = false, $channel = false
+ ) {
+ if (!class_exists('PEAR_Downloader')) {
+ require_once 'PEAR/Downloader.php';
+ }
+ return PEAR_Downloader::_downloadHttp(
+ $this, $url, $ui, $save_dir, $callback, $lastmodified,
+ $accept, $channel
+ );
+ }
+}
+
+require_once 'PEAR/Config.php';
+require_once 'PEAR/PackageFile.php';
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Config.php b/vendor/pear-pear.php.net/PEAR/PEAR/Config.php
new file mode 100644
index 000000000..d9b4d273c
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Config.php
@@ -0,0 +1,2131 @@
+
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ */
+
+/**
+ * Required for error handling
+ */
+require_once 'PEAR.php';
+require_once 'PEAR/Registry.php';
+require_once 'PEAR/Installer/Role.php';
+require_once 'System.php';
+
+/**
+ * Last created PEAR_Config instance.
+ * @var object
+ */
+$GLOBALS['_PEAR_Config_instance'] = null;
+if (!defined('PEAR_INSTALL_DIR') || !PEAR_INSTALL_DIR) {
+ $PEAR_INSTALL_DIR = PHP_LIBDIR . DIRECTORY_SEPARATOR . 'pear';
+} else {
+ $PEAR_INSTALL_DIR = PEAR_INSTALL_DIR;
+}
+
+// Below we define constants with default values for all configuration
+// parameters except username/password. All of them can have their
+// defaults set through environment variables. The reason we use the
+// PHP_ prefix is for some security, PHP protects environment
+// variables starting with PHP_*.
+
+// default channel and preferred mirror is based on whether we are invoked through
+// the "pear" or the "pecl" command
+if (!defined('PEAR_RUNTYPE')) {
+ define('PEAR_RUNTYPE', 'pear');
+}
+
+if (PEAR_RUNTYPE == 'pear') {
+ define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pear.php.net');
+} else {
+ define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pecl.php.net');
+}
+
+if (getenv('PHP_PEAR_SYSCONF_DIR')) {
+ define('PEAR_CONFIG_SYSCONFDIR', getenv('PHP_PEAR_SYSCONF_DIR'));
+} elseif (getenv('SystemRoot')) {
+ define('PEAR_CONFIG_SYSCONFDIR', getenv('SystemRoot'));
+} else {
+ define('PEAR_CONFIG_SYSCONFDIR', PHP_SYSCONFDIR);
+}
+
+// Default for master_server
+if (getenv('PHP_PEAR_MASTER_SERVER')) {
+ define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', getenv('PHP_PEAR_MASTER_SERVER'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', 'pear.php.net');
+}
+
+// Default for http_proxy
+if (getenv('PHP_PEAR_HTTP_PROXY')) {
+ define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('PHP_PEAR_HTTP_PROXY'));
+} elseif (getenv('http_proxy')) {
+ define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('http_proxy'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', '');
+}
+
+// Default for php_dir
+if (getenv('PHP_PEAR_INSTALL_DIR')) {
+ define('PEAR_CONFIG_DEFAULT_PHP_DIR', getenv('PHP_PEAR_INSTALL_DIR'));
+} else {
+ if (@file_exists($PEAR_INSTALL_DIR) && is_dir($PEAR_INSTALL_DIR)) {
+ define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR);
+ } else {
+ define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR);
+ }
+}
+
+// Default for metadata_dir
+if (getenv('PHP_PEAR_METADATA_DIR')) {
+ define('PEAR_CONFIG_DEFAULT_METADATA_DIR', getenv('PHP_PEAR_METADATA_DIR'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_METADATA_DIR', '');
+}
+
+// Default for ext_dir
+if (getenv('PHP_PEAR_EXTENSION_DIR')) {
+ define('PEAR_CONFIG_DEFAULT_EXT_DIR', getenv('PHP_PEAR_EXTENSION_DIR'));
+} else {
+ if (ini_get('extension_dir')) {
+ define('PEAR_CONFIG_DEFAULT_EXT_DIR', ini_get('extension_dir'));
+ } elseif (defined('PEAR_EXTENSION_DIR') &&
+ file_exists(PEAR_EXTENSION_DIR) && is_dir(PEAR_EXTENSION_DIR)) {
+ define('PEAR_CONFIG_DEFAULT_EXT_DIR', PEAR_EXTENSION_DIR);
+ } elseif (defined('PHP_EXTENSION_DIR')) {
+ define('PEAR_CONFIG_DEFAULT_EXT_DIR', PHP_EXTENSION_DIR);
+ } else {
+ define('PEAR_CONFIG_DEFAULT_EXT_DIR', '.');
+ }
+}
+
+// Default for doc_dir
+if (getenv('PHP_PEAR_DOC_DIR')) {
+ define('PEAR_CONFIG_DEFAULT_DOC_DIR', getenv('PHP_PEAR_DOC_DIR'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_DOC_DIR',
+ $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'docs');
+}
+
+// Default for bin_dir
+if (getenv('PHP_PEAR_BIN_DIR')) {
+ define('PEAR_CONFIG_DEFAULT_BIN_DIR', getenv('PHP_PEAR_BIN_DIR'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_BIN_DIR', PHP_BINDIR);
+}
+
+// Default for data_dir
+if (getenv('PHP_PEAR_DATA_DIR')) {
+ define('PEAR_CONFIG_DEFAULT_DATA_DIR', getenv('PHP_PEAR_DATA_DIR'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_DATA_DIR',
+ $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'data');
+}
+
+// Default for cfg_dir
+if (getenv('PHP_PEAR_CFG_DIR')) {
+ define('PEAR_CONFIG_DEFAULT_CFG_DIR', getenv('PHP_PEAR_CFG_DIR'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_CFG_DIR',
+ $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'cfg');
+}
+
+// Default for www_dir
+if (getenv('PHP_PEAR_WWW_DIR')) {
+ define('PEAR_CONFIG_DEFAULT_WWW_DIR', getenv('PHP_PEAR_WWW_DIR'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_WWW_DIR',
+ $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'www');
+}
+
+// Default for man_dir
+if (getenv('PHP_PEAR_MAN_DIR')) {
+ define('PEAR_CONFIG_DEFAULT_MAN_DIR', getenv('PHP_PEAR_MAN_DIR'));
+} else {
+ if (defined('PHP_MANDIR')) { // Added in PHP5.3.7
+ define('PEAR_CONFIG_DEFAULT_MAN_DIR', PHP_MANDIR);
+ } else {
+ define('PEAR_CONFIG_DEFAULT_MAN_DIR', PHP_PREFIX . DIRECTORY_SEPARATOR .
+ 'local' . DIRECTORY_SEPARATOR .'man');
+ }
+}
+
+// Default for test_dir
+if (getenv('PHP_PEAR_TEST_DIR')) {
+ define('PEAR_CONFIG_DEFAULT_TEST_DIR', getenv('PHP_PEAR_TEST_DIR'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_TEST_DIR',
+ $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'tests');
+}
+
+// Default for temp_dir
+if (getenv('PHP_PEAR_TEMP_DIR')) {
+ define('PEAR_CONFIG_DEFAULT_TEMP_DIR', getenv('PHP_PEAR_TEMP_DIR'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_TEMP_DIR',
+ System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' .
+ DIRECTORY_SEPARATOR . 'temp');
+}
+
+// Default for cache_dir
+if (getenv('PHP_PEAR_CACHE_DIR')) {
+ define('PEAR_CONFIG_DEFAULT_CACHE_DIR', getenv('PHP_PEAR_CACHE_DIR'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_CACHE_DIR',
+ System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' .
+ DIRECTORY_SEPARATOR . 'cache');
+}
+
+// Default for download_dir
+if (getenv('PHP_PEAR_DOWNLOAD_DIR')) {
+ define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR', getenv('PHP_PEAR_DOWNLOAD_DIR'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR',
+ System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' .
+ DIRECTORY_SEPARATOR . 'download');
+}
+
+// Default for php_bin
+if (getenv('PHP_PEAR_PHP_BIN')) {
+ define('PEAR_CONFIG_DEFAULT_PHP_BIN', getenv('PHP_PEAR_PHP_BIN'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_PHP_BIN', PEAR_CONFIG_DEFAULT_BIN_DIR.
+ DIRECTORY_SEPARATOR.'php'.(OS_WINDOWS ? '.exe' : ''));
+}
+
+// Default for verbose
+if (getenv('PHP_PEAR_VERBOSE')) {
+ define('PEAR_CONFIG_DEFAULT_VERBOSE', getenv('PHP_PEAR_VERBOSE'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_VERBOSE', 1);
+}
+
+// Default for preferred_state
+if (getenv('PHP_PEAR_PREFERRED_STATE')) {
+ define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', getenv('PHP_PEAR_PREFERRED_STATE'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', 'stable');
+}
+
+// Default for umask
+if (getenv('PHP_PEAR_UMASK')) {
+ define('PEAR_CONFIG_DEFAULT_UMASK', getenv('PHP_PEAR_UMASK'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_UMASK', decoct(umask()));
+}
+
+// Default for cache_ttl
+if (getenv('PHP_PEAR_CACHE_TTL')) {
+ define('PEAR_CONFIG_DEFAULT_CACHE_TTL', getenv('PHP_PEAR_CACHE_TTL'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_CACHE_TTL', 3600);
+}
+
+// Default for sig_type
+if (getenv('PHP_PEAR_SIG_TYPE')) {
+ define('PEAR_CONFIG_DEFAULT_SIG_TYPE', getenv('PHP_PEAR_SIG_TYPE'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_SIG_TYPE', 'gpg');
+}
+
+// Default for sig_bin
+if (getenv('PHP_PEAR_SIG_BIN')) {
+ define('PEAR_CONFIG_DEFAULT_SIG_BIN', getenv('PHP_PEAR_SIG_BIN'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_SIG_BIN',
+ System::which(
+ 'gpg', OS_WINDOWS ? 'c:\gnupg\gpg.exe' : '/usr/local/bin/gpg'));
+}
+
+// Default for sig_keydir
+if (getenv('PHP_PEAR_SIG_KEYDIR')) {
+ define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR', getenv('PHP_PEAR_SIG_KEYDIR'));
+} else {
+ define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR',
+ PEAR_CONFIG_SYSCONFDIR . DIRECTORY_SEPARATOR . 'pearkeys');
+}
+
+/**
+ * This is a class for storing configuration data, keeping track of
+ * which are system-defined, user-defined or defaulted.
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 0.1
+ */
+class PEAR_Config extends PEAR
+{
+ /**
+ * Array of config files used.
+ *
+ * @var array layer => config file
+ */
+ var $files = array(
+ 'system' => '',
+ 'user' => '',
+ );
+
+ var $layers = array();
+
+ /**
+ * Configuration data, two-dimensional array where the first
+ * dimension is the config layer ('user', 'system' and 'default'),
+ * and the second dimension is keyname => value.
+ *
+ * The order in the first dimension is important! Earlier
+ * layers will shadow later ones when a config value is
+ * requested (if a 'user' value exists, it will be returned first,
+ * then 'system' and finally 'default').
+ *
+ * @var array layer => array(keyname => value, ...)
+ */
+ var $configuration = array(
+ 'user' => array(),
+ 'system' => array(),
+ 'default' => array(),
+ );
+
+ /**
+ * Configuration values that can be set for a channel
+ *
+ * All other configuration values can only have a global value
+ * @var array
+ * @access private
+ */
+ var $_channelConfigInfo = array(
+ 'php_dir', 'ext_dir', 'doc_dir', 'bin_dir', 'data_dir', 'cfg_dir',
+ 'test_dir', 'www_dir', 'php_bin', 'php_prefix', 'php_suffix', 'username',
+ 'password', 'verbose', 'preferred_state', 'umask', 'preferred_mirror', 'php_ini'
+ );
+
+ /**
+ * Channels that can be accessed
+ * @see setChannels()
+ * @var array
+ * @access private
+ */
+ var $_channels = array('pear.php.net', 'pecl.php.net', '__uri');
+
+ /**
+ * This variable is used to control the directory values returned
+ * @see setInstallRoot();
+ * @var string|false
+ * @access private
+ */
+ var $_installRoot = false;
+
+ /**
+ * If requested, this will always refer to the registry
+ * contained in php_dir
+ * @var PEAR_Registry
+ */
+ var $_registry = array();
+
+ /**
+ * @var array
+ * @access private
+ */
+ var $_regInitialized = array();
+
+ /**
+ * @var bool
+ * @access private
+ */
+ var $_noRegistry = false;
+
+ /**
+ * amount of errors found while parsing config
+ * @var integer
+ * @access private
+ */
+ var $_errorsFound = 0;
+ var $_lastError = null;
+
+ /**
+ * Information about the configuration data. Stores the type,
+ * default value and a documentation string for each configuration
+ * value.
+ *
+ * @var array layer => array(infotype => value, ...)
+ */
+ var $configuration_info = array(
+ // Channels/Internet Access
+ 'default_channel' => array(
+ 'type' => 'string',
+ 'default' => PEAR_CONFIG_DEFAULT_CHANNEL,
+ 'doc' => 'the default channel to use for all non explicit commands',
+ 'prompt' => 'Default Channel',
+ 'group' => 'Internet Access',
+ ),
+ 'preferred_mirror' => array(
+ 'type' => 'string',
+ 'default' => PEAR_CONFIG_DEFAULT_CHANNEL,
+ 'doc' => 'the default server or mirror to use for channel actions',
+ 'prompt' => 'Default Channel Mirror',
+ 'group' => 'Internet Access',
+ ),
+ 'remote_config' => array(
+ 'type' => 'password',
+ 'default' => '',
+ 'doc' => 'ftp url of remote configuration file to use for synchronized install',
+ 'prompt' => 'Remote Configuration File',
+ 'group' => 'Internet Access',
+ ),
+ 'auto_discover' => array(
+ 'type' => 'integer',
+ 'default' => 0,
+ 'doc' => 'whether to automatically discover new channels',
+ 'prompt' => 'Auto-discover new Channels',
+ 'group' => 'Internet Access',
+ ),
+ // Internet Access
+ 'master_server' => array(
+ 'type' => 'string',
+ 'default' => 'pear.php.net',
+ 'doc' => 'name of the main PEAR server [NOT USED IN THIS VERSION]',
+ 'prompt' => 'PEAR server [DEPRECATED]',
+ 'group' => 'Internet Access',
+ ),
+ 'http_proxy' => array(
+ 'type' => 'string',
+ 'default' => PEAR_CONFIG_DEFAULT_HTTP_PROXY,
+ 'doc' => 'HTTP proxy (host:port) to use when downloading packages',
+ 'prompt' => 'HTTP Proxy Server Address',
+ 'group' => 'Internet Access',
+ ),
+ // File Locations
+ 'php_dir' => array(
+ 'type' => 'directory',
+ 'default' => PEAR_CONFIG_DEFAULT_PHP_DIR,
+ 'doc' => 'directory where .php files are installed',
+ 'prompt' => 'PEAR directory',
+ 'group' => 'File Locations',
+ ),
+ 'ext_dir' => array(
+ 'type' => 'directory',
+ 'default' => PEAR_CONFIG_DEFAULT_EXT_DIR,
+ 'doc' => 'directory where loadable extensions are installed',
+ 'prompt' => 'PHP extension directory',
+ 'group' => 'File Locations',
+ ),
+ 'doc_dir' => array(
+ 'type' => 'directory',
+ 'default' => PEAR_CONFIG_DEFAULT_DOC_DIR,
+ 'doc' => 'directory where documentation is installed',
+ 'prompt' => 'PEAR documentation directory',
+ 'group' => 'File Locations',
+ ),
+ 'bin_dir' => array(
+ 'type' => 'directory',
+ 'default' => PEAR_CONFIG_DEFAULT_BIN_DIR,
+ 'doc' => 'directory where executables are installed',
+ 'prompt' => 'PEAR executables directory',
+ 'group' => 'File Locations',
+ ),
+ 'data_dir' => array(
+ 'type' => 'directory',
+ 'default' => PEAR_CONFIG_DEFAULT_DATA_DIR,
+ 'doc' => 'directory where data files are installed',
+ 'prompt' => 'PEAR data directory',
+ 'group' => 'File Locations (Advanced)',
+ ),
+ 'cfg_dir' => array(
+ 'type' => 'directory',
+ 'default' => PEAR_CONFIG_DEFAULT_CFG_DIR,
+ 'doc' => 'directory where modifiable configuration files are installed',
+ 'prompt' => 'PEAR configuration file directory',
+ 'group' => 'File Locations (Advanced)',
+ ),
+ 'www_dir' => array(
+ 'type' => 'directory',
+ 'default' => PEAR_CONFIG_DEFAULT_WWW_DIR,
+ 'doc' => 'directory where www frontend files (html/js) are installed',
+ 'prompt' => 'PEAR www files directory',
+ 'group' => 'File Locations (Advanced)',
+ ),
+ 'man_dir' => array(
+ 'type' => 'directory',
+ 'default' => PEAR_CONFIG_DEFAULT_MAN_DIR,
+ 'doc' => 'directory where unix manual pages are installed',
+ 'prompt' => 'Systems manpage files directory',
+ 'group' => 'File Locations (Advanced)',
+ ),
+ 'test_dir' => array(
+ 'type' => 'directory',
+ 'default' => PEAR_CONFIG_DEFAULT_TEST_DIR,
+ 'doc' => 'directory where regression tests are installed',
+ 'prompt' => 'PEAR test directory',
+ 'group' => 'File Locations (Advanced)',
+ ),
+ 'cache_dir' => array(
+ 'type' => 'directory',
+ 'default' => PEAR_CONFIG_DEFAULT_CACHE_DIR,
+ 'doc' => 'directory which is used for web service cache',
+ 'prompt' => 'PEAR Installer cache directory',
+ 'group' => 'File Locations (Advanced)',
+ ),
+ 'temp_dir' => array(
+ 'type' => 'directory',
+ 'default' => PEAR_CONFIG_DEFAULT_TEMP_DIR,
+ 'doc' => 'directory which is used for all temp files',
+ 'prompt' => 'PEAR Installer temp directory',
+ 'group' => 'File Locations (Advanced)',
+ ),
+ 'download_dir' => array(
+ 'type' => 'directory',
+ 'default' => PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR,
+ 'doc' => 'directory which is used for all downloaded files',
+ 'prompt' => 'PEAR Installer download directory',
+ 'group' => 'File Locations (Advanced)',
+ ),
+ 'php_bin' => array(
+ 'type' => 'file',
+ 'default' => PEAR_CONFIG_DEFAULT_PHP_BIN,
+ 'doc' => 'PHP CLI/CGI binary for executing scripts',
+ 'prompt' => 'PHP CLI/CGI binary',
+ 'group' => 'File Locations (Advanced)',
+ ),
+ 'php_prefix' => array(
+ 'type' => 'string',
+ 'default' => '',
+ 'doc' => '--program-prefix for php_bin\'s ./configure, used for pecl installs',
+ 'prompt' => '--program-prefix passed to PHP\'s ./configure',
+ 'group' => 'File Locations (Advanced)',
+ ),
+ 'php_suffix' => array(
+ 'type' => 'string',
+ 'default' => '',
+ 'doc' => '--program-suffix for php_bin\'s ./configure, used for pecl installs',
+ 'prompt' => '--program-suffix passed to PHP\'s ./configure',
+ 'group' => 'File Locations (Advanced)',
+ ),
+ 'php_ini' => array(
+ 'type' => 'file',
+ 'default' => '',
+ 'doc' => 'location of php.ini in which to enable PECL extensions on install',
+ 'prompt' => 'php.ini location',
+ 'group' => 'File Locations (Advanced)',
+ ),
+ 'metadata_dir' => array(
+ 'type' => 'directory',
+ 'default' => PEAR_CONFIG_DEFAULT_METADATA_DIR,
+ 'doc' => 'directory where metadata files are installed (registry, filemap, channels, ...)',
+ 'prompt' => 'PEAR metadata directory',
+ 'group' => 'File Locations (Advanced)',
+ ),
+ // Maintainers
+ 'username' => array(
+ 'type' => 'string',
+ 'default' => '',
+ 'doc' => '(maintainers) your PEAR account name',
+ 'prompt' => 'PEAR username (for maintainers)',
+ 'group' => 'Maintainers',
+ ),
+ 'password' => array(
+ 'type' => 'password',
+ 'default' => '',
+ 'doc' => '(maintainers) your PEAR account password',
+ 'prompt' => 'PEAR password (for maintainers)',
+ 'group' => 'Maintainers',
+ ),
+ // Advanced
+ 'verbose' => array(
+ 'type' => 'integer',
+ 'default' => PEAR_CONFIG_DEFAULT_VERBOSE,
+ 'doc' => 'verbosity level
+0: really quiet
+1: somewhat quiet
+2: verbose
+3: debug',
+ 'prompt' => 'Debug Log Level',
+ 'group' => 'Advanced',
+ ),
+ 'preferred_state' => array(
+ 'type' => 'set',
+ 'default' => PEAR_CONFIG_DEFAULT_PREFERRED_STATE,
+ 'doc' => 'the installer will prefer releases with this state when installing packages without a version or state specified',
+ 'valid_set' => array(
+ 'stable', 'beta', 'alpha', 'devel', 'snapshot'),
+ 'prompt' => 'Preferred Package State',
+ 'group' => 'Advanced',
+ ),
+ 'umask' => array(
+ 'type' => 'mask',
+ 'default' => PEAR_CONFIG_DEFAULT_UMASK,
+ 'doc' => 'umask used when creating files (Unix-like systems only)',
+ 'prompt' => 'Unix file mask',
+ 'group' => 'Advanced',
+ ),
+ 'cache_ttl' => array(
+ 'type' => 'integer',
+ 'default' => PEAR_CONFIG_DEFAULT_CACHE_TTL,
+ 'doc' => 'amount of secs where the local cache is used and not updated',
+ 'prompt' => 'Cache TimeToLive',
+ 'group' => 'Advanced',
+ ),
+ 'sig_type' => array(
+ 'type' => 'set',
+ 'default' => PEAR_CONFIG_DEFAULT_SIG_TYPE,
+ 'doc' => 'which package signature mechanism to use',
+ 'valid_set' => array('gpg'),
+ 'prompt' => 'Package Signature Type',
+ 'group' => 'Maintainers',
+ ),
+ 'sig_bin' => array(
+ 'type' => 'string',
+ 'default' => PEAR_CONFIG_DEFAULT_SIG_BIN,
+ 'doc' => 'which package signature mechanism to use',
+ 'prompt' => 'Signature Handling Program',
+ 'group' => 'Maintainers',
+ ),
+ 'sig_keyid' => array(
+ 'type' => 'string',
+ 'default' => '',
+ 'doc' => 'which key to use for signing with',
+ 'prompt' => 'Signature Key Id',
+ 'group' => 'Maintainers',
+ ),
+ 'sig_keydir' => array(
+ 'type' => 'directory',
+ 'default' => PEAR_CONFIG_DEFAULT_SIG_KEYDIR,
+ 'doc' => 'directory where signature keys are located',
+ 'prompt' => 'Signature Key Directory',
+ 'group' => 'Maintainers',
+ ),
+ // __channels is reserved - used for channel-specific configuration
+ );
+
+ /**
+ * Constructor.
+ *
+ * @param string file to read user-defined options from
+ * @param string file to read system-wide defaults from
+ * @param bool determines whether a registry object "follows"
+ * the value of php_dir (is automatically created
+ * and moved when php_dir is changed)
+ * @param bool if true, fails if configuration files cannot be loaded
+ *
+ * @access public
+ *
+ * @see PEAR_Config::singleton
+ */
+ function __construct($user_file = '', $system_file = '', $ftp_file = false,
+ $strict = true)
+ {
+ parent::__construct();
+ PEAR_Installer_Role::initializeConfig($this);
+ $sl = DIRECTORY_SEPARATOR;
+ if (empty($user_file)) {
+ if (OS_WINDOWS) {
+ $user_file = PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini';
+ } else {
+ $user_file = getenv('HOME') . $sl . '.pearrc';
+ }
+ }
+
+ if (empty($system_file)) {
+ $system_file = PEAR_CONFIG_SYSCONFDIR . $sl;
+ if (OS_WINDOWS) {
+ $system_file .= 'pearsys.ini';
+ } else {
+ $system_file .= 'pear.conf';
+ }
+ }
+
+ $this->layers = array_keys($this->configuration);
+ $this->files['user'] = $user_file;
+ $this->files['system'] = $system_file;
+ if ($user_file && file_exists($user_file)) {
+ $this->pushErrorHandling(PEAR_ERROR_RETURN);
+ $this->readConfigFile($user_file, 'user', $strict);
+ $this->popErrorHandling();
+ if ($this->_errorsFound > 0) {
+ return;
+ }
+ }
+
+ if ($system_file && @file_exists($system_file)) {
+ $this->mergeConfigFile($system_file, false, 'system', $strict);
+ if ($this->_errorsFound > 0) {
+ return;
+ }
+
+ }
+
+ if (!$ftp_file) {
+ $ftp_file = $this->get('remote_config');
+ }
+
+ if ($ftp_file && defined('PEAR_REMOTEINSTALL_OK')) {
+ $this->readFTPConfigFile($ftp_file);
+ }
+
+ foreach ($this->configuration_info as $key => $info) {
+ $this->configuration['default'][$key] = $info['default'];
+ }
+
+ $this->_registry['default'] = new PEAR_Registry(
+ $this->configuration['default']['php_dir'], false, false,
+ $this->configuration['default']['metadata_dir']);
+ $this->_registry['default']->setConfig($this, false);
+ $this->_regInitialized['default'] = false;
+ //$GLOBALS['_PEAR_Config_instance'] = &$this;
+ }
+
+ /**
+ * Return the default locations of user and system configuration files
+ */
+ public static function getDefaultConfigFiles()
+ {
+ $sl = DIRECTORY_SEPARATOR;
+ if (OS_WINDOWS) {
+ return array(
+ 'user' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini',
+ 'system' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pearsys.ini'
+ );
+ }
+
+ return array(
+ 'user' => getenv('HOME') . $sl . '.pearrc',
+ 'system' => PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.conf'
+ );
+ }
+
+ /**
+ * Static singleton method. If you want to keep only one instance
+ * of this class in use, this method will give you a reference to
+ * the last created PEAR_Config object if one exists, or create a
+ * new object.
+ *
+ * @param string (optional) file to read user-defined options from
+ * @param string (optional) file to read system-wide defaults from
+ *
+ * @return object an existing or new PEAR_Config instance
+ *
+ * @see PEAR_Config::PEAR_Config
+ */
+ public static function &singleton($user_file = '', $system_file = '', $strict = true)
+ {
+ if (is_object($GLOBALS['_PEAR_Config_instance'])) {
+ return $GLOBALS['_PEAR_Config_instance'];
+ }
+
+ $t_conf = new PEAR_Config($user_file, $system_file, false, $strict);
+ if ($t_conf->_errorsFound > 0) {
+ return $t_conf->lastError;
+ }
+
+ $GLOBALS['_PEAR_Config_instance'] = &$t_conf;
+ return $GLOBALS['_PEAR_Config_instance'];
+ }
+
+ /**
+ * Determine whether any configuration files have been detected, and whether a
+ * registry object can be retrieved from this configuration.
+ * @return bool
+ * @since PEAR 1.4.0a1
+ */
+ function validConfiguration()
+ {
+ if ($this->isDefinedLayer('user') || $this->isDefinedLayer('system')) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Reads configuration data from a file. All existing values in
+ * the config layer are discarded and replaced with data from the
+ * file.
+ * @param string file to read from, if NULL or not specified, the
+ * last-used file for the same layer (second param) is used
+ * @param string config layer to insert data into ('user' or 'system')
+ * @return bool TRUE on success or a PEAR error on failure
+ */
+ function readConfigFile($file = null, $layer = 'user', $strict = true)
+ {
+ if (empty($this->files[$layer])) {
+ return $this->raiseError("unknown config layer `$layer'");
+ }
+
+ if ($file === null) {
+ $file = $this->files[$layer];
+ }
+
+ $data = $this->_readConfigDataFrom($file);
+ if (PEAR::isError($data)) {
+ if (!$strict) {
+ return true;
+ }
+
+ $this->_errorsFound++;
+ $this->lastError = $data;
+
+ return $data;
+ }
+
+ $this->files[$layer] = $file;
+ $this->_decodeInput($data);
+ $this->configuration[$layer] = $data;
+ $this->_setupChannels();
+ if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) {
+ $this->_registry[$layer] = new PEAR_Registry(
+ $phpdir, false, false,
+ $this->get('metadata_dir', $layer, 'pear.php.net'));
+ $this->_registry[$layer]->setConfig($this, false);
+ $this->_regInitialized[$layer] = false;
+ } else {
+ unset($this->_registry[$layer]);
+ }
+ return true;
+ }
+
+ /**
+ * @param string url to the remote config file, like ftp://www.example.com/pear/config.ini
+ * @return true|PEAR_Error
+ */
+ function readFTPConfigFile($path)
+ {
+ do { // poor man's try
+ if (!class_exists('PEAR_FTP')) {
+ if (!class_exists('PEAR_Common')) {
+ require_once 'PEAR/Common.php';
+ }
+ if (PEAR_Common::isIncludeable('PEAR/FTP.php')) {
+ require_once 'PEAR/FTP.php';
+ }
+ }
+
+ if (!class_exists('PEAR_FTP')) {
+ return PEAR::raiseError('PEAR_RemoteInstaller must be installed to use remote config');
+ }
+
+ $this->_ftp = new PEAR_FTP;
+ $this->_ftp->pushErrorHandling(PEAR_ERROR_RETURN);
+ $e = $this->_ftp->init($path);
+ if (PEAR::isError($e)) {
+ $this->_ftp->popErrorHandling();
+ return $e;
+ }
+
+ $tmp = System::mktemp('-d');
+ PEAR_Common::addTempFile($tmp);
+ $e = $this->_ftp->get(basename($path), $tmp . DIRECTORY_SEPARATOR .
+ 'pear.ini', false, FTP_BINARY);
+ if (PEAR::isError($e)) {
+ $this->_ftp->popErrorHandling();
+ return $e;
+ }
+
+ PEAR_Common::addTempFile($tmp . DIRECTORY_SEPARATOR . 'pear.ini');
+ $this->_ftp->disconnect();
+ $this->_ftp->popErrorHandling();
+ $this->files['ftp'] = $tmp . DIRECTORY_SEPARATOR . 'pear.ini';
+ $e = $this->readConfigFile(null, 'ftp');
+ if (PEAR::isError($e)) {
+ return $e;
+ }
+
+ $fail = array();
+ foreach ($this->configuration_info as $key => $val) {
+ if (in_array($this->getGroup($key),
+ array('File Locations', 'File Locations (Advanced)')) &&
+ $this->getType($key) == 'directory') {
+ // any directory configs must be set for this to work
+ if (!isset($this->configuration['ftp'][$key])) {
+ $fail[] = $key;
+ }
+ }
+ }
+
+ if (!count($fail)) {
+ return true;
+ }
+
+ $fail = '"' . implode('", "', $fail) . '"';
+ unset($this->files['ftp']);
+ unset($this->configuration['ftp']);
+ return PEAR::raiseError('ERROR: Ftp configuration file must set all ' .
+ 'directory configuration variables. These variables were not set: ' .
+ $fail);
+ } while (false); // poor man's catch
+ unset($this->files['ftp']);
+ return PEAR::raiseError('no remote host specified');
+ }
+
+ /**
+ * Reads the existing configurations and creates the _channels array from it
+ */
+ function _setupChannels()
+ {
+ $set = array_flip(array_values($this->_channels));
+ foreach ($this->configuration as $layer => $data) {
+ $i = 1000;
+ if (isset($data['__channels']) && is_array($data['__channels'])) {
+ foreach ($data['__channels'] as $channel => $info) {
+ $set[$channel] = $i++;
+ }
+ }
+ }
+ $this->_channels = array_values(array_flip($set));
+ $this->setChannels($this->_channels);
+ }
+
+ function deleteChannel($channel)
+ {
+ $ch = strtolower($channel);
+ foreach ($this->configuration as $layer => $data) {
+ if (isset($data['__channels']) && isset($data['__channels'][$ch])) {
+ unset($this->configuration[$layer]['__channels'][$ch]);
+ }
+ }
+
+ $this->_channels = array_flip($this->_channels);
+ unset($this->_channels[$ch]);
+ $this->_channels = array_flip($this->_channels);
+ }
+
+ /**
+ * Merges data into a config layer from a file. Does the same
+ * thing as readConfigFile, except it does not replace all
+ * existing values in the config layer.
+ * @param string file to read from
+ * @param bool whether to overwrite existing data (default TRUE)
+ * @param string config layer to insert data into ('user' or 'system')
+ * @param string if true, errors are returned if file opening fails
+ * @return bool TRUE on success or a PEAR error on failure
+ */
+ function mergeConfigFile($file, $override = true, $layer = 'user', $strict = true)
+ {
+ if (empty($this->files[$layer])) {
+ return $this->raiseError("unknown config layer `$layer'");
+ }
+
+ if ($file === null) {
+ $file = $this->files[$layer];
+ }
+
+ $data = $this->_readConfigDataFrom($file);
+ if (PEAR::isError($data)) {
+ if (!$strict) {
+ return true;
+ }
+
+ $this->_errorsFound++;
+ $this->lastError = $data;
+
+ return $data;
+ }
+
+ $this->_decodeInput($data);
+ if ($override) {
+ $this->configuration[$layer] =
+ PEAR_Config::arrayMergeRecursive($this->configuration[$layer], $data);
+ } else {
+ $this->configuration[$layer] =
+ PEAR_Config::arrayMergeRecursive($data, $this->configuration[$layer]);
+ }
+
+ $this->_setupChannels();
+ if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) {
+ $this->_registry[$layer] = new PEAR_Registry(
+ $phpdir, false, false,
+ $this->get('metadata_dir', $layer, 'pear.php.net'));
+ $this->_registry[$layer]->setConfig($this, false);
+ $this->_regInitialized[$layer] = false;
+ } else {
+ unset($this->_registry[$layer]);
+ }
+ return true;
+ }
+
+ /**
+ * @param array
+ * @param array
+ * @return array
+ */
+ public static function arrayMergeRecursive($arr2, $arr1)
+ {
+ $ret = array();
+ foreach ($arr2 as $key => $data) {
+ if (!isset($arr1[$key])) {
+ $ret[$key] = $data;
+ unset($arr1[$key]);
+ continue;
+ }
+ if (is_array($data)) {
+ if (!is_array($arr1[$key])) {
+ $ret[$key] = $arr1[$key];
+ unset($arr1[$key]);
+ continue;
+ }
+ $ret[$key] = PEAR_Config::arrayMergeRecursive($arr1[$key], $arr2[$key]);
+ unset($arr1[$key]);
+ }
+ }
+
+ return array_merge($ret, $arr1);
+ }
+
+ /**
+ * Writes data into a config layer from a file.
+ *
+ * @param string|null file to read from, or null for default
+ * @param string config layer to insert data into ('user' or
+ * 'system')
+ * @param string|null data to write to config file or null for internal data [DEPRECATED]
+ * @return bool TRUE on success or a PEAR error on failure
+ */
+ function writeConfigFile($file = null, $layer = 'user', $data = null)
+ {
+ $this->_lazyChannelSetup($layer);
+ if ($layer == 'both' || $layer == 'all') {
+ foreach ($this->files as $type => $file) {
+ $err = $this->writeConfigFile($file, $type, $data);
+ if (PEAR::isError($err)) {
+ return $err;
+ }
+ }
+ return true;
+ }
+
+ if (empty($this->files[$layer])) {
+ return $this->raiseError("unknown config file type `$layer'");
+ }
+
+ if ($file === null) {
+ $file = $this->files[$layer];
+ }
+
+ $data = ($data === null) ? $this->configuration[$layer] : $data;
+ $this->_encodeOutput($data);
+ $opt = array('-p', dirname($file));
+ if (!@System::mkDir($opt)) {
+ return $this->raiseError("could not create directory: " . dirname($file));
+ }
+
+ if (file_exists($file) && is_file($file) && !is_writeable($file)) {
+ return $this->raiseError("no write access to $file!");
+ }
+
+ $fp = @fopen($file, "w");
+ if (!$fp) {
+ return $this->raiseError("PEAR_Config::writeConfigFile fopen('$file','w') failed ($php_errormsg)");
+ }
+
+ $contents = "#PEAR_Config 0.9\n" . serialize($data);
+ if (!@fwrite($fp, $contents)) {
+ return $this->raiseError("PEAR_Config::writeConfigFile: fwrite failed ($php_errormsg)");
+ }
+ return true;
+ }
+
+ /**
+ * Reads configuration data from a file and returns the parsed data
+ * in an array.
+ *
+ * @param string file to read from
+ * @return array configuration data or a PEAR error on failure
+ * @access private
+ */
+ function _readConfigDataFrom($file)
+ {
+ $fp = false;
+ if (file_exists($file)) {
+ $fp = @fopen($file, "r");
+ }
+
+ if (!$fp) {
+ return $this->raiseError("PEAR_Config::readConfigFile fopen('$file','r') failed");
+ }
+
+ $size = filesize($file);
+ fclose($fp);
+ $contents = file_get_contents($file);
+ if (empty($contents)) {
+ return $this->raiseError('Configuration file "' . $file . '" is empty');
+ }
+
+ $version = false;
+ if (preg_match('/^#PEAR_Config\s+(\S+)\s+/si', $contents, $matches)) {
+ $version = $matches[1];
+ $contents = substr($contents, strlen($matches[0]));
+ } else {
+ // Museum config file
+ if (substr($contents,0,2) == 'a:') {
+ $version = '0.1';
+ }
+ }
+
+ if ($version && version_compare("$version", '1', '<')) {
+ // no '@', it is possible that unserialize
+ // raises a notice but it seems to block IO to
+ // STDOUT if a '@' is used and a notice is raise
+ $data = unserialize($contents);
+
+ if (!is_array($data) && !$data) {
+ if ($contents == serialize(false)) {
+ $data = array();
+ } else {
+ $err = $this->raiseError("PEAR_Config: bad data in $file");
+ return $err;
+ }
+ }
+ if (!is_array($data)) {
+ if (strlen(trim($contents)) > 0) {
+ $error = "PEAR_Config: bad data in $file";
+ $err = $this->raiseError($error);
+ return $err;
+ }
+
+ $data = array();
+ }
+ // add parsing of newer formats here...
+ } else {
+ $err = $this->raiseError("$file: unknown version `$version'");
+ return $err;
+ }
+
+ return $data;
+ }
+
+ /**
+ * Gets the file used for storing the config for a layer
+ *
+ * @param string $layer 'user' or 'system'
+ */
+ function getConfFile($layer)
+ {
+ return $this->files[$layer];
+ }
+
+ /**
+ * @param string Configuration class name, used for detecting duplicate calls
+ * @param array information on a role as parsed from its xml file
+ * @return true|PEAR_Error
+ * @access private
+ */
+ function _addConfigVars($class, $vars)
+ {
+ static $called = array();
+ if (isset($called[$class])) {
+ return;
+ }
+
+ $called[$class] = 1;
+ if (count($vars) > 3) {
+ return $this->raiseError('Roles can only define 3 new config variables or less');
+ }
+
+ foreach ($vars as $name => $var) {
+ if (!is_array($var)) {
+ return $this->raiseError('Configuration information must be an array');
+ }
+
+ if (!isset($var['type'])) {
+ return $this->raiseError('Configuration information must contain a type');
+ } elseif (!in_array($var['type'],
+ array('string', 'mask', 'password', 'directory', 'file', 'set'))) {
+ return $this->raiseError(
+ 'Configuration type must be one of directory, file, string, ' .
+ 'mask, set, or password');
+ }
+ if (!isset($var['default'])) {
+ return $this->raiseError(
+ 'Configuration information must contain a default value ("default" index)');
+ }
+
+ if (is_array($var['default'])) {
+ $real_default = '';
+ foreach ($var['default'] as $config_var => $val) {
+ if (strpos($config_var, 'text') === 0) {
+ $real_default .= $val;
+ } elseif (strpos($config_var, 'constant') === 0) {
+ if (!defined($val)) {
+ return $this->raiseError(
+ 'Unknown constant "' . $val . '" requested in ' .
+ 'default value for configuration variable "' .
+ $name . '"');
+ }
+
+ $real_default .= constant($val);
+ } elseif (isset($this->configuration_info[$config_var])) {
+ $real_default .=
+ $this->configuration_info[$config_var]['default'];
+ } else {
+ return $this->raiseError(
+ 'Unknown request for "' . $config_var . '" value in ' .
+ 'default value for configuration variable "' .
+ $name . '"');
+ }
+ }
+ $var['default'] = $real_default;
+ }
+
+ if ($var['type'] == 'integer') {
+ $var['default'] = (integer) $var['default'];
+ }
+
+ if (!isset($var['doc'])) {
+ return $this->raiseError(
+ 'Configuration information must contain a summary ("doc" index)');
+ }
+
+ if (!isset($var['prompt'])) {
+ return $this->raiseError(
+ 'Configuration information must contain a simple prompt ("prompt" index)');
+ }
+
+ if (!isset($var['group'])) {
+ return $this->raiseError(
+ 'Configuration information must contain a simple group ("group" index)');
+ }
+
+ if (isset($this->configuration_info[$name])) {
+ return $this->raiseError('Configuration variable "' . $name .
+ '" already exists');
+ }
+
+ $this->configuration_info[$name] = $var;
+ // fix bug #7351: setting custom config variable in a channel fails
+ $this->_channelConfigInfo[] = $name;
+ }
+
+ return true;
+ }
+
+ /**
+ * Encodes/scrambles configuration data before writing to files.
+ * Currently, 'password' values will be base64-encoded as to avoid
+ * that people spot cleartext passwords by accident.
+ *
+ * @param array (reference) array to encode values in
+ * @return bool TRUE on success
+ * @access private
+ */
+ function _encodeOutput(&$data)
+ {
+ foreach ($data as $key => $value) {
+ if ($key == '__channels') {
+ foreach ($data['__channels'] as $channel => $blah) {
+ $this->_encodeOutput($data['__channels'][$channel]);
+ }
+ }
+
+ if (!isset($this->configuration_info[$key])) {
+ continue;
+ }
+
+ $type = $this->configuration_info[$key]['type'];
+ switch ($type) {
+ // we base64-encode passwords so they are at least
+ // not shown in plain by accident
+ case 'password': {
+ $data[$key] = base64_encode($data[$key]);
+ break;
+ }
+ case 'mask': {
+ $data[$key] = octdec($data[$key]);
+ break;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Decodes/unscrambles configuration data after reading from files.
+ *
+ * @param array (reference) array to encode values in
+ * @return bool TRUE on success
+ * @access private
+ *
+ * @see PEAR_Config::_encodeOutput
+ */
+ function _decodeInput(&$data)
+ {
+ if (!is_array($data)) {
+ return true;
+ }
+
+ foreach ($data as $key => $value) {
+ if ($key == '__channels') {
+ foreach ($data['__channels'] as $channel => $blah) {
+ $this->_decodeInput($data['__channels'][$channel]);
+ }
+ }
+
+ if (!isset($this->configuration_info[$key])) {
+ continue;
+ }
+
+ $type = $this->configuration_info[$key]['type'];
+ switch ($type) {
+ case 'password': {
+ $data[$key] = base64_decode($data[$key]);
+ break;
+ }
+ case 'mask': {
+ $data[$key] = decoct($data[$key]);
+ break;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Retrieve the default channel.
+ *
+ * On startup, channels are not initialized, so if the default channel is not
+ * pear.php.net, then initialize the config.
+ * @param string registry layer
+ * @return string|false
+ */
+ function getDefaultChannel($layer = null)
+ {
+ $ret = false;
+ if ($layer === null) {
+ foreach ($this->layers as $layer) {
+ if (isset($this->configuration[$layer]['default_channel'])) {
+ $ret = $this->configuration[$layer]['default_channel'];
+ break;
+ }
+ }
+ } elseif (isset($this->configuration[$layer]['default_channel'])) {
+ $ret = $this->configuration[$layer]['default_channel'];
+ }
+
+ if ($ret == 'pear.php.net' && defined('PEAR_RUNTYPE') && PEAR_RUNTYPE == 'pecl') {
+ $ret = 'pecl.php.net';
+ }
+
+ if ($ret) {
+ if ($ret != 'pear.php.net') {
+ $this->_lazyChannelSetup();
+ }
+
+ return $ret;
+ }
+
+ return PEAR_CONFIG_DEFAULT_CHANNEL;
+ }
+
+ /**
+ * Returns a configuration value, prioritizing layers as per the
+ * layers property.
+ *
+ * @param string config key
+ * @return mixed the config value, or NULL if not found
+ * @access public
+ */
+ function get($key, $layer = null, $channel = false)
+ {
+ if (!isset($this->configuration_info[$key])) {
+ return null;
+ }
+
+ if ($key == '__channels') {
+ return null;
+ }
+
+ if ($key == 'default_channel') {
+ return $this->getDefaultChannel($layer);
+ }
+
+ if (!$channel) {
+ $channel = $this->getDefaultChannel();
+ } elseif ($channel != 'pear.php.net') {
+ $this->_lazyChannelSetup();
+ }
+ $channel = strtolower($channel);
+
+ $test = (in_array($key, $this->_channelConfigInfo)) ?
+ $this->_getChannelValue($key, $layer, $channel) :
+ null;
+ if ($test !== null) {
+ if ($this->_installRoot) {
+ if (in_array($this->getGroup($key),
+ array('File Locations', 'File Locations (Advanced)')) &&
+ $this->getType($key) == 'directory') {
+ return $this->_prependPath($test, $this->_installRoot);
+ }
+ }
+ return $test;
+ }
+
+ if ($layer === null) {
+ foreach ($this->layers as $layer) {
+ if (isset($this->configuration[$layer][$key])) {
+ $test = $this->configuration[$layer][$key];
+ if ($this->_installRoot) {
+ if (in_array($this->getGroup($key),
+ array('File Locations', 'File Locations (Advanced)')) &&
+ $this->getType($key) == 'directory') {
+ return $this->_prependPath($test, $this->_installRoot);
+ }
+ }
+
+ if ($key == 'preferred_mirror') {
+ $reg = &$this->getRegistry();
+ if (is_object($reg)) {
+ $chan = $reg->getChannel($channel);
+ if (PEAR::isError($chan)) {
+ return $channel;
+ }
+
+ if (!$chan->getMirror($test) && $chan->getName() != $test) {
+ return $channel; // mirror does not exist
+ }
+ }
+ }
+ return $test;
+ }
+ }
+ } elseif (isset($this->configuration[$layer][$key])) {
+ $test = $this->configuration[$layer][$key];
+ if ($this->_installRoot) {
+ if (in_array($this->getGroup($key),
+ array('File Locations', 'File Locations (Advanced)')) &&
+ $this->getType($key) == 'directory') {
+ return $this->_prependPath($test, $this->_installRoot);
+ }
+ }
+
+ if ($key == 'preferred_mirror') {
+ $reg = &$this->getRegistry();
+ if (is_object($reg)) {
+ $chan = $reg->getChannel($channel);
+ if (PEAR::isError($chan)) {
+ return $channel;
+ }
+
+ if (!$chan->getMirror($test) && $chan->getName() != $test) {
+ return $channel; // mirror does not exist
+ }
+ }
+ }
+
+ return $test;
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns a channel-specific configuration value, prioritizing layers as per the
+ * layers property.
+ *
+ * @param string config key
+ * @return mixed the config value, or NULL if not found
+ * @access private
+ */
+ function _getChannelValue($key, $layer, $channel)
+ {
+ if ($key == '__channels' || $channel == 'pear.php.net') {
+ return null;
+ }
+
+ $ret = null;
+ if ($layer === null) {
+ foreach ($this->layers as $ilayer) {
+ if (isset($this->configuration[$ilayer]['__channels'][$channel][$key])) {
+ $ret = $this->configuration[$ilayer]['__channels'][$channel][$key];
+ break;
+ }
+ }
+ } elseif (isset($this->configuration[$layer]['__channels'][$channel][$key])) {
+ $ret = $this->configuration[$layer]['__channels'][$channel][$key];
+ }
+
+ if ($key != 'preferred_mirror') {
+ return $ret;
+ }
+
+
+ if ($ret !== null) {
+ $reg = &$this->getRegistry($layer);
+ if (is_object($reg)) {
+ $chan = $reg->getChannel($channel);
+ if (PEAR::isError($chan)) {
+ return $channel;
+ }
+
+ if (!$chan->getMirror($ret) && $chan->getName() != $ret) {
+ return $channel; // mirror does not exist
+ }
+ }
+
+ return $ret;
+ }
+
+ if ($channel != $this->getDefaultChannel($layer)) {
+ return $channel; // we must use the channel name as the preferred mirror
+ // if the user has not chosen an alternate
+ }
+
+ return $this->getDefaultChannel($layer);
+ }
+
+ /**
+ * Set a config value in a specific layer (defaults to 'user').
+ * Enforces the types defined in the configuration_info array. An
+ * integer config variable will be cast to int, and a set config
+ * variable will be validated against its legal values.
+ *
+ * @param string config key
+ * @param string config value
+ * @param string (optional) config layer
+ * @param string channel to set this value for, or null for global value
+ * @return bool TRUE on success, FALSE on failure
+ */
+ function set($key, $value, $layer = 'user', $channel = false)
+ {
+ if ($key == '__channels') {
+ return false;
+ }
+
+ if (!isset($this->configuration[$layer])) {
+ return false;
+ }
+
+ if ($key == 'default_channel') {
+ // can only set this value globally
+ $channel = 'pear.php.net';
+ if ($value != 'pear.php.net') {
+ $this->_lazyChannelSetup($layer);
+ }
+ }
+
+ if ($key == 'preferred_mirror') {
+ if ($channel == '__uri') {
+ return false; // can't set the __uri pseudo-channel's mirror
+ }
+
+ $reg = &$this->getRegistry($layer);
+ if (is_object($reg)) {
+ $chan = $reg->getChannel($channel ? $channel : 'pear.php.net');
+ if (PEAR::isError($chan)) {
+ return false;
+ }
+
+ if (!$chan->getMirror($value) && $chan->getName() != $value) {
+ return false; // mirror does not exist
+ }
+ }
+ }
+
+ if (!isset($this->configuration_info[$key])) {
+ return false;
+ }
+
+ extract($this->configuration_info[$key]);
+ switch ($type) {
+ case 'integer':
+ $value = (int)$value;
+ break;
+ case 'set': {
+ // If a valid_set is specified, require the value to
+ // be in the set. If there is no valid_set, accept
+ // any value.
+ if ($valid_set) {
+ reset($valid_set);
+ if ((key($valid_set) === 0 && !in_array($value, $valid_set)) ||
+ (key($valid_set) !== 0 && empty($valid_set[$value])))
+ {
+ return false;
+ }
+ }
+ break;
+ }
+ }
+
+ if (!$channel) {
+ $channel = $this->get('default_channel', null, 'pear.php.net');
+ }
+
+ if (!in_array($channel, $this->_channels)) {
+ $this->_lazyChannelSetup($layer);
+ $reg = &$this->getRegistry($layer);
+ if ($reg) {
+ $channel = $reg->channelName($channel);
+ }
+
+ if (!in_array($channel, $this->_channels)) {
+ return false;
+ }
+ }
+
+ if ($channel != 'pear.php.net') {
+ if (in_array($key, $this->_channelConfigInfo)) {
+ $this->configuration[$layer]['__channels'][$channel][$key] = $value;
+ return true;
+ }
+
+ return false;
+ }
+
+ if ($key == 'default_channel') {
+ if (!isset($reg)) {
+ $reg = &$this->getRegistry($layer);
+ if (!$reg) {
+ $reg = &$this->getRegistry();
+ }
+ }
+
+ if ($reg) {
+ $value = $reg->channelName($value);
+ }
+
+ if (!$value) {
+ return false;
+ }
+ }
+
+ $this->configuration[$layer][$key] = $value;
+ if ($key == 'php_dir' && !$this->_noRegistry) {
+ if (!isset($this->_registry[$layer]) ||
+ $value != $this->_registry[$layer]->install_dir) {
+ $this->_registry[$layer] = new PEAR_Registry($value);
+ $this->_regInitialized[$layer] = false;
+ $this->_registry[$layer]->setConfig($this, false);
+ }
+ }
+
+ return true;
+ }
+
+ function _lazyChannelSetup($uselayer = false)
+ {
+ if ($this->_noRegistry) {
+ return;
+ }
+
+ $merge = false;
+ foreach ($this->_registry as $layer => $p) {
+ if ($uselayer && $uselayer != $layer) {
+ continue;
+ }
+
+ if (!$this->_regInitialized[$layer]) {
+ if ($layer == 'default' && isset($this->_registry['user']) ||
+ isset($this->_registry['system'])) {
+ // only use the default registry if there are no alternatives
+ continue;
+ }
+
+ if (!is_object($this->_registry[$layer])) {
+ if ($phpdir = $this->get('php_dir', $layer, 'pear.php.net')) {
+ $this->_registry[$layer] = new PEAR_Registry(
+ $phpdir, false, false,
+ $this->get('metadata_dir', $layer, 'pear.php.net'));
+ $this->_registry[$layer]->setConfig($this, false);
+ $this->_regInitialized[$layer] = false;
+ } else {
+ unset($this->_registry[$layer]);
+ return;
+ }
+ }
+
+ $this->setChannels($this->_registry[$layer]->listChannels(), $merge);
+ $this->_regInitialized[$layer] = true;
+ $merge = true;
+ }
+ }
+ }
+
+ /**
+ * Set the list of channels.
+ *
+ * This should be set via a call to {@link PEAR_Registry::listChannels()}
+ * @param array
+ * @param bool
+ * @return bool success of operation
+ */
+ function setChannels($channels, $merge = false)
+ {
+ if (!is_array($channels)) {
+ return false;
+ }
+
+ if ($merge) {
+ $this->_channels = array_merge($this->_channels, $channels);
+ } else {
+ $this->_channels = $channels;
+ }
+
+ foreach ($channels as $channel) {
+ $channel = strtolower($channel);
+ if ($channel == 'pear.php.net') {
+ continue;
+ }
+
+ foreach ($this->layers as $layer) {
+ if (!isset($this->configuration[$layer]['__channels'])) {
+ $this->configuration[$layer]['__channels'] = array();
+ }
+ if (!isset($this->configuration[$layer]['__channels'][$channel])
+ || !is_array($this->configuration[$layer]['__channels'][$channel])) {
+ $this->configuration[$layer]['__channels'][$channel] = array();
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Get the type of a config value.
+ *
+ * @param string config key
+ *
+ * @return string type, one of "string", "integer", "file",
+ * "directory", "set" or "password".
+ *
+ * @access public
+ *
+ */
+ function getType($key)
+ {
+ if (isset($this->configuration_info[$key])) {
+ return $this->configuration_info[$key]['type'];
+ }
+ return false;
+ }
+
+ /**
+ * Get the documentation for a config value.
+ *
+ * @param string config key
+ * @return string documentation string
+ *
+ * @access public
+ *
+ */
+ function getDocs($key)
+ {
+ if (isset($this->configuration_info[$key])) {
+ return $this->configuration_info[$key]['doc'];
+ }
+
+ return false;
+ }
+
+ /**
+ * Get the short documentation for a config value.
+ *
+ * @param string config key
+ * @return string short documentation string
+ *
+ * @access public
+ *
+ */
+ function getPrompt($key)
+ {
+ if (isset($this->configuration_info[$key])) {
+ return $this->configuration_info[$key]['prompt'];
+ }
+
+ return false;
+ }
+
+ /**
+ * Get the parameter group for a config key.
+ *
+ * @param string config key
+ * @return string parameter group
+ *
+ * @access public
+ *
+ */
+ function getGroup($key)
+ {
+ if (isset($this->configuration_info[$key])) {
+ return $this->configuration_info[$key]['group'];
+ }
+
+ return false;
+ }
+
+ /**
+ * Get the list of parameter groups.
+ *
+ * @return array list of parameter groups
+ *
+ * @access public
+ *
+ */
+ function getGroups()
+ {
+ $tmp = array();
+ foreach ($this->configuration_info as $key => $info) {
+ $tmp[$info['group']] = 1;
+ }
+
+ return array_keys($tmp);
+ }
+
+ /**
+ * Get the list of the parameters in a group.
+ *
+ * @param string $group parameter group
+ * @return array list of parameters in $group
+ *
+ * @access public
+ *
+ */
+ function getGroupKeys($group)
+ {
+ $keys = array();
+ foreach ($this->configuration_info as $key => $info) {
+ if ($info['group'] == $group) {
+ $keys[] = $key;
+ }
+ }
+
+ return $keys;
+ }
+
+ /**
+ * Get the list of allowed set values for a config value. Returns
+ * NULL for config values that are not sets.
+ *
+ * @param string config key
+ * @return array enumerated array of set values, or NULL if the
+ * config key is unknown or not a set
+ *
+ * @access public
+ *
+ */
+ function getSetValues($key)
+ {
+ if (isset($this->configuration_info[$key]) &&
+ isset($this->configuration_info[$key]['type']) &&
+ $this->configuration_info[$key]['type'] == 'set')
+ {
+ $valid_set = $this->configuration_info[$key]['valid_set'];
+ reset($valid_set);
+ if (key($valid_set) === 0) {
+ return $valid_set;
+ }
+
+ return array_keys($valid_set);
+ }
+
+ return null;
+ }
+
+ /**
+ * Get all the current config keys.
+ *
+ * @return array simple array of config keys
+ *
+ * @access public
+ */
+ function getKeys()
+ {
+ $keys = array();
+ foreach ($this->layers as $layer) {
+ $test = $this->configuration[$layer];
+ if (isset($test['__channels'])) {
+ foreach ($test['__channels'] as $channel => $configs) {
+ $keys = array_merge($keys, $configs);
+ }
+ }
+
+ unset($test['__channels']);
+ $keys = array_merge($keys, $test);
+
+ }
+ return array_keys($keys);
+ }
+
+ /**
+ * Remove the a config key from a specific config layer.
+ *
+ * @param string config key
+ * @param string (optional) config layer
+ * @param string (optional) channel (defaults to default channel)
+ * @return bool TRUE on success, FALSE on failure
+ *
+ * @access public
+ */
+ function remove($key, $layer = 'user', $channel = null)
+ {
+ if ($channel === null) {
+ $channel = $this->getDefaultChannel();
+ }
+
+ if ($channel !== 'pear.php.net') {
+ if (isset($this->configuration[$layer]['__channels'][$channel][$key])) {
+ unset($this->configuration[$layer]['__channels'][$channel][$key]);
+ return true;
+ }
+ }
+
+ if (isset($this->configuration[$layer][$key])) {
+ unset($this->configuration[$layer][$key]);
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Temporarily remove an entire config layer. USE WITH CARE!
+ *
+ * @param string config key
+ * @param string (optional) config layer
+ * @return bool TRUE on success, FALSE on failure
+ *
+ * @access public
+ */
+ function removeLayer($layer)
+ {
+ if (isset($this->configuration[$layer])) {
+ $this->configuration[$layer] = array();
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Stores configuration data in a layer.
+ *
+ * @param string config layer to store
+ * @return bool TRUE on success, or PEAR error on failure
+ *
+ * @access public
+ */
+ function store($layer = 'user', $data = null)
+ {
+ return $this->writeConfigFile(null, $layer, $data);
+ }
+
+ /**
+ * Tells what config layer that gets to define a key.
+ *
+ * @param string config key
+ * @param boolean return the defining channel
+ *
+ * @return string|array the config layer, or an empty string if not found.
+ *
+ * if $returnchannel, the return is an array array('layer' => layername,
+ * 'channel' => channelname), or an empty string if not found
+ *
+ * @access public
+ */
+ function definedBy($key, $returnchannel = false)
+ {
+ foreach ($this->layers as $layer) {
+ $channel = $this->getDefaultChannel();
+ if ($channel !== 'pear.php.net') {
+ if (isset($this->configuration[$layer]['__channels'][$channel][$key])) {
+ if ($returnchannel) {
+ return array('layer' => $layer, 'channel' => $channel);
+ }
+ return $layer;
+ }
+ }
+
+ if (isset($this->configuration[$layer][$key])) {
+ if ($returnchannel) {
+ return array('layer' => $layer, 'channel' => 'pear.php.net');
+ }
+ return $layer;
+ }
+ }
+
+ return '';
+ }
+
+ /**
+ * Tells whether a given key exists as a config value.
+ *
+ * @param string config key
+ * @return bool whether exists in this object
+ *
+ * @access public
+ */
+ function isDefined($key)
+ {
+ foreach ($this->layers as $layer) {
+ if (isset($this->configuration[$layer][$key])) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Tells whether a given config layer exists.
+ *
+ * @param string config layer
+ * @return bool whether exists in this object
+ *
+ * @access public
+ */
+ function isDefinedLayer($layer)
+ {
+ return isset($this->configuration[$layer]);
+ }
+
+ /**
+ * Returns the layers defined (except the 'default' one)
+ *
+ * @return array of the defined layers
+ */
+ function getLayers()
+ {
+ $cf = $this->configuration;
+ unset($cf['default']);
+ return array_keys($cf);
+ }
+
+ function apiVersion()
+ {
+ return '1.1';
+ }
+
+ /**
+ * @return PEAR_Registry
+ */
+ function &getRegistry($use = null)
+ {
+ $layer = $use === null ? 'user' : $use;
+ if (isset($this->_registry[$layer])) {
+ return $this->_registry[$layer];
+ } elseif ($use === null && isset($this->_registry['system'])) {
+ return $this->_registry['system'];
+ } elseif ($use === null && isset($this->_registry['default'])) {
+ return $this->_registry['default'];
+ } elseif ($use) {
+ $a = false;
+ return $a;
+ }
+
+ // only go here if null was passed in
+ echo "CRITICAL ERROR: Registry could not be initialized from any value";
+ exit(1);
+ }
+
+ /**
+ * This is to allow customization like the use of installroot
+ * @param PEAR_Registry
+ * @return bool
+ */
+ function setRegistry(&$reg, $layer = 'user')
+ {
+ if ($this->_noRegistry) {
+ return false;
+ }
+
+ if (!in_array($layer, array('user', 'system'))) {
+ return false;
+ }
+
+ $this->_registry[$layer] = &$reg;
+ if (is_object($reg)) {
+ $this->_registry[$layer]->setConfig($this, false);
+ }
+
+ return true;
+ }
+
+ function noRegistry()
+ {
+ $this->_noRegistry = true;
+ }
+
+ /**
+ * @return PEAR_REST
+ */
+ function &getREST($version, $options = array())
+ {
+ $version = str_replace('.', '', $version);
+ if (!class_exists($class = 'PEAR_REST_' . $version)) {
+ require_once 'PEAR/REST/' . $version . '.php';
+ }
+
+ $remote = new $class($this, $options);
+ return $remote;
+ }
+
+ /**
+ * The ftp server is set in {@link readFTPConfigFile()}. It exists only if a
+ * remote configuration file has been specified
+ * @return PEAR_FTP|false
+ */
+ function &getFTP()
+ {
+ if (isset($this->_ftp)) {
+ return $this->_ftp;
+ }
+
+ $a = false;
+ return $a;
+ }
+
+ function _prependPath($path, $prepend)
+ {
+ if (strlen($prepend) > 0) {
+ if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) {
+ if (preg_match('/^[a-z]:/i', $prepend)) {
+ $prepend = substr($prepend, 2);
+ } elseif ($prepend{0} != '\\') {
+ $prepend = "\\$prepend";
+ }
+ $path = substr($path, 0, 2) . $prepend . substr($path, 2);
+ } else {
+ $path = $prepend . $path;
+ }
+ }
+ return $path;
+ }
+
+ /**
+ * @param string|false installation directory to prepend to all _dir variables, or false to
+ * disable
+ */
+ function setInstallRoot($root)
+ {
+ if (substr($root, -1) == DIRECTORY_SEPARATOR) {
+ $root = substr($root, 0, -1);
+ }
+ $old = $this->_installRoot;
+ $this->_installRoot = $root;
+ if (($old != $root) && !$this->_noRegistry) {
+ foreach (array_keys($this->_registry) as $layer) {
+ if ($layer == 'ftp' || !isset($this->_registry[$layer])) {
+ continue;
+ }
+ $this->_registry[$layer] =
+ new PEAR_Registry(
+ $this->get('php_dir', $layer, 'pear.php.net'), false, false,
+ $this->get('metadata_dir', $layer, 'pear.php.net'));
+ $this->_registry[$layer]->setConfig($this, false);
+ $this->_regInitialized[$layer] = false;
+ }
+ }
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Dependency2.php b/vendor/pear-pear.php.net/PEAR/PEAR/Dependency2.php
new file mode 100644
index 000000000..77646f1f9
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Dependency2.php
@@ -0,0 +1,1357 @@
+
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+
+/**
+ * Required for the PEAR_VALIDATE_* constants
+ */
+require_once 'PEAR/Validate.php';
+
+/**
+ * Dependency check for PEAR packages
+ *
+ * This class handles both version 1.0 and 2.0 dependencies
+ * WARNING: *any* changes to this class must be duplicated in the
+ * test_PEAR_Dependency2 class found in tests/PEAR_Dependency2/setup.php.inc,
+ * or unit tests will not actually validate the changes
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_Dependency2
+{
+ /**
+ * One of the PEAR_VALIDATE_* states
+ * @see PEAR_VALIDATE_NORMAL
+ * @var integer
+ */
+ var $_state;
+
+ /**
+ * Command-line options to install/upgrade/uninstall commands
+ * @param array
+ */
+ var $_options;
+
+ /**
+ * @var OS_Guess
+ */
+ var $_os;
+
+ /**
+ * @var PEAR_Registry
+ */
+ var $_registry;
+
+ /**
+ * @var PEAR_Config
+ */
+ var $_config;
+
+ /**
+ * @var PEAR_DependencyDB
+ */
+ var $_dependencydb;
+
+ /**
+ * Output of PEAR_Registry::parsedPackageName()
+ * @var array
+ */
+ var $_currentPackage;
+
+ /**
+ * @param PEAR_Config
+ * @param array installation options
+ * @param array format of PEAR_Registry::parsedPackageName()
+ * @param int installation state (one of PEAR_VALIDATE_*)
+ */
+ function __construct(&$config, $installoptions, $package,
+ $state = PEAR_VALIDATE_INSTALLING)
+ {
+ $this->_config = &$config;
+ if (!class_exists('PEAR_DependencyDB')) {
+ require_once 'PEAR/DependencyDB.php';
+ }
+
+ if (isset($installoptions['packagingroot'])) {
+ // make sure depdb is in the right location
+ $config->setInstallRoot($installoptions['packagingroot']);
+ }
+
+ $this->_registry = &$config->getRegistry();
+ $this->_dependencydb = &PEAR_DependencyDB::singleton($config);
+ if (isset($installoptions['packagingroot'])) {
+ $config->setInstallRoot(false);
+ }
+
+ $this->_options = $installoptions;
+ $this->_state = $state;
+ if (!class_exists('OS_Guess')) {
+ require_once 'OS/Guess.php';
+ }
+
+ $this->_os = new OS_Guess;
+ $this->_currentPackage = $package;
+ }
+
+ function _getExtraString($dep)
+ {
+ $extra = ' (';
+ if (isset($dep['uri'])) {
+ return '';
+ }
+
+ if (isset($dep['recommended'])) {
+ $extra .= 'recommended version ' . $dep['recommended'];
+ } else {
+ if (isset($dep['min'])) {
+ $extra .= 'version >= ' . $dep['min'];
+ }
+
+ if (isset($dep['max'])) {
+ if ($extra != ' (') {
+ $extra .= ', ';
+ }
+ $extra .= 'version <= ' . $dep['max'];
+ }
+
+ if (isset($dep['exclude'])) {
+ if (!is_array($dep['exclude'])) {
+ $dep['exclude'] = array($dep['exclude']);
+ }
+
+ if ($extra != ' (') {
+ $extra .= ', ';
+ }
+
+ $extra .= 'excluded versions: ';
+ foreach ($dep['exclude'] as $i => $exclude) {
+ if ($i) {
+ $extra .= ', ';
+ }
+ $extra .= $exclude;
+ }
+ }
+ }
+
+ $extra .= ')';
+ if ($extra == ' ()') {
+ $extra = '';
+ }
+
+ return $extra;
+ }
+
+ /**
+ * This makes unit-testing a heck of a lot easier
+ */
+ function getPHP_OS()
+ {
+ return PHP_OS;
+ }
+
+ /**
+ * This makes unit-testing a heck of a lot easier
+ */
+ function getsysname()
+ {
+ return $this->_os->getSysname();
+ }
+
+ /**
+ * Specify a dependency on an OS. Use arch for detailed os/processor information
+ *
+ * There are two generic OS dependencies that will be the most common, unix and windows.
+ * Other options are linux, freebsd, darwin (OS X), sunos, irix, hpux, aix
+ */
+ function validateOsDependency($dep)
+ {
+ if ($this->_state != PEAR_VALIDATE_INSTALLING && $this->_state != PEAR_VALIDATE_DOWNLOADING) {
+ return true;
+ }
+
+ if ($dep['name'] == '*') {
+ return true;
+ }
+
+ $not = isset($dep['conflicts']) ? true : false;
+ switch (strtolower($dep['name'])) {
+ case 'windows' :
+ if ($not) {
+ if (strtolower(substr($this->getPHP_OS(), 0, 3)) == 'win') {
+ if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+ return $this->raiseError("Cannot install %s on Windows");
+ }
+
+ return $this->warning("warning: Cannot install %s on Windows");
+ }
+ } else {
+ if (strtolower(substr($this->getPHP_OS(), 0, 3)) != 'win') {
+ if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+ return $this->raiseError("Can only install %s on Windows");
+ }
+
+ return $this->warning("warning: Can only install %s on Windows");
+ }
+ }
+ break;
+ case 'unix' :
+ $unices = array('linux', 'freebsd', 'darwin', 'sunos', 'irix', 'hpux', 'aix');
+ if ($not) {
+ if (in_array($this->getSysname(), $unices)) {
+ if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+ return $this->raiseError("Cannot install %s on any Unix system");
+ }
+
+ return $this->warning( "warning: Cannot install %s on any Unix system");
+ }
+ } else {
+ if (!in_array($this->getSysname(), $unices)) {
+ if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+ return $this->raiseError("Can only install %s on a Unix system");
+ }
+
+ return $this->warning("warning: Can only install %s on a Unix system");
+ }
+ }
+ break;
+ default :
+ if ($not) {
+ if (strtolower($dep['name']) == strtolower($this->getSysname())) {
+ if (!isset($this->_options['nodeps']) &&
+ !isset($this->_options['force'])) {
+ return $this->raiseError('Cannot install %s on ' . $dep['name'] .
+ ' operating system');
+ }
+
+ return $this->warning('warning: Cannot install %s on ' .
+ $dep['name'] . ' operating system');
+ }
+ } else {
+ if (strtolower($dep['name']) != strtolower($this->getSysname())) {
+ if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+ return $this->raiseError('Cannot install %s on ' .
+ $this->getSysname() .
+ ' operating system, can only install on ' . $dep['name']);
+ }
+
+ return $this->warning('warning: Cannot install %s on ' .
+ $this->getSysname() .
+ ' operating system, can only install on ' . $dep['name']);
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * This makes unit-testing a heck of a lot easier
+ */
+ function matchSignature($pattern)
+ {
+ return $this->_os->matchSignature($pattern);
+ }
+
+ /**
+ * Specify a complex dependency on an OS/processor/kernel version,
+ * Use OS for simple operating system dependency.
+ *
+ * This is the only dependency that accepts an eregable pattern. The pattern
+ * will be matched against the php_uname() output parsed by OS_Guess
+ */
+ function validateArchDependency($dep)
+ {
+ if ($this->_state != PEAR_VALIDATE_INSTALLING) {
+ return true;
+ }
+
+ $not = isset($dep['conflicts']) ? true : false;
+ if (!$this->matchSignature($dep['pattern'])) {
+ if (!$not) {
+ if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+ return $this->raiseError('%s Architecture dependency failed, does not ' .
+ 'match "' . $dep['pattern'] . '"');
+ }
+
+ return $this->warning('warning: %s Architecture dependency failed, does ' .
+ 'not match "' . $dep['pattern'] . '"');
+ }
+
+ return true;
+ }
+
+ if ($not) {
+ if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+ return $this->raiseError('%s Architecture dependency failed, required "' .
+ $dep['pattern'] . '"');
+ }
+
+ return $this->warning('warning: %s Architecture dependency failed, ' .
+ 'required "' . $dep['pattern'] . '"');
+ }
+
+ return true;
+ }
+
+ /**
+ * This makes unit-testing a heck of a lot easier
+ */
+ function extension_loaded($name)
+ {
+ return extension_loaded($name);
+ }
+
+ /**
+ * This makes unit-testing a heck of a lot easier
+ */
+ function phpversion($name = null)
+ {
+ if ($name !== null) {
+ return phpversion($name);
+ }
+
+ return phpversion();
+ }
+
+ function validateExtensionDependency($dep, $required = true)
+ {
+ if ($this->_state != PEAR_VALIDATE_INSTALLING &&
+ $this->_state != PEAR_VALIDATE_DOWNLOADING) {
+ return true;
+ }
+
+ $loaded = $this->extension_loaded($dep['name']);
+ $extra = $this->_getExtraString($dep);
+ if (isset($dep['exclude'])) {
+ if (!is_array($dep['exclude'])) {
+ $dep['exclude'] = array($dep['exclude']);
+ }
+ }
+
+ if (!isset($dep['min']) && !isset($dep['max']) &&
+ !isset($dep['recommended']) && !isset($dep['exclude'])
+ ) {
+ if ($loaded) {
+ if (isset($dep['conflicts'])) {
+ if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+ return $this->raiseError('%s conflicts with PHP extension "' .
+ $dep['name'] . '"' . $extra);
+ }
+
+ return $this->warning('warning: %s conflicts with PHP extension "' .
+ $dep['name'] . '"' . $extra);
+ }
+
+ return true;
+ }
+
+ if (isset($dep['conflicts'])) {
+ return true;
+ }
+
+ if ($required) {
+ if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+ return $this->raiseError('%s requires PHP extension "' .
+ $dep['name'] . '"' . $extra);
+ }
+
+ return $this->warning('warning: %s requires PHP extension "' .
+ $dep['name'] . '"' . $extra);
+ }
+
+ return $this->warning('%s can optionally use PHP extension "' .
+ $dep['name'] . '"' . $extra);
+ }
+
+ if (!$loaded) {
+ if (isset($dep['conflicts'])) {
+ return true;
+ }
+
+ if (!$required) {
+ return $this->warning('%s can optionally use PHP extension "' .
+ $dep['name'] . '"' . $extra);
+ }
+
+ if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+ return $this->raiseError('%s requires PHP extension "' . $dep['name'] .
+ '"' . $extra);
+ }
+
+ return $this->warning('warning: %s requires PHP extension "' . $dep['name'] .
+ '"' . $extra);
+ }
+
+ $version = (string) $this->phpversion($dep['name']);
+ if (empty($version)) {
+ $version = '0';
+ }
+
+ $fail = false;
+ if (isset($dep['min']) && !version_compare($version, $dep['min'], '>=')) {
+ $fail = true;
+ }
+
+ if (isset($dep['max']) && !version_compare($version, $dep['max'], '<=')) {
+ $fail = true;
+ }
+
+ if ($fail && !isset($dep['conflicts'])) {
+ if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+ return $this->raiseError('%s requires PHP extension "' . $dep['name'] .
+ '"' . $extra . ', installed version is ' . $version);
+ }
+
+ return $this->warning('warning: %s requires PHP extension "' . $dep['name'] .
+ '"' . $extra . ', installed version is ' . $version);
+ } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail && isset($dep['conflicts'])) {
+ if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+ return $this->raiseError('%s conflicts with PHP extension "' .
+ $dep['name'] . '"' . $extra . ', installed version is ' . $version);
+ }
+
+ return $this->warning('warning: %s conflicts with PHP extension "' .
+ $dep['name'] . '"' . $extra . ', installed version is ' . $version);
+ }
+
+ if (isset($dep['exclude'])) {
+ foreach ($dep['exclude'] as $exclude) {
+ if (version_compare($version, $exclude, '==')) {
+ if (isset($dep['conflicts'])) {
+ continue;
+ }
+
+ if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+ return $this->raiseError('%s is not compatible with PHP extension "' .
+ $dep['name'] . '" version ' .
+ $exclude);
+ }
+
+ return $this->warning('warning: %s is not compatible with PHP extension "' .
+ $dep['name'] . '" version ' .
+ $exclude);
+ } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) {
+ if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+ return $this->raiseError('%s conflicts with PHP extension "' .
+ $dep['name'] . '"' . $extra . ', installed version is ' . $version);
+ }
+
+ return $this->warning('warning: %s conflicts with PHP extension "' .
+ $dep['name'] . '"' . $extra . ', installed version is ' . $version);
+ }
+ }
+ }
+
+ if (isset($dep['recommended'])) {
+ if (version_compare($version, $dep['recommended'], '==')) {
+ return true;
+ }
+
+ if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+ return $this->raiseError('%s dependency: PHP extension ' . $dep['name'] .
+ ' version "' . $version . '"' .
+ ' is not the recommended version "' . $dep['recommended'] .
+ '", but may be compatible, use --force to install');
+ }
+
+ return $this->warning('warning: %s dependency: PHP extension ' .
+ $dep['name'] . ' version "' . $version . '"' .
+ ' is not the recommended version "' . $dep['recommended'].'"');
+ }
+
+ return true;
+ }
+
+ function validatePhpDependency($dep)
+ {
+ if ($this->_state != PEAR_VALIDATE_INSTALLING &&
+ $this->_state != PEAR_VALIDATE_DOWNLOADING) {
+ return true;
+ }
+
+ $version = $this->phpversion();
+ $extra = $this->_getExtraString($dep);
+ if (isset($dep['exclude'])) {
+ if (!is_array($dep['exclude'])) {
+ $dep['exclude'] = array($dep['exclude']);
+ }
+ }
+
+ if (isset($dep['min'])) {
+ if (!version_compare($version, $dep['min'], '>=')) {
+ if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+ return $this->raiseError('%s requires PHP' .
+ $extra . ', installed version is ' . $version);
+ }
+
+ return $this->warning('warning: %s requires PHP' .
+ $extra . ', installed version is ' . $version);
+ }
+ }
+
+ if (isset($dep['max'])) {
+ if (!version_compare($version, $dep['max'], '<=')) {
+ if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+ return $this->raiseError('%s requires PHP' .
+ $extra . ', installed version is ' . $version);
+ }
+
+ return $this->warning('warning: %s requires PHP' .
+ $extra . ', installed version is ' . $version);
+ }
+ }
+
+ if (isset($dep['exclude'])) {
+ foreach ($dep['exclude'] as $exclude) {
+ if (version_compare($version, $exclude, '==')) {
+ if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+ return $this->raiseError('%s is not compatible with PHP version ' .
+ $exclude);
+ }
+
+ return $this->warning(
+ 'warning: %s is not compatible with PHP version ' .
+ $exclude);
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * This makes unit-testing a heck of a lot easier
+ */
+ function getPEARVersion()
+ {
+ return '1.10.3';
+ }
+
+ function validatePearinstallerDependency($dep)
+ {
+ $pearversion = $this->getPEARVersion();
+ $extra = $this->_getExtraString($dep);
+ if (isset($dep['exclude'])) {
+ if (!is_array($dep['exclude'])) {
+ $dep['exclude'] = array($dep['exclude']);
+ }
+ }
+
+ if (version_compare($pearversion, $dep['min'], '<')) {
+ if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+ return $this->raiseError('%s requires PEAR Installer' . $extra .
+ ', installed version is ' . $pearversion);
+ }
+
+ return $this->warning('warning: %s requires PEAR Installer' . $extra .
+ ', installed version is ' . $pearversion);
+ }
+
+ if (isset($dep['max'])) {
+ if (version_compare($pearversion, $dep['max'], '>')) {
+ if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+ return $this->raiseError('%s requires PEAR Installer' . $extra .
+ ', installed version is ' . $pearversion);
+ }
+
+ return $this->warning('warning: %s requires PEAR Installer' . $extra .
+ ', installed version is ' . $pearversion);
+ }
+ }
+
+ if (isset($dep['exclude'])) {
+ if (!isset($dep['exclude'][0])) {
+ $dep['exclude'] = array($dep['exclude']);
+ }
+
+ foreach ($dep['exclude'] as $exclude) {
+ if (version_compare($exclude, $pearversion, '==')) {
+ if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+ return $this->raiseError('%s is not compatible with PEAR Installer ' .
+ 'version ' . $exclude);
+ }
+
+ return $this->warning('warning: %s is not compatible with PEAR ' .
+ 'Installer version ' . $exclude);
+ }
+ }
+ }
+
+ return true;
+ }
+
+ function validateSubpackageDependency($dep, $required, $params)
+ {
+ return $this->validatePackageDependency($dep, $required, $params);
+ }
+
+ /**
+ * @param array dependency information (2.0 format)
+ * @param boolean whether this is a required dependency
+ * @param array a list of downloaded packages to be installed, if any
+ * @param boolean if true, then deps on pear.php.net that fail will also check
+ * against pecl.php.net packages to accommodate extensions that have
+ * moved to pecl.php.net from pear.php.net
+ */
+ function validatePackageDependency($dep, $required, $params, $depv1 = false)
+ {
+ if ($this->_state != PEAR_VALIDATE_INSTALLING &&
+ $this->_state != PEAR_VALIDATE_DOWNLOADING) {
+ return true;
+ }
+
+ if (isset($dep['providesextension'])) {
+ if ($this->extension_loaded($dep['providesextension'])) {
+ $save = $dep;
+ $subdep = $dep;
+ $subdep['name'] = $subdep['providesextension'];
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ $ret = $this->validateExtensionDependency($subdep, $required);
+ PEAR::popErrorHandling();
+ if (!PEAR::isError($ret)) {
+ return true;
+ }
+ }
+ }
+
+ if ($this->_state == PEAR_VALIDATE_INSTALLING) {
+ return $this->_validatePackageInstall($dep, $required, $depv1);
+ }
+
+ if ($this->_state == PEAR_VALIDATE_DOWNLOADING) {
+ return $this->_validatePackageDownload($dep, $required, $params, $depv1);
+ }
+ }
+
+ function _validatePackageDownload($dep, $required, $params, $depv1 = false)
+ {
+ $dep['package'] = $dep['name'];
+ if (isset($dep['uri'])) {
+ $dep['channel'] = '__uri';
+ }
+
+ $depname = $this->_registry->parsedPackageNameToString($dep, true);
+ $found = false;
+ foreach ($params as $param) {
+ if ($param->isEqual(
+ array('package' => $dep['name'],
+ 'channel' => $dep['channel']))) {
+ $found = true;
+ break;
+ }
+
+ if ($depv1 && $dep['channel'] == 'pear.php.net') {
+ if ($param->isEqual(
+ array('package' => $dep['name'],
+ 'channel' => 'pecl.php.net'))) {
+ $found = true;
+ break;
+ }
+ }
+ }
+
+ if (!$found && isset($dep['providesextension'])) {
+ foreach ($params as $param) {
+ if ($param->isExtension($dep['providesextension'])) {
+ $found = true;
+ break;
+ }
+ }
+ }
+
+ if ($found) {
+ $version = $param->getVersion();
+ $installed = false;
+ $downloaded = true;
+ } else {
+ if ($this->_registry->packageExists($dep['name'], $dep['channel'])) {
+ $installed = true;
+ $downloaded = false;
+ $version = $this->_registry->packageinfo($dep['name'], 'version',
+ $dep['channel']);
+ } else {
+ if ($dep['channel'] == 'pecl.php.net' && $this->_registry->packageExists($dep['name'],
+ 'pear.php.net')) {
+ $installed = true;
+ $downloaded = false;
+ $version = $this->_registry->packageinfo($dep['name'], 'version',
+ 'pear.php.net');
+ } else {
+ $version = 'not installed or downloaded';
+ $installed = false;
+ $downloaded = false;
+ }
+ }
+ }
+
+ $extra = $this->_getExtraString($dep);
+ if (isset($dep['exclude']) && !is_array($dep['exclude'])) {
+ $dep['exclude'] = array($dep['exclude']);
+ }
+
+ if (!isset($dep['min']) && !isset($dep['max']) &&
+ !isset($dep['recommended']) && !isset($dep['exclude'])
+ ) {
+ if ($installed || $downloaded) {
+ $installed = $installed ? 'installed' : 'downloaded';
+ if (isset($dep['conflicts'])) {
+ $rest = '';
+ if ($version) {
+ $rest = ", $installed version is " . $version;
+ }
+
+ if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+ return $this->raiseError('%s conflicts with package "' . $depname . '"' . $extra . $rest);
+ }
+
+ return $this->warning('warning: %s conflicts with package "' . $depname . '"' . $extra . $rest);
+ }
+
+ return true;
+ }
+
+ if (isset($dep['conflicts'])) {
+ return true;
+ }
+
+ if ($required) {
+ if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+ return $this->raiseError('%s requires package "' . $depname . '"' . $extra);
+ }
+
+ return $this->warning('warning: %s requires package "' . $depname . '"' . $extra);
+ }
+
+ return $this->warning('%s can optionally use package "' . $depname . '"' . $extra);
+ }
+
+ if (!$installed && !$downloaded) {
+ if (isset($dep['conflicts'])) {
+ return true;
+ }
+
+ if ($required) {
+ if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+ return $this->raiseError('%s requires package "' . $depname . '"' . $extra);
+ }
+
+ return $this->warning('warning: %s requires package "' . $depname . '"' . $extra);
+ }
+
+ return $this->warning('%s can optionally use package "' . $depname . '"' . $extra);
+ }
+
+ $fail = false;
+ if (isset($dep['min']) && version_compare($version, $dep['min'], '<')) {
+ $fail = true;
+ }
+
+ if (isset($dep['max']) && version_compare($version, $dep['max'], '>')) {
+ $fail = true;
+ }
+
+ if ($fail && !isset($dep['conflicts'])) {
+ $installed = $installed ? 'installed' : 'downloaded';
+ $dep['package'] = $dep['name'];
+ $dep = $this->_registry->parsedPackageNameToString($dep, true);
+ if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+ return $this->raiseError('%s requires package "' . $depname . '"' .
+ $extra . ", $installed version is " . $version);
+ }
+
+ return $this->warning('warning: %s requires package "' . $depname . '"' .
+ $extra . ", $installed version is " . $version);
+ } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail &&
+ isset($dep['conflicts']) && !isset($dep['exclude'])) {
+ $installed = $installed ? 'installed' : 'downloaded';
+ if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+ return $this->raiseError('%s conflicts with package "' . $depname . '"' . $extra .
+ ", $installed version is " . $version);
+ }
+
+ return $this->warning('warning: %s conflicts with package "' . $depname . '"' .
+ $extra . ", $installed version is " . $version);
+ }
+
+ if (isset($dep['exclude'])) {
+ $installed = $installed ? 'installed' : 'downloaded';
+ foreach ($dep['exclude'] as $exclude) {
+ if (version_compare($version, $exclude, '==') && !isset($dep['conflicts'])) {
+ if (!isset($this->_options['nodeps']) &&
+ !isset($this->_options['force'])
+ ) {
+ return $this->raiseError('%s is not compatible with ' .
+ $installed . ' package "' .
+ $depname . '" version ' .
+ $exclude);
+ }
+
+ return $this->warning('warning: %s is not compatible with ' .
+ $installed . ' package "' .
+ $depname . '" version ' .
+ $exclude);
+ } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) {
+ $installed = $installed ? 'installed' : 'downloaded';
+ if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+ return $this->raiseError('%s conflicts with package "' . $depname . '"' .
+ $extra . ", $installed version is " . $version);
+ }
+
+ return $this->warning('warning: %s conflicts with package "' . $depname . '"' .
+ $extra . ", $installed version is " . $version);
+ }
+ }
+ }
+
+ if (isset($dep['recommended'])) {
+ $installed = $installed ? 'installed' : 'downloaded';
+ if (version_compare($version, $dep['recommended'], '==')) {
+ return true;
+ }
+
+ if (!$found && $installed) {
+ $param = $this->_registry->getPackage($dep['name'], $dep['channel']);
+ }
+
+ if ($param) {
+ $found = false;
+ foreach ($params as $parent) {
+ if ($parent->isEqual($this->_currentPackage)) {
+ $found = true;
+ break;
+ }
+ }
+
+ if ($found) {
+ if ($param->isCompatible($parent)) {
+ return true;
+ }
+ } else { // this is for validPackage() calls
+ $parent = $this->_registry->getPackage($this->_currentPackage['package'],
+ $this->_currentPackage['channel']);
+ if ($parent !== null && $param->isCompatible($parent)) {
+ return true;
+ }
+ }
+ }
+
+ if (!isset($this->_options['nodeps']) && !isset($this->_options['force']) &&
+ !isset($this->_options['loose'])
+ ) {
+ return $this->raiseError('%s dependency package "' . $depname .
+ '" ' . $installed . ' version ' . $version .
+ ' is not the recommended version ' . $dep['recommended'] .
+ ', but may be compatible, use --force to install');
+ }
+
+ return $this->warning('warning: %s dependency package "' . $depname .
+ '" ' . $installed . ' version ' . $version .
+ ' is not the recommended version ' . $dep['recommended']);
+ }
+
+ return true;
+ }
+
+ function _validatePackageInstall($dep, $required, $depv1 = false)
+ {
+ return $this->_validatePackageDownload($dep, $required, array(), $depv1);
+ }
+
+ /**
+ * Verify that uninstalling packages passed in to command line is OK.
+ *
+ * @param PEAR_Installer $dl
+ * @return PEAR_Error|true
+ */
+ function validatePackageUninstall(&$dl)
+ {
+ if (PEAR::isError($this->_dependencydb)) {
+ return $this->_dependencydb;
+ }
+
+ $params = array();
+ // construct an array of "downloaded" packages to fool the package dependency checker
+ // into using these to validate uninstalls of circular dependencies
+ $downloaded = &$dl->getUninstallPackages();
+ foreach ($downloaded as $i => $pf) {
+ if (!class_exists('PEAR_Downloader_Package')) {
+ require_once 'PEAR/Downloader/Package.php';
+ }
+ $dp = new PEAR_Downloader_Package($dl);
+ $dp->setPackageFile($downloaded[$i]);
+ $params[$i] = $dp;
+ }
+
+ // check cache
+ $memyselfandI = strtolower($this->_currentPackage['channel']) . '/' .
+ strtolower($this->_currentPackage['package']);
+ if (isset($dl->___uninstall_package_cache)) {
+ $badpackages = $dl->___uninstall_package_cache;
+ if (isset($badpackages[$memyselfandI]['warnings'])) {
+ foreach ($badpackages[$memyselfandI]['warnings'] as $warning) {
+ $dl->log(0, $warning[0]);
+ }
+ }
+
+ if (isset($badpackages[$memyselfandI]['errors'])) {
+ foreach ($badpackages[$memyselfandI]['errors'] as $error) {
+ if (is_array($error)) {
+ $dl->log(0, $error[0]);
+ } else {
+ $dl->log(0, $error->getMessage());
+ }
+ }
+
+ if (isset($this->_options['nodeps']) || isset($this->_options['force'])) {
+ return $this->warning(
+ 'warning: %s should not be uninstalled, other installed packages depend ' .
+ 'on this package');
+ }
+
+ return $this->raiseError(
+ '%s cannot be uninstalled, other installed packages depend on this package');
+ }
+
+ return true;
+ }
+
+ // first, list the immediate parents of each package to be uninstalled
+ $perpackagelist = array();
+ $allparents = array();
+ foreach ($params as $i => $param) {
+ $a = array(
+ 'channel' => strtolower($param->getChannel()),
+ 'package' => strtolower($param->getPackage())
+ );
+
+ $deps = $this->_dependencydb->getDependentPackages($a);
+ if ($deps) {
+ foreach ($deps as $d) {
+ $pardeps = $this->_dependencydb->getDependencies($d);
+ foreach ($pardeps as $dep) {
+ if (strtolower($dep['dep']['channel']) == $a['channel'] &&
+ strtolower($dep['dep']['name']) == $a['package']) {
+ if (!isset($perpackagelist[$a['channel'] . '/' . $a['package']])) {
+ $perpackagelist[$a['channel'] . '/' . $a['package']] = array();
+ }
+ $perpackagelist[$a['channel'] . '/' . $a['package']][]
+ = array($d['channel'] . '/' . $d['package'], $dep);
+ if (!isset($allparents[$d['channel'] . '/' . $d['package']])) {
+ $allparents[$d['channel'] . '/' . $d['package']] = array();
+ }
+ if (!isset($allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']])) {
+ $allparents[$d['channel'] . '/' . $d['package']][$a['channel'] . '/' . $a['package']] = array();
+ }
+ $allparents[$d['channel'] . '/' . $d['package']]
+ [$a['channel'] . '/' . $a['package']][]
+ = array($d, $dep);
+ }
+ }
+ }
+ }
+ }
+
+ // next, remove any packages from the parents list that are not installed
+ $remove = array();
+ foreach ($allparents as $parent => $d1) {
+ foreach ($d1 as $d) {
+ if ($this->_registry->packageExists($d[0][0]['package'], $d[0][0]['channel'])) {
+ continue;
+ }
+ $remove[$parent] = true;
+ }
+ }
+
+ // next remove any packages from the parents list that are not passed in for
+ // uninstallation
+ foreach ($allparents as $parent => $d1) {
+ foreach ($d1 as $d) {
+ foreach ($params as $param) {
+ if (strtolower($param->getChannel()) == $d[0][0]['channel'] &&
+ strtolower($param->getPackage()) == $d[0][0]['package']) {
+ // found it
+ continue 3;
+ }
+ }
+ $remove[$parent] = true;
+ }
+ }
+
+ // remove all packages whose dependencies fail
+ // save which ones failed for error reporting
+ $badchildren = array();
+ do {
+ $fail = false;
+ foreach ($remove as $package => $unused) {
+ if (!isset($allparents[$package])) {
+ continue;
+ }
+
+ foreach ($allparents[$package] as $kid => $d1) {
+ foreach ($d1 as $depinfo) {
+ if ($depinfo[1]['type'] != 'optional') {
+ if (isset($badchildren[$kid])) {
+ continue;
+ }
+ $badchildren[$kid] = true;
+ $remove[$kid] = true;
+ $fail = true;
+ continue 2;
+ }
+ }
+ }
+ if ($fail) {
+ // start over, we removed some children
+ continue 2;
+ }
+ }
+ } while ($fail);
+
+ // next, construct the list of packages that can't be uninstalled
+ $badpackages = array();
+ $save = $this->_currentPackage;
+ foreach ($perpackagelist as $package => $packagedeps) {
+ foreach ($packagedeps as $parent) {
+ if (!isset($remove[$parent[0]])) {
+ continue;
+ }
+
+ $packagename = $this->_registry->parsePackageName($parent[0]);
+ $packagename['channel'] = $this->_registry->channelAlias($packagename['channel']);
+ $pa = $this->_registry->getPackage($packagename['package'], $packagename['channel']);
+ $packagename['package'] = $pa->getPackage();
+ $this->_currentPackage = $packagename;
+ // parent is not present in uninstall list, make sure we can actually
+ // uninstall it (parent dep is optional)
+ $parentname['channel'] = $this->_registry->channelAlias($parent[1]['dep']['channel']);
+ $pa = $this->_registry->getPackage($parent[1]['dep']['name'], $parent[1]['dep']['channel']);
+ $parentname['package'] = $pa->getPackage();
+ $parent[1]['dep']['package'] = $parentname['package'];
+ $parent[1]['dep']['channel'] = $parentname['channel'];
+ if ($parent[1]['type'] == 'optional') {
+ $test = $this->_validatePackageUninstall($parent[1]['dep'], false, $dl);
+ if ($test !== true) {
+ $badpackages[$package]['warnings'][] = $test;
+ }
+ } else {
+ $test = $this->_validatePackageUninstall($parent[1]['dep'], true, $dl);
+ if ($test !== true) {
+ $badpackages[$package]['errors'][] = $test;
+ }
+ }
+ }
+ }
+
+ $this->_currentPackage = $save;
+ $dl->___uninstall_package_cache = $badpackages;
+ if (isset($badpackages[$memyselfandI])) {
+ if (isset($badpackages[$memyselfandI]['warnings'])) {
+ foreach ($badpackages[$memyselfandI]['warnings'] as $warning) {
+ $dl->log(0, $warning[0]);
+ }
+ }
+
+ if (isset($badpackages[$memyselfandI]['errors'])) {
+ foreach ($badpackages[$memyselfandI]['errors'] as $error) {
+ if (is_array($error)) {
+ $dl->log(0, $error[0]);
+ } else {
+ $dl->log(0, $error->getMessage());
+ }
+ }
+
+ if (isset($this->_options['nodeps']) || isset($this->_options['force'])) {
+ return $this->warning(
+ 'warning: %s should not be uninstalled, other installed packages depend ' .
+ 'on this package');
+ }
+
+ return $this->raiseError(
+ '%s cannot be uninstalled, other installed packages depend on this package');
+ }
+ }
+
+ return true;
+ }
+
+ function _validatePackageUninstall($dep, $required, $dl)
+ {
+ $depname = $this->_registry->parsedPackageNameToString($dep, true);
+ $version = $this->_registry->packageinfo($dep['package'], 'version', $dep['channel']);
+ if (!$version) {
+ return true;
+ }
+
+ $extra = $this->_getExtraString($dep);
+ if (isset($dep['exclude']) && !is_array($dep['exclude'])) {
+ $dep['exclude'] = array($dep['exclude']);
+ }
+
+ if (isset($dep['conflicts'])) {
+ return true; // uninstall OK - these packages conflict (probably installed with --force)
+ }
+
+ if (!isset($dep['min']) && !isset($dep['max'])) {
+ if (!$required) {
+ return $this->warning('"' . $depname . '" can be optionally used by ' .
+ 'installed package %s' . $extra);
+ }
+
+ if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+ return $this->raiseError('"' . $depname . '" is required by ' .
+ 'installed package %s' . $extra);
+ }
+
+ return $this->warning('warning: "' . $depname . '" is required by ' .
+ 'installed package %s' . $extra);
+ }
+
+ $fail = false;
+ if (isset($dep['min']) && version_compare($version, $dep['min'], '>=')) {
+ $fail = true;
+ }
+
+ if (isset($dep['max']) && version_compare($version, $dep['max'], '<=')) {
+ $fail = true;
+ }
+
+ // we re-use this variable, preserve the original value
+ $saverequired = $required;
+ if (!$required) {
+ return $this->warning($depname . $extra . ' can be optionally used by installed package' .
+ ' "%s"');
+ }
+
+ if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
+ return $this->raiseError($depname . $extra . ' is required by installed package' .
+ ' "%s"');
+ }
+
+ return $this->raiseError('warning: ' . $depname . $extra .
+ ' is required by installed package "%s"');
+ }
+
+ /**
+ * validate a downloaded package against installed packages
+ *
+ * As of PEAR 1.4.3, this will only validate
+ *
+ * @param array|PEAR_Downloader_Package|PEAR_PackageFile_v1|PEAR_PackageFile_v2
+ * $pkg package identifier (either
+ * array('package' => blah, 'channel' => blah) or an array with
+ * index 'info' referencing an object)
+ * @param PEAR_Downloader $dl
+ * @param array $params full list of packages to install
+ * @return true|PEAR_Error
+ */
+ function validatePackage($pkg, &$dl, $params = array())
+ {
+ if (is_array($pkg) && isset($pkg['info'])) {
+ $deps = $this->_dependencydb->getDependentPackageDependencies($pkg['info']);
+ } else {
+ $deps = $this->_dependencydb->getDependentPackageDependencies($pkg);
+ }
+
+ $fail = false;
+ if ($deps) {
+ if (!class_exists('PEAR_Downloader_Package')) {
+ require_once 'PEAR/Downloader/Package.php';
+ }
+
+ $dp = new PEAR_Downloader_Package($dl);
+ if (is_object($pkg)) {
+ $dp->setPackageFile($pkg);
+ } else {
+ $dp->setDownloadURL($pkg);
+ }
+
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ foreach ($deps as $channel => $info) {
+ foreach ($info as $package => $ds) {
+ foreach ($params as $packd) {
+ if (strtolower($packd->getPackage()) == strtolower($package) &&
+ $packd->getChannel() == $channel) {
+ $dl->log(3, 'skipping installed package check of "' .
+ $this->_registry->parsedPackageNameToString(
+ array('channel' => $channel, 'package' => $package),
+ true) .
+ '", version "' . $packd->getVersion() . '" will be ' .
+ 'downloaded and installed');
+ continue 2; // jump to next package
+ }
+ }
+
+ foreach ($ds as $d) {
+ $checker = new PEAR_Dependency2($this->_config, $this->_options,
+ array('channel' => $channel, 'package' => $package), $this->_state);
+ $dep = $d['dep'];
+ $required = $d['type'] == 'required';
+ $ret = $checker->_validatePackageDownload($dep, $required, array(&$dp));
+ if (is_array($ret)) {
+ $dl->log(0, $ret[0]);
+ } elseif (PEAR::isError($ret)) {
+ $dl->log(0, $ret->getMessage());
+ $fail = true;
+ }
+ }
+ }
+ }
+ PEAR::popErrorHandling();
+ }
+
+ if ($fail) {
+ return $this->raiseError(
+ '%s cannot be installed, conflicts with installed packages');
+ }
+
+ return true;
+ }
+
+ /**
+ * validate a package.xml 1.0 dependency
+ */
+ function validateDependency1($dep, $params = array())
+ {
+ if (!isset($dep['optional'])) {
+ $dep['optional'] = 'no';
+ }
+
+ list($newdep, $type) = $this->normalizeDep($dep);
+ if (!$newdep) {
+ return $this->raiseError("Invalid Dependency");
+ }
+
+ if (method_exists($this, "validate{$type}Dependency")) {
+ return $this->{"validate{$type}Dependency"}($newdep, $dep['optional'] == 'no',
+ $params, true);
+ }
+ }
+
+ /**
+ * Convert a 1.0 dep into a 2.0 dep
+ */
+ function normalizeDep($dep)
+ {
+ $types = array(
+ 'pkg' => 'Package',
+ 'ext' => 'Extension',
+ 'os' => 'Os',
+ 'php' => 'Php'
+ );
+
+ if (!isset($types[$dep['type']])) {
+ return array(false, false);
+ }
+
+ $type = $types[$dep['type']];
+
+ $newdep = array();
+ switch ($type) {
+ case 'Package' :
+ $newdep['channel'] = 'pear.php.net';
+ case 'Extension' :
+ case 'Os' :
+ $newdep['name'] = $dep['name'];
+ break;
+ }
+
+ $dep['rel'] = PEAR_Dependency2::signOperator($dep['rel']);
+ switch ($dep['rel']) {
+ case 'has' :
+ return array($newdep, $type);
+ break;
+ case 'not' :
+ $newdep['conflicts'] = true;
+ break;
+ case '>=' :
+ case '>' :
+ $newdep['min'] = $dep['version'];
+ if ($dep['rel'] == '>') {
+ $newdep['exclude'] = $dep['version'];
+ }
+ break;
+ case '<=' :
+ case '<' :
+ $newdep['max'] = $dep['version'];
+ if ($dep['rel'] == '<') {
+ $newdep['exclude'] = $dep['version'];
+ }
+ break;
+ case 'ne' :
+ case '!=' :
+ $newdep['min'] = '0';
+ $newdep['max'] = '100000';
+ $newdep['exclude'] = $dep['version'];
+ break;
+ case '==' :
+ $newdep['min'] = $dep['version'];
+ $newdep['max'] = $dep['version'];
+ break;
+ }
+ if ($type == 'Php') {
+ if (!isset($newdep['min'])) {
+ $newdep['min'] = '4.4.0';
+ }
+
+ if (!isset($newdep['max'])) {
+ $newdep['max'] = '6.0.0';
+ }
+ }
+ return array($newdep, $type);
+ }
+
+ /**
+ * Converts text comparing operators to them sign equivalents
+ *
+ * Example: 'ge' to '>='
+ *
+ * @access public
+ * @param string Operator
+ * @return string Sign equivalent
+ */
+ function signOperator($operator)
+ {
+ switch($operator) {
+ case 'lt': return '<';
+ case 'le': return '<=';
+ case 'gt': return '>';
+ case 'ge': return '>=';
+ case 'eq': return '==';
+ case 'ne': return '!=';
+ default:
+ return $operator;
+ }
+ }
+
+ function raiseError($msg)
+ {
+ if (isset($this->_options['ignore-errors'])) {
+ return $this->warning($msg);
+ }
+
+ return PEAR::raiseError(sprintf($msg, $this->_registry->parsedPackageNameToString(
+ $this->_currentPackage, true)));
+ }
+
+ function warning($msg)
+ {
+ return array(sprintf($msg, $this->_registry->parsedPackageNameToString(
+ $this->_currentPackage, true)));
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/DependencyDB.php b/vendor/pear-pear.php.net/PEAR/PEAR/DependencyDB.php
new file mode 100644
index 000000000..5421929a2
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/DependencyDB.php
@@ -0,0 +1,764 @@
+
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+
+/**
+ * Needed for error handling
+ */
+require_once 'PEAR.php';
+require_once 'PEAR/Config.php';
+
+$GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'] = array();
+/**
+ * Track dependency relationships between installed packages
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @author Tomas V.V.Cox
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_DependencyDB
+{
+ // {{{ properties
+
+ /**
+ * This is initialized by {@link setConfig()}
+ * @var PEAR_Config
+ * @access private
+ */
+ var $_config;
+ /**
+ * This is initialized by {@link setConfig()}
+ * @var PEAR_Registry
+ * @access private
+ */
+ var $_registry;
+ /**
+ * Filename of the dependency DB (usually .depdb)
+ * @var string
+ * @access private
+ */
+ var $_depdb = false;
+ /**
+ * File name of the lockfile (usually .depdblock)
+ * @var string
+ * @access private
+ */
+ var $_lockfile = false;
+ /**
+ * Open file resource for locking the lockfile
+ * @var resource|false
+ * @access private
+ */
+ var $_lockFp = false;
+ /**
+ * API version of this class, used to validate a file on-disk
+ * @var string
+ * @access private
+ */
+ var $_version = '1.0';
+ /**
+ * Cached dependency database file
+ * @var array|null
+ * @access private
+ */
+ var $_cache;
+
+ // }}}
+ // {{{ & singleton()
+
+ /**
+ * Get a raw dependency database. Calls setConfig() and assertDepsDB()
+ * @param PEAR_Config
+ * @param string|false full path to the dependency database, or false to use default
+ * @return PEAR_DependencyDB|PEAR_Error
+ */
+ public static function &singleton(&$config, $depdb = false)
+ {
+ $phpdir = $config->get('php_dir', null, 'pear.php.net');
+ if (!isset($GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir])) {
+ $a = new PEAR_DependencyDB;
+ $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir] = &$a;
+ $a->setConfig($config, $depdb);
+ $e = $a->assertDepsDB();
+ if (PEAR::isError($e)) {
+ return $e;
+ }
+ }
+
+ return $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'][$phpdir];
+ }
+
+ /**
+ * Set up the registry/location of dependency DB
+ * @param PEAR_Config|false
+ * @param string|false full path to the dependency database, or false to use default
+ */
+ function setConfig(&$config, $depdb = false)
+ {
+ if (!$config) {
+ $this->_config = &PEAR_Config::singleton();
+ } else {
+ $this->_config = &$config;
+ }
+
+ $this->_registry = &$this->_config->getRegistry();
+ if (!$depdb) {
+ $dir = $this->_config->get('metadata_dir', null, 'pear.php.net');
+ if (!$dir) {
+ $dir = $this->_config->get('php_dir', null, 'pear.php.net');
+ }
+ $this->_depdb = $dir . DIRECTORY_SEPARATOR . '.depdb';
+ } else {
+ $this->_depdb = $depdb;
+ }
+
+ $this->_lockfile = dirname($this->_depdb) . DIRECTORY_SEPARATOR . '.depdblock';
+ }
+ // }}}
+
+ function hasWriteAccess()
+ {
+ if (!file_exists($this->_depdb)) {
+ $dir = $this->_depdb;
+ while ($dir && $dir != '.') {
+ $dir = dirname($dir); // cd ..
+ if ($dir != '.' && file_exists($dir)) {
+ if (is_writeable($dir)) {
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ return false;
+ }
+
+ return is_writeable($this->_depdb);
+ }
+
+ // {{{ assertDepsDB()
+
+ /**
+ * Create the dependency database, if it doesn't exist. Error if the database is
+ * newer than the code reading it.
+ * @return void|PEAR_Error
+ */
+ function assertDepsDB()
+ {
+ if (!is_file($this->_depdb)) {
+ $this->rebuildDB();
+ return;
+ }
+
+ $depdb = $this->_getDepDB();
+ // Datatype format has been changed, rebuild the Deps DB
+ if ($depdb['_version'] < $this->_version) {
+ $this->rebuildDB();
+ }
+
+ if ($depdb['_version']{0} > $this->_version{0}) {
+ return PEAR::raiseError('Dependency database is version ' .
+ $depdb['_version'] . ', and we are version ' .
+ $this->_version . ', cannot continue');
+ }
+ }
+
+ /**
+ * Get a list of installed packages that depend on this package
+ * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array
+ * @return array|false
+ */
+ function getDependentPackages(&$pkg)
+ {
+ $data = $this->_getDepDB();
+ if (is_object($pkg)) {
+ $channel = strtolower($pkg->getChannel());
+ $package = strtolower($pkg->getPackage());
+ } else {
+ $channel = strtolower($pkg['channel']);
+ $package = strtolower($pkg['package']);
+ }
+
+ if (isset($data['packages'][$channel][$package])) {
+ return $data['packages'][$channel][$package];
+ }
+
+ return false;
+ }
+
+ /**
+ * Get a list of the actual dependencies of installed packages that depend on
+ * a package.
+ * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array
+ * @return array|false
+ */
+ function getDependentPackageDependencies(&$pkg)
+ {
+ $data = $this->_getDepDB();
+ if (is_object($pkg)) {
+ $channel = strtolower($pkg->getChannel());
+ $package = strtolower($pkg->getPackage());
+ } else {
+ $channel = strtolower($pkg['channel']);
+ $package = strtolower($pkg['package']);
+ }
+
+ $depend = $this->getDependentPackages($pkg);
+ if (!$depend) {
+ return false;
+ }
+
+ $dependencies = array();
+ foreach ($depend as $info) {
+ $temp = $this->getDependencies($info);
+ foreach ($temp as $dep) {
+ if (
+ isset($dep['dep'], $dep['dep']['channel'], $dep['dep']['name']) &&
+ strtolower($dep['dep']['channel']) == $channel &&
+ strtolower($dep['dep']['name']) == $package
+ ) {
+ if (!isset($dependencies[$info['channel']])) {
+ $dependencies[$info['channel']] = array();
+ }
+
+ if (!isset($dependencies[$info['channel']][$info['package']])) {
+ $dependencies[$info['channel']][$info['package']] = array();
+ }
+ $dependencies[$info['channel']][$info['package']][] = $dep;
+ }
+ }
+ }
+
+ return $dependencies;
+ }
+
+ /**
+ * Get a list of dependencies of this installed package
+ * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array
+ * @return array|false
+ */
+ function getDependencies(&$pkg)
+ {
+ if (is_object($pkg)) {
+ $channel = strtolower($pkg->getChannel());
+ $package = strtolower($pkg->getPackage());
+ } else {
+ $channel = strtolower($pkg['channel']);
+ $package = strtolower($pkg['package']);
+ }
+
+ $data = $this->_getDepDB();
+ if (isset($data['dependencies'][$channel][$package])) {
+ return $data['dependencies'][$channel][$package];
+ }
+
+ return false;
+ }
+
+ /**
+ * Determine whether $parent depends on $child, near or deep
+ * @param array|PEAR_PackageFile_v2|PEAR_PackageFile_v2
+ * @param array|PEAR_PackageFile_v2|PEAR_PackageFile_v2
+ */
+ function dependsOn($parent, $child)
+ {
+ $c = array();
+ $this->_getDepDB();
+ return $this->_dependsOn($parent, $child, $c);
+ }
+
+ function _dependsOn($parent, $child, &$checked)
+ {
+ if (is_object($parent)) {
+ $channel = strtolower($parent->getChannel());
+ $package = strtolower($parent->getPackage());
+ } else {
+ $channel = strtolower($parent['channel']);
+ $package = strtolower($parent['package']);
+ }
+
+ if (is_object($child)) {
+ $depchannel = strtolower($child->getChannel());
+ $deppackage = strtolower($child->getPackage());
+ } else {
+ $depchannel = strtolower($child['channel']);
+ $deppackage = strtolower($child['package']);
+ }
+
+ if (isset($checked[$channel][$package][$depchannel][$deppackage])) {
+ return false; // avoid endless recursion
+ }
+
+ $checked[$channel][$package][$depchannel][$deppackage] = true;
+ if (!isset($this->_cache['dependencies'][$channel][$package])) {
+ return false;
+ }
+
+ foreach ($this->_cache['dependencies'][$channel][$package] as $info) {
+ if (isset($info['dep']['uri'])) {
+ if (is_object($child)) {
+ if ($info['dep']['uri'] == $child->getURI()) {
+ return true;
+ }
+ } elseif (isset($child['uri'])) {
+ if ($info['dep']['uri'] == $child['uri']) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ if (strtolower($info['dep']['channel']) == $depchannel &&
+ strtolower($info['dep']['name']) == $deppackage) {
+ return true;
+ }
+ }
+
+ foreach ($this->_cache['dependencies'][$channel][$package] as $info) {
+ if (isset($info['dep']['uri'])) {
+ if ($this->_dependsOn(array(
+ 'uri' => $info['dep']['uri'],
+ 'package' => $info['dep']['name']), $child, $checked)) {
+ return true;
+ }
+ } else {
+ if ($this->_dependsOn(array(
+ 'channel' => $info['dep']['channel'],
+ 'package' => $info['dep']['name']), $child, $checked)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Register dependencies of a package that is being installed or upgraded
+ * @param PEAR_PackageFile_v2|PEAR_PackageFile_v2
+ */
+ function installPackage(&$package)
+ {
+ $data = $this->_getDepDB();
+ unset($this->_cache);
+ $this->_setPackageDeps($data, $package);
+ $this->_writeDepDB($data);
+ }
+
+ /**
+ * Remove dependencies of a package that is being uninstalled, or upgraded.
+ *
+ * Upgraded packages first uninstall, then install
+ * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array If an array, then it must have
+ * indices 'channel' and 'package'
+ */
+ function uninstallPackage(&$pkg)
+ {
+ $data = $this->_getDepDB();
+ unset($this->_cache);
+ if (is_object($pkg)) {
+ $channel = strtolower($pkg->getChannel());
+ $package = strtolower($pkg->getPackage());
+ } else {
+ $channel = strtolower($pkg['channel']);
+ $package = strtolower($pkg['package']);
+ }
+
+ if (!isset($data['dependencies'][$channel][$package])) {
+ return true;
+ }
+
+ foreach ($data['dependencies'][$channel][$package] as $dep) {
+ $found = false;
+ $depchannel = isset($dep['dep']['uri']) ? '__uri' : strtolower($dep['dep']['channel']);
+ $depname = strtolower($dep['dep']['name']);
+ if (isset($data['packages'][$depchannel][$depname])) {
+ foreach ($data['packages'][$depchannel][$depname] as $i => $info) {
+ if ($info['channel'] == $channel && $info['package'] == $package) {
+ $found = true;
+ break;
+ }
+ }
+ }
+
+ if ($found) {
+ unset($data['packages'][$depchannel][$depname][$i]);
+ if (!count($data['packages'][$depchannel][$depname])) {
+ unset($data['packages'][$depchannel][$depname]);
+ if (!count($data['packages'][$depchannel])) {
+ unset($data['packages'][$depchannel]);
+ }
+ } else {
+ $data['packages'][$depchannel][$depname] =
+ array_values($data['packages'][$depchannel][$depname]);
+ }
+ }
+ }
+
+ unset($data['dependencies'][$channel][$package]);
+ if (!count($data['dependencies'][$channel])) {
+ unset($data['dependencies'][$channel]);
+ }
+
+ if (!count($data['dependencies'])) {
+ unset($data['dependencies']);
+ }
+
+ if (!count($data['packages'])) {
+ unset($data['packages']);
+ }
+
+ $this->_writeDepDB($data);
+ }
+
+ /**
+ * Rebuild the dependency DB by reading registry entries.
+ * @return true|PEAR_Error
+ */
+ function rebuildDB()
+ {
+ $depdb = array('_version' => $this->_version);
+ if (!$this->hasWriteAccess()) {
+ // allow startup for read-only with older Registry
+ return $depdb;
+ }
+
+ $packages = $this->_registry->listAllPackages();
+ if (PEAR::isError($packages)) {
+ return $packages;
+ }
+
+ foreach ($packages as $channel => $ps) {
+ foreach ($ps as $package) {
+ $package = $this->_registry->getPackage($package, $channel);
+ if (PEAR::isError($package)) {
+ return $package;
+ }
+ $this->_setPackageDeps($depdb, $package);
+ }
+ }
+
+ $error = $this->_writeDepDB($depdb);
+ if (PEAR::isError($error)) {
+ return $error;
+ }
+
+ $this->_cache = $depdb;
+ return true;
+ }
+
+ /**
+ * Register usage of the dependency DB to prevent race conditions
+ * @param int one of the LOCK_* constants
+ * @return true|PEAR_Error
+ * @access private
+ */
+ function _lock($mode = LOCK_EX)
+ {
+ if (stristr(php_uname(), 'Windows 9')) {
+ return true;
+ }
+
+ if ($mode != LOCK_UN && is_resource($this->_lockFp)) {
+ // XXX does not check type of lock (LOCK_SH/LOCK_EX)
+ return true;
+ }
+
+ $open_mode = 'w';
+ // XXX People reported problems with LOCK_SH and 'w'
+ if ($mode === LOCK_SH) {
+ if (!file_exists($this->_lockfile)) {
+ touch($this->_lockfile);
+ } elseif (!is_file($this->_lockfile)) {
+ return PEAR::raiseError('could not create Dependency lock file, ' .
+ 'it exists and is not a regular file');
+ }
+ $open_mode = 'r';
+ }
+
+ if (!is_resource($this->_lockFp)) {
+ $this->_lockFp = @fopen($this->_lockfile, $open_mode);
+ }
+
+ if (!is_resource($this->_lockFp)) {
+ return PEAR::raiseError("could not create Dependency lock file" .
+ (isset($php_errormsg) ? ": " . $php_errormsg : ""));
+ }
+
+ if (!(int)flock($this->_lockFp, $mode)) {
+ switch ($mode) {
+ case LOCK_SH: $str = 'shared'; break;
+ case LOCK_EX: $str = 'exclusive'; break;
+ case LOCK_UN: $str = 'unlock'; break;
+ default: $str = 'unknown'; break;
+ }
+
+ return PEAR::raiseError("could not acquire $str lock ($this->_lockfile)");
+ }
+
+ return true;
+ }
+
+ /**
+ * Release usage of dependency DB
+ * @return true|PEAR_Error
+ * @access private
+ */
+ function _unlock()
+ {
+ $ret = $this->_lock(LOCK_UN);
+ if (is_resource($this->_lockFp)) {
+ fclose($this->_lockFp);
+ }
+ $this->_lockFp = null;
+ return $ret;
+ }
+
+ /**
+ * Load the dependency database from disk, or return the cache
+ * @return array|PEAR_Error
+ */
+ function _getDepDB()
+ {
+ if (!$this->hasWriteAccess()) {
+ return array('_version' => $this->_version);
+ }
+
+ if (isset($this->_cache)) {
+ return $this->_cache;
+ }
+
+ if (!$fp = fopen($this->_depdb, 'r')) {
+ $err = PEAR::raiseError("Could not open dependencies file `".$this->_depdb."'");
+ return $err;
+ }
+
+ clearstatcache();
+ fclose($fp);
+ $data = unserialize(file_get_contents($this->_depdb));
+ $this->_cache = $data;
+ return $data;
+ }
+
+ /**
+ * Write out the dependency database to disk
+ * @param array the database
+ * @return true|PEAR_Error
+ * @access private
+ */
+ function _writeDepDB(&$deps)
+ {
+ if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
+ return $e;
+ }
+
+ if (!$fp = fopen($this->_depdb, 'wb')) {
+ $this->_unlock();
+ return PEAR::raiseError("Could not open dependencies file `".$this->_depdb."' for writing");
+ }
+
+ fwrite($fp, serialize($deps));
+ fclose($fp);
+ $this->_unlock();
+ $this->_cache = $deps;
+ return true;
+ }
+
+ /**
+ * Register all dependencies from a package in the dependencies database, in essence
+ * "installing" the package's dependency information
+ * @param array the database
+ * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+ * @access private
+ */
+ function _setPackageDeps(&$data, &$pkg)
+ {
+ $pkg->setConfig($this->_config);
+ if ($pkg->getPackagexmlVersion() == '1.0') {
+ $gen = &$pkg->getDefaultGenerator();
+ $deps = $gen->dependenciesToV2();
+ } else {
+ $deps = $pkg->getDeps(true);
+ }
+
+ if (!$deps) {
+ return;
+ }
+
+ if (!is_array($data)) {
+ $data = array();
+ }
+
+ if (!isset($data['dependencies'])) {
+ $data['dependencies'] = array();
+ }
+
+ $channel = strtolower($pkg->getChannel());
+ $package = strtolower($pkg->getPackage());
+
+ if (!isset($data['dependencies'][$channel])) {
+ $data['dependencies'][$channel] = array();
+ }
+
+ $data['dependencies'][$channel][$package] = array();
+ if (isset($deps['required']['package'])) {
+ if (!isset($deps['required']['package'][0])) {
+ $deps['required']['package'] = array($deps['required']['package']);
+ }
+
+ foreach ($deps['required']['package'] as $dep) {
+ $this->_registerDep($data, $pkg, $dep, 'required');
+ }
+ }
+
+ if (isset($deps['optional']['package'])) {
+ if (!isset($deps['optional']['package'][0])) {
+ $deps['optional']['package'] = array($deps['optional']['package']);
+ }
+
+ foreach ($deps['optional']['package'] as $dep) {
+ $this->_registerDep($data, $pkg, $dep, 'optional');
+ }
+ }
+
+ if (isset($deps['required']['subpackage'])) {
+ if (!isset($deps['required']['subpackage'][0])) {
+ $deps['required']['subpackage'] = array($deps['required']['subpackage']);
+ }
+
+ foreach ($deps['required']['subpackage'] as $dep) {
+ $this->_registerDep($data, $pkg, $dep, 'required');
+ }
+ }
+
+ if (isset($deps['optional']['subpackage'])) {
+ if (!isset($deps['optional']['subpackage'][0])) {
+ $deps['optional']['subpackage'] = array($deps['optional']['subpackage']);
+ }
+
+ foreach ($deps['optional']['subpackage'] as $dep) {
+ $this->_registerDep($data, $pkg, $dep, 'optional');
+ }
+ }
+
+ if (isset($deps['group'])) {
+ if (!isset($deps['group'][0])) {
+ $deps['group'] = array($deps['group']);
+ }
+
+ foreach ($deps['group'] as $group) {
+ if (isset($group['package'])) {
+ if (!isset($group['package'][0])) {
+ $group['package'] = array($group['package']);
+ }
+
+ foreach ($group['package'] as $dep) {
+ $this->_registerDep($data, $pkg, $dep, 'optional',
+ $group['attribs']['name']);
+ }
+ }
+
+ if (isset($group['subpackage'])) {
+ if (!isset($group['subpackage'][0])) {
+ $group['subpackage'] = array($group['subpackage']);
+ }
+
+ foreach ($group['subpackage'] as $dep) {
+ $this->_registerDep($data, $pkg, $dep, 'optional',
+ $group['attribs']['name']);
+ }
+ }
+ }
+ }
+
+ if ($data['dependencies'][$channel][$package] == array()) {
+ unset($data['dependencies'][$channel][$package]);
+ if (!count($data['dependencies'][$channel])) {
+ unset($data['dependencies'][$channel]);
+ }
+ }
+ }
+
+ /**
+ * @param array the database
+ * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+ * @param array the specific dependency
+ * @param required|optional whether this is a required or an optional dep
+ * @param string|false dependency group this dependency is from, or false for ordinary dep
+ */
+ function _registerDep(&$data, &$pkg, $dep, $type, $group = false)
+ {
+ $info = array(
+ 'dep' => $dep,
+ 'type' => $type,
+ 'group' => $group
+ );
+
+ $dep = array_map('strtolower', $dep);
+ $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri';
+ if (!isset($data['dependencies'])) {
+ $data['dependencies'] = array();
+ }
+
+ $channel = strtolower($pkg->getChannel());
+ $package = strtolower($pkg->getPackage());
+
+ if (!isset($data['dependencies'][$channel])) {
+ $data['dependencies'][$channel] = array();
+ }
+
+ if (!isset($data['dependencies'][$channel][$package])) {
+ $data['dependencies'][$channel][$package] = array();
+ }
+
+ $data['dependencies'][$channel][$package][] = $info;
+ if (isset($data['packages'][$depchannel][$dep['name']])) {
+ $found = false;
+ foreach ($data['packages'][$depchannel][$dep['name']] as $i => $p) {
+ if ($p['channel'] == $channel && $p['package'] == $package) {
+ $found = true;
+ break;
+ }
+ }
+ } else {
+ if (!isset($data['packages'])) {
+ $data['packages'] = array();
+ }
+
+ if (!isset($data['packages'][$depchannel])) {
+ $data['packages'][$depchannel] = array();
+ }
+
+ if (!isset($data['packages'][$depchannel][$dep['name']])) {
+ $data['packages'][$depchannel][$dep['name']] = array();
+ }
+
+ $found = false;
+ }
+
+ if (!$found) {
+ $data['packages'][$depchannel][$dep['name']][] = array(
+ 'channel' => $channel,
+ 'package' => $package
+ );
+ }
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Downloader.php b/vendor/pear-pear.php.net/PEAR/PEAR/Downloader.php
new file mode 100644
index 000000000..15f26bcef
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Downloader.php
@@ -0,0 +1,1763 @@
+
+ * @author Stig Bakken
+ * @author Tomas V. V. Cox
+ * @author Martin Jansen
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.3.0
+ */
+
+/**
+ * Needed for constants, extending
+ */
+require_once 'PEAR/Common.php';
+require_once 'PEAR/Proxy.php';
+
+define('PEAR_INSTALLER_OK', 1);
+define('PEAR_INSTALLER_FAILED', 0);
+define('PEAR_INSTALLER_SKIPPED', -1);
+define('PEAR_INSTALLER_ERROR_NO_PREF_STATE', 2);
+
+/**
+ * Administration class used to download anything from the internet (PEAR Packages,
+ * static URLs, xml files)
+ *
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @author Stig Bakken
+ * @author Tomas V. V. Cox
+ * @author Martin Jansen
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.3.0
+ */
+class PEAR_Downloader extends PEAR_Common
+{
+ /**
+ * @var PEAR_Registry
+ * @access private
+ */
+ var $_registry;
+
+ /**
+ * Preferred Installation State (snapshot, devel, alpha, beta, stable)
+ * @var string|null
+ * @access private
+ */
+ var $_preferredState;
+
+ /**
+ * Options from command-line passed to Install.
+ *
+ * Recognized options:
+ * - onlyreqdeps : install all required dependencies as well
+ * - alldeps : install all dependencies, including optional
+ * - installroot : base relative path to install files in
+ * - force : force a download even if warnings would prevent it
+ * - nocompress : download uncompressed tarballs
+ * @see PEAR_Command_Install
+ * @access private
+ * @var array
+ */
+ var $_options;
+
+ /**
+ * Downloaded Packages after a call to download().
+ *
+ * Format of each entry:
+ *
+ *
+ * array('pkg' => 'package_name', 'file' => '/path/to/local/file',
+ * 'info' => array() // parsed package.xml
+ * );
+ *
+ * @access private
+ * @var array
+ */
+ var $_downloadedPackages = array();
+
+ /**
+ * Packages slated for download.
+ *
+ * This is used to prevent downloading a package more than once should it be a dependency
+ * for two packages to be installed.
+ * Format of each entry:
+ *
+ *
+ * array('package_name1' => parsed package.xml, 'package_name2' => parsed package.xml,
+ * );
+ *
+ * @access private
+ * @var array
+ */
+ var $_toDownload = array();
+
+ /**
+ * Array of every package installed, with names lower-cased.
+ *
+ * Format:
+ *
+ * array('package1' => 0, 'package2' => 1, );
+ *
+ * @var array
+ */
+ var $_installed = array();
+
+ /**
+ * @var array
+ * @access private
+ */
+ var $_errorStack = array();
+
+ /**
+ * @var boolean
+ * @access private
+ */
+ var $_internalDownload = false;
+
+ /**
+ * Temporary variable used in sorting packages by dependency in {@link sortPkgDeps()}
+ * @var array
+ * @access private
+ */
+ var $_packageSortTree;
+
+ /**
+ * Temporary directory, or configuration value where downloads will occur
+ * @var string
+ */
+ var $_downloadDir;
+
+ /**
+ * List of methods that can be called both statically and non-statically.
+ * @var array
+ */
+ protected static $bivalentMethods = array(
+ 'setErrorHandling' => true,
+ 'raiseError' => true,
+ 'throwError' => true,
+ 'pushErrorHandling' => true,
+ 'popErrorHandling' => true,
+ 'downloadHttp' => true,
+ );
+
+ /**
+ * @param PEAR_Frontend_*
+ * @param array
+ * @param PEAR_Config
+ */
+ function __construct($ui = null, $options = array(), $config = null)
+ {
+ parent::__construct();
+ $this->_options = $options;
+ if ($config !== null) {
+ $this->config = &$config;
+ $this->_preferredState = $this->config->get('preferred_state');
+ }
+ $this->ui = &$ui;
+ if (!$this->_preferredState) {
+ // don't inadvertently use a non-set preferred_state
+ $this->_preferredState = null;
+ }
+
+ if ($config !== null) {
+ if (isset($this->_options['installroot'])) {
+ $this->config->setInstallRoot($this->_options['installroot']);
+ }
+ $this->_registry = &$config->getRegistry();
+ }
+
+ if (isset($this->_options['alldeps']) || isset($this->_options['onlyreqdeps'])) {
+ $this->_installed = $this->_registry->listAllPackages();
+ foreach ($this->_installed as $key => $unused) {
+ if (!count($unused)) {
+ continue;
+ }
+ $strtolower = create_function('$a','return strtolower($a);');
+ array_walk($this->_installed[$key], $strtolower);
+ }
+ }
+ }
+
+ /**
+ * Attempt to discover a channel's remote capabilities from
+ * its server name
+ * @param string
+ * @return boolean
+ */
+ function discover($channel)
+ {
+ $this->log(1, 'Attempting to discover channel "' . $channel . '"...');
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ $callback = $this->ui ? array(&$this, '_downloadCallback') : null;
+ if (!class_exists('System')) {
+ require_once 'System.php';
+ }
+
+ $tmpdir = $this->config->get('temp_dir');
+ $tmp = System::mktemp('-d -t "' . $tmpdir . '"');
+ $a = $this->downloadHttp('http://' . $channel . '/channel.xml', $this->ui, $tmp, $callback, false);
+ PEAR::popErrorHandling();
+ if (PEAR::isError($a)) {
+ // Attempt to fallback to https automatically.
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ $this->log(1, 'Attempting fallback to https instead of http on channel "' . $channel . '"...');
+ $a = $this->downloadHttp('https://' . $channel . '/channel.xml', $this->ui, $tmp, $callback, false);
+ PEAR::popErrorHandling();
+ if (PEAR::isError($a)) {
+ return false;
+ }
+ }
+
+ list($a, $lastmodified) = $a;
+ if (!class_exists('PEAR_ChannelFile')) {
+ require_once 'PEAR/ChannelFile.php';
+ }
+
+ $b = new PEAR_ChannelFile;
+ if ($b->fromXmlFile($a)) {
+ unlink($a);
+ if ($this->config->get('auto_discover')) {
+ $this->_registry->addChannel($b, $lastmodified);
+ $alias = $b->getName();
+ if ($b->getName() == $this->_registry->channelName($b->getAlias())) {
+ $alias = $b->getAlias();
+ }
+
+ $this->log(1, 'Auto-discovered channel "' . $channel .
+ '", alias "' . $alias . '", adding to registry');
+ }
+
+ return true;
+ }
+
+ unlink($a);
+ return false;
+ }
+
+ /**
+ * For simpler unit-testing
+ * @param PEAR_Downloader
+ * @return PEAR_Downloader_Package
+ */
+ function newDownloaderPackage(&$t)
+ {
+ if (!class_exists('PEAR_Downloader_Package')) {
+ require_once 'PEAR/Downloader/Package.php';
+ }
+ $a = new PEAR_Downloader_Package($t);
+ return $a;
+ }
+
+ /**
+ * For simpler unit-testing
+ * @param PEAR_Config
+ * @param array
+ * @param array
+ * @param int
+ */
+ function &getDependency2Object(&$c, $i, $p, $s)
+ {
+ if (!class_exists('PEAR_Dependency2')) {
+ require_once 'PEAR/Dependency2.php';
+ }
+ $z = new PEAR_Dependency2($c, $i, $p, $s);
+ return $z;
+ }
+
+ function &download($params)
+ {
+ if (!count($params)) {
+ $a = array();
+ return $a;
+ }
+
+ if (!isset($this->_registry)) {
+ $this->_registry = &$this->config->getRegistry();
+ }
+
+ $channelschecked = array();
+ // convert all parameters into PEAR_Downloader_Package objects
+ foreach ($params as $i => $param) {
+ $params[$i] = $this->newDownloaderPackage($this);
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $err = $params[$i]->initialize($param);
+ PEAR::staticPopErrorHandling();
+ if (!$err) {
+ // skip parameters that were missed by preferred_state
+ continue;
+ }
+
+ if (PEAR::isError($err)) {
+ if (!isset($this->_options['soft']) && $err->getMessage() !== '') {
+ $this->log(0, $err->getMessage());
+ }
+
+ $params[$i] = false;
+ if (is_object($param)) {
+ $param = $param->getChannel() . '/' . $param->getPackage();
+ }
+
+ if (!isset($this->_options['soft'])) {
+ $this->log(2, 'Package "' . $param . '" is not valid');
+ }
+
+ // Message logged above in a specific verbose mode, passing null to not show up on CLI
+ $this->pushError(null, PEAR_INSTALLER_SKIPPED);
+ } else {
+ do {
+ if ($params[$i] && $params[$i]->getType() == 'local') {
+ // bug #7090 skip channel.xml check for local packages
+ break;
+ }
+
+ if ($params[$i] && !isset($channelschecked[$params[$i]->getChannel()]) &&
+ !isset($this->_options['offline'])
+ ) {
+ $channelschecked[$params[$i]->getChannel()] = true;
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ if (!class_exists('System')) {
+ require_once 'System.php';
+ }
+
+ $curchannel = $this->_registry->getChannel($params[$i]->getChannel());
+ if (PEAR::isError($curchannel)) {
+ PEAR::staticPopErrorHandling();
+ return $this->raiseError($curchannel);
+ }
+
+ if (PEAR::isError($dir = $this->getDownloadDir())) {
+ PEAR::staticPopErrorHandling();
+ break;
+ }
+
+ $mirror = $this->config->get('preferred_mirror', null, $params[$i]->getChannel());
+ $url = 'http://' . $mirror . '/channel.xml';
+ $a = $this->downloadHttp($url, $this->ui, $dir, null, $curchannel->lastModified());
+
+ PEAR::staticPopErrorHandling();
+ if ($a === false) {
+ //channel.xml not modified
+ break;
+ } else if (PEAR::isError($a)) {
+ // Attempt fallback to https automatically
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ $a = $this->downloadHttp('https://' . $mirror .
+ '/channel.xml', $this->ui, $dir, null, $curchannel->lastModified());
+
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($a) || !$a) {
+ break;
+ }
+ }
+ $this->log(0, 'WARNING: channel "' . $params[$i]->getChannel() . '" has ' .
+ 'updated its protocols, use "' . PEAR_RUNTYPE . ' channel-update ' . $params[$i]->getChannel() .
+ '" to update');
+ }
+ } while (false);
+
+ if ($params[$i] && !isset($this->_options['downloadonly'])) {
+ if (isset($this->_options['packagingroot'])) {
+ $checkdir = $this->_prependPath(
+ $this->config->get('php_dir', null, $params[$i]->getChannel()),
+ $this->_options['packagingroot']);
+ } else {
+ $checkdir = $this->config->get('php_dir',
+ null, $params[$i]->getChannel());
+ }
+
+ while ($checkdir && $checkdir != '/' && !file_exists($checkdir)) {
+ $checkdir = dirname($checkdir);
+ }
+
+ if ($checkdir == '.') {
+ $checkdir = '/';
+ }
+
+ if (!is_writeable($checkdir)) {
+ return PEAR::raiseError('Cannot install, php_dir for channel "' .
+ $params[$i]->getChannel() . '" is not writeable by the current user');
+ }
+ }
+ }
+ }
+
+ unset($channelschecked);
+ PEAR_Downloader_Package::removeDuplicates($params);
+ if (!count($params)) {
+ $a = array();
+ return $a;
+ }
+
+ if (!isset($this->_options['nodeps']) && !isset($this->_options['offline'])) {
+ $reverify = true;
+ while ($reverify) {
+ $reverify = false;
+ foreach ($params as $i => $param) {
+ //PHP Bug 40768 / PEAR Bug #10944
+ //Nested foreaches fail in PHP 5.2.1
+ key($params);
+ $ret = $params[$i]->detectDependencies($params);
+ if (PEAR::isError($ret)) {
+ $reverify = true;
+ $params[$i] = false;
+ PEAR_Downloader_Package::removeDuplicates($params);
+ if (!isset($this->_options['soft'])) {
+ $this->log(0, $ret->getMessage());
+ }
+ continue 2;
+ }
+ }
+ }
+ }
+
+ if (isset($this->_options['offline'])) {
+ $this->log(3, 'Skipping dependency download check, --offline specified');
+ }
+
+ if (!count($params)) {
+ $a = array();
+ return $a;
+ }
+
+ while (PEAR_Downloader_Package::mergeDependencies($params));
+ PEAR_Downloader_Package::removeDuplicates($params, true);
+ $errorparams = array();
+ if (PEAR_Downloader_Package::detectStupidDuplicates($params, $errorparams)) {
+ if (count($errorparams)) {
+ foreach ($errorparams as $param) {
+ $name = $this->_registry->parsedPackageNameToString($param->getParsedPackage());
+ $this->pushError('Duplicate package ' . $name . ' found', PEAR_INSTALLER_FAILED);
+ }
+ $a = array();
+ return $a;
+ }
+ }
+
+ PEAR_Downloader_Package::removeInstalled($params);
+ if (!count($params)) {
+ $this->pushError('No valid packages found', PEAR_INSTALLER_FAILED);
+ $a = array();
+ return $a;
+ }
+
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ $err = $this->analyzeDependencies($params);
+ PEAR::popErrorHandling();
+ if (!count($params)) {
+ $this->pushError('No valid packages found', PEAR_INSTALLER_FAILED);
+ $a = array();
+ return $a;
+ }
+
+ $ret = array();
+ $newparams = array();
+ if (isset($this->_options['pretend'])) {
+ return $params;
+ }
+
+ $somefailed = false;
+ foreach ($params as $i => $package) {
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $pf = &$params[$i]->download();
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($pf)) {
+ if (!isset($this->_options['soft'])) {
+ $this->log(1, $pf->getMessage());
+ $this->log(0, 'Error: cannot download "' .
+ $this->_registry->parsedPackageNameToString($package->getParsedPackage(),
+ true) .
+ '"');
+ }
+ $somefailed = true;
+ continue;
+ }
+
+ $newparams[] = &$params[$i];
+ $ret[] = array(
+ 'file' => $pf->getArchiveFile(),
+ 'info' => &$pf,
+ 'pkg' => $pf->getPackage()
+ );
+ }
+
+ if ($somefailed) {
+ // remove params that did not download successfully
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ $err = $this->analyzeDependencies($newparams, true);
+ PEAR::popErrorHandling();
+ if (!count($newparams)) {
+ $this->pushError('Download failed', PEAR_INSTALLER_FAILED);
+ $a = array();
+ return $a;
+ }
+ }
+
+ $this->_downloadedPackages = $ret;
+ return $newparams;
+ }
+
+ /**
+ * @param array all packages to be installed
+ */
+ function analyzeDependencies(&$params, $force = false)
+ {
+ if (isset($this->_options['downloadonly'])) {
+ return;
+ }
+
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $redo = true;
+ $reset = $hasfailed = $failed = false;
+ while ($redo) {
+ $redo = false;
+ foreach ($params as $i => $param) {
+ $deps = $param->getDeps();
+ if (!$deps) {
+ $depchecker = &$this->getDependency2Object($this->config, $this->getOptions(),
+ $param->getParsedPackage(), PEAR_VALIDATE_DOWNLOADING);
+ $send = $param->getPackageFile();
+
+ $installcheck = $depchecker->validatePackage($send, $this, $params);
+ if (PEAR::isError($installcheck)) {
+ if (!isset($this->_options['soft'])) {
+ $this->log(0, $installcheck->getMessage());
+ }
+ $hasfailed = true;
+ $params[$i] = false;
+ $reset = true;
+ $redo = true;
+ $failed = false;
+ PEAR_Downloader_Package::removeDuplicates($params);
+ continue 2;
+ }
+ continue;
+ }
+
+ if (!$reset && $param->alreadyValidated() && !$force) {
+ continue;
+ }
+
+ if (count($deps)) {
+ $depchecker = &$this->getDependency2Object($this->config, $this->getOptions(),
+ $param->getParsedPackage(), PEAR_VALIDATE_DOWNLOADING);
+ $send = $param->getPackageFile();
+ if ($send === null) {
+ $send = $param->getDownloadURL();
+ }
+
+ $installcheck = $depchecker->validatePackage($send, $this, $params);
+ if (PEAR::isError($installcheck)) {
+ if (!isset($this->_options['soft'])) {
+ $this->log(0, $installcheck->getMessage());
+ }
+ $hasfailed = true;
+ $params[$i] = false;
+ $reset = true;
+ $redo = true;
+ $failed = false;
+ PEAR_Downloader_Package::removeDuplicates($params);
+ continue 2;
+ }
+
+ $failed = false;
+ if (isset($deps['required']) && is_array($deps['required'])) {
+ foreach ($deps['required'] as $type => $dep) {
+ // note: Dependency2 will never return a PEAR_Error if ignore-errors
+ // is specified, so soft is needed to turn off logging
+ if (!isset($dep[0])) {
+ if (PEAR::isError($e = $depchecker->{"validate{$type}Dependency"}($dep,
+ true, $params))) {
+ $failed = true;
+ if (!isset($this->_options['soft'])) {
+ $this->log(0, $e->getMessage());
+ }
+ } elseif (is_array($e) && !$param->alreadyValidated()) {
+ if (!isset($this->_options['soft'])) {
+ $this->log(0, $e[0]);
+ }
+ }
+ } else {
+ foreach ($dep as $d) {
+ if (PEAR::isError($e =
+ $depchecker->{"validate{$type}Dependency"}($d,
+ true, $params))) {
+ $failed = true;
+ if (!isset($this->_options['soft'])) {
+ $this->log(0, $e->getMessage());
+ }
+ } elseif (is_array($e) && !$param->alreadyValidated()) {
+ if (!isset($this->_options['soft'])) {
+ $this->log(0, $e[0]);
+ }
+ }
+ }
+ }
+ }
+
+ if (isset($deps['optional']) && is_array($deps['optional'])) {
+ foreach ($deps['optional'] as $type => $dep) {
+ if (!isset($dep[0])) {
+ if (PEAR::isError($e =
+ $depchecker->{"validate{$type}Dependency"}($dep,
+ false, $params))) {
+ $failed = true;
+ if (!isset($this->_options['soft'])) {
+ $this->log(0, $e->getMessage());
+ }
+ } elseif (is_array($e) && !$param->alreadyValidated()) {
+ if (!isset($this->_options['soft'])) {
+ $this->log(0, $e[0]);
+ }
+ }
+ } else {
+ foreach ($dep as $d) {
+ if (PEAR::isError($e =
+ $depchecker->{"validate{$type}Dependency"}($d,
+ false, $params))) {
+ $failed = true;
+ if (!isset($this->_options['soft'])) {
+ $this->log(0, $e->getMessage());
+ }
+ } elseif (is_array($e) && !$param->alreadyValidated()) {
+ if (!isset($this->_options['soft'])) {
+ $this->log(0, $e[0]);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ $groupname = $param->getGroup();
+ if (isset($deps['group']) && $groupname) {
+ if (!isset($deps['group'][0])) {
+ $deps['group'] = array($deps['group']);
+ }
+
+ $found = false;
+ foreach ($deps['group'] as $group) {
+ if ($group['attribs']['name'] == $groupname) {
+ $found = true;
+ break;
+ }
+ }
+
+ if ($found) {
+ unset($group['attribs']);
+ foreach ($group as $type => $dep) {
+ if (!isset($dep[0])) {
+ if (PEAR::isError($e =
+ $depchecker->{"validate{$type}Dependency"}($dep,
+ false, $params))) {
+ $failed = true;
+ if (!isset($this->_options['soft'])) {
+ $this->log(0, $e->getMessage());
+ }
+ } elseif (is_array($e) && !$param->alreadyValidated()) {
+ if (!isset($this->_options['soft'])) {
+ $this->log(0, $e[0]);
+ }
+ }
+ } else {
+ foreach ($dep as $d) {
+ if (PEAR::isError($e =
+ $depchecker->{"validate{$type}Dependency"}($d,
+ false, $params))) {
+ $failed = true;
+ if (!isset($this->_options['soft'])) {
+ $this->log(0, $e->getMessage());
+ }
+ } elseif (is_array($e) && !$param->alreadyValidated()) {
+ if (!isset($this->_options['soft'])) {
+ $this->log(0, $e[0]);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ } else {
+ foreach ($deps as $dep) {
+ if (PEAR::isError($e = $depchecker->validateDependency1($dep, $params))) {
+ $failed = true;
+ if (!isset($this->_options['soft'])) {
+ $this->log(0, $e->getMessage());
+ }
+ } elseif (is_array($e) && !$param->alreadyValidated()) {
+ if (!isset($this->_options['soft'])) {
+ $this->log(0, $e[0]);
+ }
+ }
+ }
+ }
+ $params[$i]->setValidated();
+ }
+
+ if ($failed) {
+ $hasfailed = true;
+ $params[$i] = false;
+ $reset = true;
+ $redo = true;
+ $failed = false;
+ PEAR_Downloader_Package::removeDuplicates($params);
+ continue 2;
+ }
+ }
+ }
+
+ PEAR::staticPopErrorHandling();
+ if ($hasfailed && (isset($this->_options['ignore-errors']) ||
+ isset($this->_options['nodeps']))) {
+ // this is probably not needed, but just in case
+ if (!isset($this->_options['soft'])) {
+ $this->log(0, 'WARNING: dependencies failed');
+ }
+ }
+ }
+
+ /**
+ * Retrieve the directory that downloads will happen in
+ * @access private
+ * @return string
+ */
+ function getDownloadDir()
+ {
+ if (isset($this->_downloadDir)) {
+ return $this->_downloadDir;
+ }
+
+ $downloaddir = $this->config->get('download_dir');
+ if (empty($downloaddir) || (is_dir($downloaddir) && !is_writable($downloaddir))) {
+ if (is_dir($downloaddir) && !is_writable($downloaddir)) {
+ $this->log(0, 'WARNING: configuration download directory "' . $downloaddir .
+ '" is not writeable. Change download_dir config variable to ' .
+ 'a writeable dir to avoid this warning');
+ }
+
+ if (!class_exists('System')) {
+ require_once 'System.php';
+ }
+
+ if (PEAR::isError($downloaddir = System::mktemp('-d'))) {
+ return $downloaddir;
+ }
+ $this->log(3, '+ tmp dir created at ' . $downloaddir);
+ }
+
+ if (!is_writable($downloaddir)) {
+ if (PEAR::isError(System::mkdir(array('-p', $downloaddir))) ||
+ !is_writable($downloaddir)) {
+ return PEAR::raiseError('download directory "' . $downloaddir .
+ '" is not writeable. Change download_dir config variable to ' .
+ 'a writeable dir');
+ }
+ }
+
+ return $this->_downloadDir = $downloaddir;
+ }
+
+ function setDownloadDir($dir)
+ {
+ if (!@is_writable($dir)) {
+ if (PEAR::isError(System::mkdir(array('-p', $dir)))) {
+ return PEAR::raiseError('download directory "' . $dir .
+ '" is not writeable. Change download_dir config variable to ' .
+ 'a writeable dir');
+ }
+ }
+ $this->_downloadDir = $dir;
+ }
+
+ function configSet($key, $value, $layer = 'user', $channel = false)
+ {
+ $this->config->set($key, $value, $layer, $channel);
+ $this->_preferredState = $this->config->get('preferred_state', null, $channel);
+ if (!$this->_preferredState) {
+ // don't inadvertently use a non-set preferred_state
+ $this->_preferredState = null;
+ }
+ }
+
+ function setOptions($options)
+ {
+ $this->_options = $options;
+ }
+
+ function getOptions()
+ {
+ return $this->_options;
+ }
+
+
+ /**
+ * @param array output of {@link parsePackageName()}
+ * @access private
+ */
+ function _getPackageDownloadUrl($parr)
+ {
+ $curchannel = $this->config->get('default_channel');
+ $this->configSet('default_channel', $parr['channel']);
+ // getDownloadURL returns an array. On error, it only contains information
+ // on the latest release as array(version, info). On success it contains
+ // array(version, info, download url string)
+ $state = isset($parr['state']) ? $parr['state'] : $this->config->get('preferred_state');
+ if (!$this->_registry->channelExists($parr['channel'])) {
+ do {
+ if ($this->config->get('auto_discover') && $this->discover($parr['channel'])) {
+ break;
+ }
+
+ $this->configSet('default_channel', $curchannel);
+ return PEAR::raiseError('Unknown remote channel: ' . $parr['channel']);
+ } while (false);
+ }
+
+ $chan = $this->_registry->getChannel($parr['channel']);
+ if (PEAR::isError($chan)) {
+ return $chan;
+ }
+
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $version = $this->_registry->packageInfo($parr['package'], 'version', $parr['channel']);
+ $stability = $this->_registry->packageInfo($parr['package'], 'stability', $parr['channel']);
+ // package is installed - use the installed release stability level
+ if (!isset($parr['state']) && $stability !== null) {
+ $state = $stability['release'];
+ }
+ PEAR::staticPopErrorHandling();
+ $base2 = false;
+
+ $preferred_mirror = $this->config->get('preferred_mirror');
+ if (!$chan->supportsREST($preferred_mirror) ||
+ (
+ !($base2 = $chan->getBaseURL('REST1.3', $preferred_mirror))
+ &&
+ !($base = $chan->getBaseURL('REST1.0', $preferred_mirror))
+ )
+ ) {
+ return $this->raiseError($parr['channel'] . ' is using a unsupported protocol - This should never happen.');
+ }
+
+ if ($base2) {
+ $rest = &$this->config->getREST('1.3', $this->_options);
+ $base = $base2;
+ } else {
+ $rest = &$this->config->getREST('1.0', $this->_options);
+ }
+
+ $downloadVersion = false;
+ if (!isset($parr['version']) && !isset($parr['state']) && $version
+ && !PEAR::isError($version)
+ && !isset($this->_options['downloadonly'])
+ ) {
+ $downloadVersion = $version;
+ }
+
+ $url = $rest->getDownloadURL($base, $parr, $state, $downloadVersion, $chan->getName());
+ if (PEAR::isError($url)) {
+ $this->configSet('default_channel', $curchannel);
+ return $url;
+ }
+
+ if ($parr['channel'] != $curchannel) {
+ $this->configSet('default_channel', $curchannel);
+ }
+
+ if (!is_array($url)) {
+ return $url;
+ }
+
+ $url['raw'] = false; // no checking is necessary for REST
+ if (!is_array($url['info'])) {
+ return PEAR::raiseError('Invalid remote dependencies retrieved from REST - ' .
+ 'this should never happen');
+ }
+
+ if (!isset($this->_options['force']) &&
+ !isset($this->_options['downloadonly']) &&
+ $version &&
+ !PEAR::isError($version) &&
+ !isset($parr['group'])
+ ) {
+ if (version_compare($version, $url['version'], '=')) {
+ return PEAR::raiseError($this->_registry->parsedPackageNameToString(
+ $parr, true) . ' is already installed and is the same as the ' .
+ 'released version ' . $url['version'], -976);
+ }
+
+ if (version_compare($version, $url['version'], '>')) {
+ return PEAR::raiseError($this->_registry->parsedPackageNameToString(
+ $parr, true) . ' is already installed and is newer than detected ' .
+ 'released version ' . $url['version'], -976);
+ }
+ }
+
+ if (isset($url['info']['required']) || $url['compatible']) {
+ require_once 'PEAR/PackageFile/v2.php';
+ $pf = new PEAR_PackageFile_v2;
+ $pf->setRawChannel($parr['channel']);
+ if ($url['compatible']) {
+ $pf->setRawCompatible($url['compatible']);
+ }
+ } else {
+ require_once 'PEAR/PackageFile/v1.php';
+ $pf = new PEAR_PackageFile_v1;
+ }
+
+ $pf->setRawPackage($url['package']);
+ $pf->setDeps($url['info']);
+ if ($url['compatible']) {
+ $pf->setCompatible($url['compatible']);
+ }
+
+ $pf->setRawState($url['stability']);
+ $url['info'] = &$pf;
+ if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) {
+ $ext = '.tar';
+ } else {
+ $ext = '.tgz';
+ }
+
+ if (is_array($url) && isset($url['url'])) {
+ $url['url'] .= $ext;
+ }
+
+ return $url;
+ }
+
+ /**
+ * @param array dependency array
+ * @access private
+ */
+ function _getDepPackageDownloadUrl($dep, $parr)
+ {
+ $xsdversion = isset($dep['rel']) ? '1.0' : '2.0';
+ $curchannel = $this->config->get('default_channel');
+ if (isset($dep['uri'])) {
+ $xsdversion = '2.0';
+ $chan = $this->_registry->getChannel('__uri');
+ if (PEAR::isError($chan)) {
+ return $chan;
+ }
+
+ $version = $this->_registry->packageInfo($dep['name'], 'version', '__uri');
+ $this->configSet('default_channel', '__uri');
+ } else {
+ if (isset($dep['channel'])) {
+ $remotechannel = $dep['channel'];
+ } else {
+ $remotechannel = 'pear.php.net';
+ }
+
+ if (!$this->_registry->channelExists($remotechannel)) {
+ do {
+ if ($this->config->get('auto_discover')) {
+ if ($this->discover($remotechannel)) {
+ break;
+ }
+ }
+ return PEAR::raiseError('Unknown remote channel: ' . $remotechannel);
+ } while (false);
+ }
+
+ $chan = $this->_registry->getChannel($remotechannel);
+ if (PEAR::isError($chan)) {
+ return $chan;
+ }
+
+ $version = $this->_registry->packageInfo($dep['name'], 'version', $remotechannel);
+ $this->configSet('default_channel', $remotechannel);
+ }
+
+ $state = isset($parr['state']) ? $parr['state'] : $this->config->get('preferred_state');
+ if (isset($parr['state']) && isset($parr['version'])) {
+ unset($parr['state']);
+ }
+
+ if (isset($dep['uri'])) {
+ $info = $this->newDownloaderPackage($this);
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $err = $info->initialize($dep);
+ PEAR::staticPopErrorHandling();
+ if (!$err) {
+ // skip parameters that were missed by preferred_state
+ return PEAR::raiseError('Cannot initialize dependency');
+ }
+
+ if (PEAR::isError($err)) {
+ if (!isset($this->_options['soft'])) {
+ $this->log(0, $err->getMessage());
+ }
+
+ if (is_object($info)) {
+ $param = $info->getChannel() . '/' . $info->getPackage();
+ }
+ return PEAR::raiseError('Package "' . $param . '" is not valid');
+ }
+ return $info;
+ } elseif ($chan->supportsREST($this->config->get('preferred_mirror'))
+ &&
+ (
+ ($base2 = $chan->getBaseURL('REST1.3', $this->config->get('preferred_mirror')))
+ ||
+ ($base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror')))
+ )
+ ) {
+ if ($base2) {
+ $base = $base2;
+ $rest = &$this->config->getREST('1.3', $this->_options);
+ } else {
+ $rest = &$this->config->getREST('1.0', $this->_options);
+ }
+
+ $url = $rest->getDepDownloadURL($base, $xsdversion, $dep, $parr,
+ $state, $version, $chan->getName());
+ if (PEAR::isError($url)) {
+ return $url;
+ }
+
+ if ($parr['channel'] != $curchannel) {
+ $this->configSet('default_channel', $curchannel);
+ }
+
+ if (!is_array($url)) {
+ return $url;
+ }
+
+ $url['raw'] = false; // no checking is necessary for REST
+ if (!is_array($url['info'])) {
+ return PEAR::raiseError('Invalid remote dependencies retrieved from REST - ' .
+ 'this should never happen');
+ }
+
+ if (isset($url['info']['required'])) {
+ if (!class_exists('PEAR_PackageFile_v2')) {
+ require_once 'PEAR/PackageFile/v2.php';
+ }
+ $pf = new PEAR_PackageFile_v2;
+ $pf->setRawChannel($remotechannel);
+ } else {
+ if (!class_exists('PEAR_PackageFile_v1')) {
+ require_once 'PEAR/PackageFile/v1.php';
+ }
+ $pf = new PEAR_PackageFile_v1;
+
+ }
+ $pf->setRawPackage($url['package']);
+ $pf->setDeps($url['info']);
+ if ($url['compatible']) {
+ $pf->setCompatible($url['compatible']);
+ }
+
+ $pf->setRawState($url['stability']);
+ $url['info'] = &$pf;
+ if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) {
+ $ext = '.tar';
+ } else {
+ $ext = '.tgz';
+ }
+
+ if (is_array($url) && isset($url['url'])) {
+ $url['url'] .= $ext;
+ }
+
+ return $url;
+ }
+
+ return $this->raiseError($parr['channel'] . ' is using a unsupported protocol - This should never happen.');
+ }
+
+ /**
+ * @deprecated in favor of _getPackageDownloadUrl
+ */
+ function getPackageDownloadUrl($package, $version = null, $channel = false)
+ {
+ if ($version) {
+ $package .= "-$version";
+ }
+ if ($this === null || $this->_registry === null) {
+ $package = "http://pear.php.net/get/$package";
+ } else {
+ $chan = $this->_registry->getChannel($channel);
+ if (PEAR::isError($chan)) {
+ return '';
+ }
+ $package = "http://" . $chan->getServer() . "/get/$package";
+ }
+ if (!extension_loaded("zlib")) {
+ $package .= '?uncompress=yes';
+ }
+ return $package;
+ }
+
+ /**
+ * 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;
+ }
+
+ 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':
+ if($params[1] == -1) {
+ $length = "Unknown size";
+ } else {
+ $length = number_format($params[1], 0, '', ',')." bytes";
+ }
+ $this->log(1, "Starting to download {$params[0]} ($length)");
+ break;
+ }
+ if (method_exists($this->ui, '_downloadCallback'))
+ $this->ui->_downloadCallback($msg, $params);
+ }
+
+ function _prependPath($path, $prepend)
+ {
+ if (strlen($prepend) > 0) {
+ if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) {
+ if (preg_match('/^[a-z]:/i', $prepend)) {
+ $prepend = substr($prepend, 2);
+ } elseif ($prepend{0} != '\\') {
+ $prepend = "\\$prepend";
+ }
+ $path = substr($path, 0, 2) . $prepend . substr($path, 2);
+ } else {
+ $path = $prepend . $path;
+ }
+ }
+ return $path;
+ }
+
+ /**
+ * @param string
+ * @param integer
+ */
+ function pushError($errmsg, $code = -1)
+ {
+ array_push($this->_errorStack, array($errmsg, $code));
+ }
+
+ function getErrorMsgs()
+ {
+ $msgs = array();
+ $errs = $this->_errorStack;
+ foreach ($errs as $err) {
+ $msgs[] = $err[0];
+ }
+ $this->_errorStack = array();
+ return $msgs;
+ }
+
+ /**
+ * for BC
+ *
+ * @deprecated
+ */
+ function sortPkgDeps(&$packages, $uninstall = false)
+ {
+ $uninstall ?
+ $this->sortPackagesForUninstall($packages) :
+ $this->sortPackagesForInstall($packages);
+ }
+
+ /**
+ * Sort a list of arrays of array(downloaded packagefilename) by dependency.
+ *
+ * This uses the topological sort method from graph theory, and the
+ * Structures_Graph package to properly sort dependencies for installation.
+ * @param array an array of downloaded PEAR_Downloader_Packages
+ * @return array array of array(packagefilename, package.xml contents)
+ */
+ function sortPackagesForInstall(&$packages)
+ {
+ require_once 'Structures/Graph.php';
+ require_once 'Structures/Graph/Node.php';
+ require_once 'Structures/Graph/Manipulator/TopologicalSorter.php';
+ $depgraph = new Structures_Graph(true);
+ $nodes = array();
+ $reg = &$this->config->getRegistry();
+ foreach ($packages as $i => $package) {
+ $pname = $reg->parsedPackageNameToString(
+ array(
+ 'channel' => $package->getChannel(),
+ 'package' => strtolower($package->getPackage()),
+ ));
+ $nodes[$pname] = new Structures_Graph_Node;
+ $nodes[$pname]->setData($packages[$i]);
+ $depgraph->addNode($nodes[$pname]);
+ }
+
+ $deplinks = array();
+ foreach ($nodes as $package => $node) {
+ $pf = &$node->getData();
+ $pdeps = $pf->getDeps(true);
+ if (!$pdeps) {
+ continue;
+ }
+
+ if ($pf->getPackagexmlVersion() == '1.0') {
+ foreach ($pdeps as $dep) {
+ if ($dep['type'] != 'pkg' ||
+ (isset($dep['optional']) && $dep['optional'] == 'yes')) {
+ continue;
+ }
+
+ $dname = $reg->parsedPackageNameToString(
+ array(
+ 'channel' => 'pear.php.net',
+ 'package' => strtolower($dep['name']),
+ ));
+
+ if (isset($nodes[$dname])) {
+ if (!isset($deplinks[$dname])) {
+ $deplinks[$dname] = array();
+ }
+
+ $deplinks[$dname][$package] = 1;
+ // dependency is in installed packages
+ continue;
+ }
+
+ $dname = $reg->parsedPackageNameToString(
+ array(
+ 'channel' => 'pecl.php.net',
+ 'package' => strtolower($dep['name']),
+ ));
+
+ if (isset($nodes[$dname])) {
+ if (!isset($deplinks[$dname])) {
+ $deplinks[$dname] = array();
+ }
+
+ $deplinks[$dname][$package] = 1;
+ // dependency is in installed packages
+ continue;
+ }
+ }
+ } else {
+ // the only ordering we care about is:
+ // 1) subpackages must be installed before packages that depend on them
+ // 2) required deps must be installed before packages that depend on them
+ if (isset($pdeps['required']['subpackage'])) {
+ $t = $pdeps['required']['subpackage'];
+ if (!isset($t[0])) {
+ $t = array($t);
+ }
+
+ $this->_setupGraph($t, $reg, $deplinks, $nodes, $package);
+ }
+
+ if (isset($pdeps['group'])) {
+ if (!isset($pdeps['group'][0])) {
+ $pdeps['group'] = array($pdeps['group']);
+ }
+
+ foreach ($pdeps['group'] as $group) {
+ if (isset($group['subpackage'])) {
+ $t = $group['subpackage'];
+ if (!isset($t[0])) {
+ $t = array($t);
+ }
+
+ $this->_setupGraph($t, $reg, $deplinks, $nodes, $package);
+ }
+ }
+ }
+
+ if (isset($pdeps['optional']['subpackage'])) {
+ $t = $pdeps['optional']['subpackage'];
+ if (!isset($t[0])) {
+ $t = array($t);
+ }
+
+ $this->_setupGraph($t, $reg, $deplinks, $nodes, $package);
+ }
+
+ if (isset($pdeps['required']['package'])) {
+ $t = $pdeps['required']['package'];
+ if (!isset($t[0])) {
+ $t = array($t);
+ }
+
+ $this->_setupGraph($t, $reg, $deplinks, $nodes, $package);
+ }
+
+ if (isset($pdeps['group'])) {
+ if (!isset($pdeps['group'][0])) {
+ $pdeps['group'] = array($pdeps['group']);
+ }
+
+ foreach ($pdeps['group'] as $group) {
+ if (isset($group['package'])) {
+ $t = $group['package'];
+ if (!isset($t[0])) {
+ $t = array($t);
+ }
+
+ $this->_setupGraph($t, $reg, $deplinks, $nodes, $package);
+ }
+ }
+ }
+ }
+ }
+
+ $this->_detectDepCycle($deplinks);
+ foreach ($deplinks as $dependent => $parents) {
+ foreach ($parents as $parent => $unused) {
+ $nodes[$dependent]->connectTo($nodes[$parent]);
+ }
+ }
+
+ $installOrder = Structures_Graph_Manipulator_TopologicalSorter::sort($depgraph);
+ $ret = array();
+ for ($i = 0, $count = count($installOrder); $i < $count; $i++) {
+ foreach ($installOrder[$i] as $index => $sortedpackage) {
+ $data = &$installOrder[$i][$index]->getData();
+ $ret[] = &$nodes[$reg->parsedPackageNameToString(
+ array(
+ 'channel' => $data->getChannel(),
+ 'package' => strtolower($data->getPackage()),
+ ))]->getData();
+ }
+ }
+
+ $packages = $ret;
+ return;
+ }
+
+ /**
+ * Detect recursive links between dependencies and break the cycles
+ *
+ * @param array
+ * @access private
+ */
+ function _detectDepCycle(&$deplinks)
+ {
+ do {
+ $keepgoing = false;
+ foreach ($deplinks as $dep => $parents) {
+ foreach ($parents as $parent => $unused) {
+ // reset the parent cycle detector
+ $this->_testCycle(null, null, null);
+ if ($this->_testCycle($dep, $deplinks, $parent)) {
+ $keepgoing = true;
+ unset($deplinks[$dep][$parent]);
+ if (count($deplinks[$dep]) == 0) {
+ unset($deplinks[$dep]);
+ }
+
+ continue 3;
+ }
+ }
+ }
+ } while ($keepgoing);
+ }
+
+ function _testCycle($test, $deplinks, $dep)
+ {
+ static $visited = array();
+ if ($test === null) {
+ $visited = array();
+ return;
+ }
+
+ // this happens when a parent has a dep cycle on another dependency
+ // but the child is not part of the cycle
+ if (isset($visited[$dep])) {
+ return false;
+ }
+
+ $visited[$dep] = 1;
+ if ($test == $dep) {
+ return true;
+ }
+
+ if (isset($deplinks[$dep])) {
+ if (in_array($test, array_keys($deplinks[$dep]), true)) {
+ return true;
+ }
+
+ foreach ($deplinks[$dep] as $parent => $unused) {
+ if ($this->_testCycle($test, $deplinks, $parent)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Set up the dependency for installation parsing
+ *
+ * @param array $t dependency information
+ * @param PEAR_Registry $reg
+ * @param array $deplinks list of dependency links already established
+ * @param array $nodes all existing package nodes
+ * @param string $package parent package name
+ * @access private
+ */
+ function _setupGraph($t, $reg, &$deplinks, &$nodes, $package)
+ {
+ foreach ($t as $dep) {
+ $depchannel = !isset($dep['channel']) ? '__uri': $dep['channel'];
+ $dname = $reg->parsedPackageNameToString(
+ array(
+ 'channel' => $depchannel,
+ 'package' => strtolower($dep['name']),
+ ));
+
+ if (isset($nodes[$dname])) {
+ if (!isset($deplinks[$dname])) {
+ $deplinks[$dname] = array();
+ }
+ $deplinks[$dname][$package] = 1;
+ }
+ }
+ }
+
+ function _dependsOn($a, $b)
+ {
+ return $this->_checkDepTree(strtolower($a->getChannel()), strtolower($a->getPackage()), $b);
+ }
+
+ function _checkDepTree($channel, $package, $b, $checked = array())
+ {
+ $checked[$channel][$package] = true;
+ if (!isset($this->_depTree[$channel][$package])) {
+ return false;
+ }
+
+ if (isset($this->_depTree[$channel][$package][strtolower($b->getChannel())]
+ [strtolower($b->getPackage())])) {
+ return true;
+ }
+
+ foreach ($this->_depTree[$channel][$package] as $ch => $packages) {
+ foreach ($packages as $pa => $true) {
+ if ($this->_checkDepTree($ch, $pa, $b, $checked)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ function _sortInstall($a, $b)
+ {
+ if (!$a->getDeps() && !$b->getDeps()) {
+ return 0; // neither package has dependencies, order is insignificant
+ }
+ if ($a->getDeps() && !$b->getDeps()) {
+ return 1; // $a must be installed after $b because $a has dependencies
+ }
+ if (!$a->getDeps() && $b->getDeps()) {
+ return -1; // $b must be installed after $a because $b has dependencies
+ }
+ // both packages have dependencies
+ if ($this->_dependsOn($a, $b)) {
+ return 1;
+ }
+ if ($this->_dependsOn($b, $a)) {
+ return -1;
+ }
+ return 0;
+ }
+
+ /**
+ * Download a file through HTTP. Considers suggested file name in
+ * Content-disposition: header and can run a callback function for
+ * different events. The callback will be called with two
+ * parameters: the callback type, and parameters. The implemented
+ * callback types are:
+ *
+ * 'setup' called at the very beginning, parameter is a UI object
+ * that should be used for all output
+ * 'message' the parameter is a string with an informational message
+ * 'saveas' may be used to save with a different file name, the
+ * parameter is the filename that is about to be used.
+ * If a 'saveas' callback returns a non-empty string,
+ * that file name will be used as the filename instead.
+ * Note that $save_dir will not be affected by this, only
+ * the basename of the file.
+ * 'start' download is starting, parameter is number of bytes
+ * that are expected, or -1 if unknown
+ * 'bytesread' parameter is the number of bytes read so far
+ * 'done' download is complete, parameter is the total number
+ * of bytes read
+ * 'connfailed' if the TCP/SSL connection fails, this callback is called
+ * with array(host,port,errno,errmsg)
+ * 'writefailed' if writing to disk fails, this callback is called
+ * with array(destfile,errmsg)
+ *
+ * If an HTTP proxy has been configured (http_proxy PEAR_Config
+ * setting), the proxy will be used.
+ *
+ * @param string $url the URL to download
+ * @param object $ui PEAR_Frontend_* instance
+ * @param object $config PEAR_Config instance
+ * @param string $save_dir directory to save file in
+ * @param mixed $callback function/method to call for status
+ * updates
+ * @param false|string|array $lastmodified header values to check against for caching
+ * use false to return the header values from this download
+ * @param false|array $accept Accept headers to send
+ * @param false|string $channel Channel to use for retrieving authentication
+ * @return mixed Returns the full path of the downloaded file or a PEAR
+ * error on failure. If the error is caused by
+ * socket-related errors, the error object will
+ * have the fsockopen error code available through
+ * getCode(). If caching is requested, then return the header
+ * values.
+ * If $lastmodified was given and the there are no changes,
+ * boolean false is returned.
+ *
+ * @access public
+ */
+ public static function _downloadHttp(
+ $object, $url, &$ui, $save_dir = '.', $callback = null, $lastmodified = null,
+ $accept = false, $channel = false
+ ) {
+ static $redirect = 0;
+ // always reset , so we are clean case of error
+ $wasredirect = $redirect;
+ $redirect = 0;
+ if ($callback) {
+ call_user_func($callback, 'setup', array(&$ui));
+ }
+
+ $info = parse_url($url);
+ if (!isset($info['scheme']) || !in_array($info['scheme'], array('http', 'https'))) {
+ return PEAR::raiseError('Cannot download non-http URL "' . $url . '"');
+ }
+
+ if (!isset($info['host'])) {
+ return PEAR::raiseError('Cannot download from non-URL "' . $url . '"');
+ }
+
+ $host = isset($info['host']) ? $info['host'] : null;
+ $port = isset($info['port']) ? $info['port'] : null;
+ $path = isset($info['path']) ? $info['path'] : null;
+
+ if ($object !== null) {
+ $config = $object->config;
+ } else {
+ $config = &PEAR_Config::singleton();
+ }
+
+ $proxy = new PEAR_Proxy($config);
+
+ if ($proxy->isProxyConfigured() && $callback) {
+ call_user_func($callback, 'message', "Using HTTP proxy $host:$port");
+ }
+
+ if (empty($port)) {
+ $port = (isset($info['scheme']) && $info['scheme'] == 'https') ? 443 : 80;
+ }
+
+ $scheme = (isset($info['scheme']) && $info['scheme'] == 'https') ? 'https' : 'http';
+ $secure = ($scheme == 'https');
+
+ $fp = $proxy->openSocket($host, $port, $secure);
+ if (PEAR::isError($fp)) {
+ if ($callback) {
+ $errno = $fp->getCode();
+ $errstr = $fp->getMessage();
+ call_user_func($callback, 'connfailed', array($host, $port,
+ $errno, $errstr));
+ }
+ return $fp;
+ }
+
+ $requestPath = $path;
+ if ($proxy->isProxyConfigured()) {
+ $requestPath = $url;
+ }
+
+ if ($lastmodified === false || $lastmodified) {
+ $request = "GET $requestPath HTTP/1.1\r\n";
+ } else {
+ $request = "GET $requestPath HTTP/1.0\r\n";
+ }
+ $request .= "Host: $host\r\n";
+
+ $ifmodifiedsince = '';
+ if (is_array($lastmodified)) {
+ if (isset($lastmodified['Last-Modified'])) {
+ $ifmodifiedsince = 'If-Modified-Since: ' . $lastmodified['Last-Modified'] . "\r\n";
+ }
+
+ if (isset($lastmodified['ETag'])) {
+ $ifmodifiedsince .= "If-None-Match: $lastmodified[ETag]\r\n";
+ }
+ } else {
+ $ifmodifiedsince = ($lastmodified ? "If-Modified-Since: $lastmodified\r\n" : '');
+ }
+
+ $request .= $ifmodifiedsince .
+ "User-Agent: PEAR/1.10.3/PHP/" . PHP_VERSION . "\r\n";
+
+ if ($object !== null) { // only pass in authentication for non-static calls
+ $username = $config->get('username', null, $channel);
+ $password = $config->get('password', null, $channel);
+ if ($username && $password) {
+ $tmp = base64_encode("$username:$password");
+ $request .= "Authorization: Basic $tmp\r\n";
+ }
+ }
+
+ $proxyAuth = $proxy->getProxyAuth();
+ if ($proxyAuth) {
+ $request .= 'Proxy-Authorization: Basic ' .
+ $proxyAuth . "\r\n";
+ }
+
+ if ($accept) {
+ $request .= 'Accept: ' . implode(', ', $accept) . "\r\n";
+ }
+
+ $request .= "Connection: close\r\n";
+ $request .= "\r\n";
+ fwrite($fp, $request);
+ $headers = array();
+ $reply = 0;
+ while (trim($line = fgets($fp, 1024))) {
+ if (preg_match('/^([^:]+):\s+(.*)\s*\\z/', $line, $matches)) {
+ $headers[strtolower($matches[1])] = trim($matches[2]);
+ } elseif (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) {
+ $reply = (int)$matches[1];
+ if ($reply == 304 && ($lastmodified || ($lastmodified === false))) {
+ return false;
+ }
+
+ if (!in_array($reply, array(200, 301, 302, 303, 305, 307))) {
+ return PEAR::raiseError("File $scheme://$host:$port$path not valid (received: $line)");
+ }
+ }
+ }
+
+ if ($reply != 200) {
+ if (!isset($headers['location'])) {
+ return PEAR::raiseError("File $scheme://$host:$port$path not valid (redirected but no location)");
+ }
+
+ if ($wasredirect > 4) {
+ return PEAR::raiseError("File $scheme://$host:$port$path not valid (redirection looped more than 5 times)");
+ }
+
+ $redirect = $wasredirect + 1;
+ return static::_downloadHttp($object, $headers['location'],
+ $ui, $save_dir, $callback, $lastmodified, $accept);
+ }
+
+ if (isset($headers['content-disposition']) &&
+ preg_match('/\sfilename=\"([^;]*\S)\"\s*(;|\\z)/', $headers['content-disposition'], $matches)) {
+ $save_as = basename($matches[1]);
+ } else {
+ $save_as = basename($url);
+ }
+
+ if ($callback) {
+ $tmp = call_user_func($callback, 'saveas', $save_as);
+ if ($tmp) {
+ $save_as = $tmp;
+ }
+ }
+
+ $dest_file = $save_dir . DIRECTORY_SEPARATOR . $save_as;
+ if (is_link($dest_file)) {
+ return PEAR::raiseError('SECURITY ERROR: Will not write to ' . $dest_file . ' as it is symlinked to ' . readlink($dest_file) . ' - Possible symlink attack');
+ }
+
+ if (!$wp = @fopen($dest_file, 'wb')) {
+ fclose($fp);
+ if ($callback) {
+ call_user_func($callback, 'writefailed', array($dest_file, $php_errormsg));
+ }
+ return PEAR::raiseError("could not open $dest_file for writing");
+ }
+
+ $length = isset($headers['content-length']) ? $headers['content-length'] : -1;
+
+ $bytes = 0;
+ if ($callback) {
+ call_user_func($callback, 'start', array(basename($dest_file), $length));
+ }
+
+ while ($data = fread($fp, 1024)) {
+ $bytes += strlen($data);
+ if ($callback) {
+ call_user_func($callback, 'bytesread', $bytes);
+ }
+ if (!@fwrite($wp, $data)) {
+ fclose($fp);
+ if ($callback) {
+ call_user_func($callback, 'writefailed', array($dest_file, $php_errormsg));
+ }
+ return PEAR::raiseError("$dest_file: write failed ($php_errormsg)");
+ }
+ }
+
+ fclose($fp);
+ fclose($wp);
+ if ($callback) {
+ call_user_func($callback, 'done', $bytes);
+ }
+
+ if ($lastmodified === false || $lastmodified) {
+ if (isset($headers['etag'])) {
+ $lastmodified = array('ETag' => $headers['etag']);
+ }
+
+ if (isset($headers['last-modified'])) {
+ if (is_array($lastmodified)) {
+ $lastmodified['Last-Modified'] = $headers['last-modified'];
+ } else {
+ $lastmodified = $headers['last-modified'];
+ }
+ }
+ return array($dest_file, $lastmodified, $headers);
+ }
+ return $dest_file;
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Downloader/Package.php b/vendor/pear-pear.php.net/PEAR/PEAR/Downloader/Package.php
new file mode 100644
index 000000000..925c0ecd5
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Downloader/Package.php
@@ -0,0 +1,1981 @@
+
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+
+/**
+ * Error code when parameter initialization fails because no releases
+ * exist within preferred_state, but releases do exist
+ */
+define('PEAR_DOWNLOADER_PACKAGE_STATE', -1003);
+/**
+ * Error code when parameter initialization fails because no releases
+ * exist that will work with the existing PHP version
+ */
+define('PEAR_DOWNLOADER_PACKAGE_PHPVERSION', -1004);
+
+/**
+ * Coordinates download parameters and manages their dependencies
+ * prior to downloading them.
+ *
+ * Input can come from three sources:
+ *
+ * - local files (archives or package.xml)
+ * - remote files (downloadable urls)
+ * - abstract package names
+ *
+ * The first two elements are handled cleanly by PEAR_PackageFile, but the third requires
+ * accessing pearweb's xml-rpc interface to determine necessary dependencies, and the
+ * format returned of dependencies is slightly different from that used in package.xml.
+ *
+ * This class hides the differences between these elements, and makes automatic
+ * dependency resolution a piece of cake. It also manages conflicts when
+ * two classes depend on incompatible dependencies, or differing versions of the same
+ * package dependency. In addition, download will not be attempted if the php version is
+ * not supported, PEAR installer version is not supported, or non-PECL extensions are not
+ * installed.
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_Downloader_Package
+{
+ /**
+ * @var PEAR_Downloader
+ */
+ var $_downloader;
+ /**
+ * @var PEAR_Config
+ */
+ var $_config;
+ /**
+ * @var PEAR_Registry
+ */
+ var $_registry;
+ /**
+ * Used to implement packagingroot properly
+ * @var PEAR_Registry
+ */
+ var $_installRegistry;
+ /**
+ * @var PEAR_PackageFile_v1|PEAR_PackageFile|v2
+ */
+ var $_packagefile;
+ /**
+ * @var array
+ */
+ var $_parsedname;
+ /**
+ * @var array
+ */
+ var $_downloadURL;
+ /**
+ * @var array
+ */
+ var $_downloadDeps = array();
+ /**
+ * @var boolean
+ */
+ var $_valid = false;
+ /**
+ * @var boolean
+ */
+ var $_analyzed = false;
+ /**
+ * if this or a parent package was invoked with Package-state, this is set to the
+ * state variable.
+ *
+ * This allows temporary reassignment of preferred_state for a parent package and all of
+ * its dependencies.
+ * @var string|false
+ */
+ var $_explicitState = false;
+ /**
+ * If this package is invoked with Package#group, this variable will be true
+ */
+ var $_explicitGroup = false;
+ /**
+ * Package type local|url
+ * @var string
+ */
+ var $_type;
+ /**
+ * Contents of package.xml, if downloaded from a remote channel
+ * @var string|false
+ * @access private
+ */
+ var $_rawpackagefile;
+ /**
+ * @var boolean
+ * @access private
+ */
+ var $_validated = false;
+
+ /**
+ * @param PEAR_Downloader
+ */
+ function __construct(&$downloader)
+ {
+ $this->_downloader = &$downloader;
+ $this->_config = &$this->_downloader->config;
+ $this->_registry = &$this->_config->getRegistry();
+ $options = $downloader->getOptions();
+ if (isset($options['packagingroot'])) {
+ $this->_config->setInstallRoot($options['packagingroot']);
+ $this->_installRegistry = &$this->_config->getRegistry();
+ $this->_config->setInstallRoot(false);
+ } else {
+ $this->_installRegistry = &$this->_registry;
+ }
+ $this->_valid = $this->_analyzed = false;
+ }
+
+ /**
+ * Parse the input and determine whether this is a local file, a remote uri, or an
+ * abstract package name.
+ *
+ * This is the heart of the PEAR_Downloader_Package(), and is used in
+ * {@link PEAR_Downloader::download()}
+ * @param string
+ * @return bool|PEAR_Error
+ */
+ function initialize($param)
+ {
+ $origErr = $this->_fromFile($param);
+ if ($this->_valid) {
+ return true;
+ }
+
+ $options = $this->_downloader->getOptions();
+ if (isset($options['offline'])) {
+ if (PEAR::isError($origErr) && !isset($options['soft'])) {
+ foreach ($origErr->getUserInfo() as $userInfo) {
+ if (isset($userInfo['message'])) {
+ $this->_downloader->log(0, $userInfo['message']);
+ }
+ }
+
+ $this->_downloader->log(0, $origErr->getMessage());
+ }
+
+ return PEAR::raiseError('Cannot download non-local package "' . $param . '"');
+ }
+
+ $err = $this->_fromUrl($param);
+ if (PEAR::isError($err) || !$this->_valid) {
+ if ($this->_type == 'url') {
+ if (PEAR::isError($err) && !isset($options['soft'])) {
+ $this->_downloader->log(0, $err->getMessage());
+ }
+
+ return PEAR::raiseError("Invalid or missing remote package file");
+ }
+
+ $err = $this->_fromString($param);
+ if (PEAR::isError($err) || !$this->_valid) {
+ if (PEAR::isError($err) && $err->getCode() == PEAR_DOWNLOADER_PACKAGE_STATE) {
+ return false; // instruct the downloader to silently skip
+ }
+
+ if (isset($this->_type) && $this->_type == 'local' && PEAR::isError($origErr)) {
+ if (is_array($origErr->getUserInfo())) {
+ foreach ($origErr->getUserInfo() as $err) {
+ if (is_array($err)) {
+ $err = $err['message'];
+ }
+
+ if (!isset($options['soft'])) {
+ $this->_downloader->log(0, $err);
+ }
+ }
+ }
+
+ if (!isset($options['soft'])) {
+ $this->_downloader->log(0, $origErr->getMessage());
+ }
+
+ if (is_array($param)) {
+ $param = $this->_registry->parsedPackageNameToString($param, true);
+ }
+
+ if (!isset($options['soft'])) {
+ $this->_downloader->log(2, "Cannot initialize '$param', invalid or missing package file");
+ }
+
+ // Passing no message back - already logged above
+ return PEAR::raiseError();
+ }
+
+ if (PEAR::isError($err) && !isset($options['soft'])) {
+ $this->_downloader->log(0, $err->getMessage());
+ }
+
+ if (is_array($param)) {
+ $param = $this->_registry->parsedPackageNameToString($param, true);
+ }
+
+ if (!isset($options['soft'])) {
+ $this->_downloader->log(2, "Cannot initialize '$param', invalid or missing package file");
+ }
+
+ // Passing no message back - already logged above
+ return PEAR::raiseError();
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Retrieve any non-local packages
+ * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|PEAR_Error
+ */
+ function &download()
+ {
+ if (isset($this->_packagefile)) {
+ return $this->_packagefile;
+ }
+
+ if (isset($this->_downloadURL['url'])) {
+ $this->_isvalid = false;
+ $info = $this->getParsedPackage();
+ foreach ($info as $i => $p) {
+ $info[$i] = strtolower($p);
+ }
+
+ $err = $this->_fromUrl($this->_downloadURL['url'],
+ $this->_registry->parsedPackageNameToString($this->_parsedname, true));
+ $newinfo = $this->getParsedPackage();
+ foreach ($newinfo as $i => $p) {
+ $newinfo[$i] = strtolower($p);
+ }
+
+ if ($info != $newinfo) {
+ do {
+ if ($info['channel'] == 'pecl.php.net' && $newinfo['channel'] == 'pear.php.net') {
+ $info['channel'] = 'pear.php.net';
+ if ($info == $newinfo) {
+ // skip the channel check if a pecl package says it's a PEAR package
+ break;
+ }
+ }
+ if ($info['channel'] == 'pear.php.net' && $newinfo['channel'] == 'pecl.php.net') {
+ $info['channel'] = 'pecl.php.net';
+ if ($info == $newinfo) {
+ // skip the channel check if a pecl package says it's a PEAR package
+ break;
+ }
+ }
+
+ return PEAR::raiseError('CRITICAL ERROR: We are ' .
+ $this->_registry->parsedPackageNameToString($info) . ', but the file ' .
+ 'downloaded claims to be ' .
+ $this->_registry->parsedPackageNameToString($this->getParsedPackage()));
+ } while (false);
+ }
+
+ if (PEAR::isError($err) || !$this->_valid) {
+ return $err;
+ }
+ }
+
+ $this->_type = 'local';
+ return $this->_packagefile;
+ }
+
+ function &getPackageFile()
+ {
+ return $this->_packagefile;
+ }
+
+ function &getDownloader()
+ {
+ return $this->_downloader;
+ }
+
+ function getType()
+ {
+ return $this->_type;
+ }
+
+ /**
+ * Like {@link initialize()}, but operates on a dependency
+ */
+ function fromDepURL($dep)
+ {
+ $this->_downloadURL = $dep;
+ if (isset($dep['uri'])) {
+ $options = $this->_downloader->getOptions();
+ if (!extension_loaded("zlib") || isset($options['nocompress'])) {
+ $ext = '.tar';
+ } else {
+ $ext = '.tgz';
+ }
+
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ $err = $this->_fromUrl($dep['uri'] . $ext);
+ PEAR::popErrorHandling();
+ if (PEAR::isError($err)) {
+ if (!isset($options['soft'])) {
+ $this->_downloader->log(0, $err->getMessage());
+ }
+
+ return PEAR::raiseError('Invalid uri dependency "' . $dep['uri'] . $ext . '", ' .
+ 'cannot download');
+ }
+ } else {
+ $this->_parsedname =
+ array(
+ 'package' => $dep['info']->getPackage(),
+ 'channel' => $dep['info']->getChannel(),
+ 'version' => $dep['version']
+ );
+ if (!isset($dep['nodefault'])) {
+ $this->_parsedname['group'] = 'default'; // download the default dependency group
+ $this->_explicitGroup = false;
+ }
+
+ $this->_rawpackagefile = $dep['raw'];
+ }
+ }
+
+ function detectDependencies($params)
+ {
+ $options = $this->_downloader->getOptions();
+ if (isset($options['downloadonly'])) {
+ return;
+ }
+
+ if (isset($options['offline'])) {
+ $this->_downloader->log(3, 'Skipping dependency download check, --offline specified');
+ return;
+ }
+
+ $pname = $this->getParsedPackage();
+ if (!$pname) {
+ return;
+ }
+
+ $deps = $this->getDeps();
+ if (!$deps) {
+ return;
+ }
+
+ if (isset($deps['required'])) { // package.xml 2.0
+ return $this->_detect2($deps, $pname, $options, $params);
+ }
+
+ return $this->_detect1($deps, $pname, $options, $params);
+ }
+
+ function setValidated()
+ {
+ $this->_validated = true;
+ }
+
+ function alreadyValidated()
+ {
+ return $this->_validated;
+ }
+
+ /**
+ * Remove packages to be downloaded that are already installed
+ * @param array of PEAR_Downloader_Package objects
+ */
+ public static function removeInstalled(&$params)
+ {
+ if (!isset($params[0])) {
+ return;
+ }
+
+ $options = $params[0]->_downloader->getOptions();
+ if (!isset($options['downloadonly'])) {
+ foreach ($params as $i => $param) {
+ $package = $param->getPackage();
+ $channel = $param->getChannel();
+ // remove self if already installed with this version
+ // this does not need any pecl magic - we only remove exact matches
+ if ($param->_installRegistry->packageExists($package, $channel)) {
+ $packageVersion = $param->_installRegistry->packageInfo($package, 'version', $channel);
+ if (version_compare($packageVersion, $param->getVersion(), '==')) {
+ if (!isset($options['force']) && !isset($options['packagingroot'])) {
+ $info = $param->getParsedPackage();
+ unset($info['version']);
+ unset($info['state']);
+ if (!isset($options['soft'])) {
+ $param->_downloader->log(1, 'Skipping package "' .
+ $param->getShortName() .
+ '", already installed as version ' . $packageVersion);
+ }
+ $params[$i] = false;
+ }
+ } elseif (!isset($options['force']) && !isset($options['upgrade']) &&
+ !isset($options['soft']) && !isset($options['packagingroot'])) {
+ $info = $param->getParsedPackage();
+ $param->_downloader->log(1, 'Skipping package "' .
+ $param->getShortName() .
+ '", already installed as version ' . $packageVersion);
+ $params[$i] = false;
+ }
+ }
+ }
+ }
+
+ PEAR_Downloader_Package::removeDuplicates($params);
+ }
+
+ function _detect2($deps, $pname, $options, $params)
+ {
+ $this->_downloadDeps = array();
+ $groupnotfound = false;
+ foreach (array('package', 'subpackage') as $packagetype) {
+ // get required dependency group
+ if (isset($deps['required'][$packagetype])) {
+ if (isset($deps['required'][$packagetype][0])) {
+ foreach ($deps['required'][$packagetype] as $dep) {
+ if (isset($dep['conflicts'])) {
+ // skip any package that this package conflicts with
+ continue;
+ }
+ $ret = $this->_detect2Dep($dep, $pname, 'required', $params);
+ if (is_array($ret)) {
+ $this->_downloadDeps[] = $ret;
+ } elseif (PEAR::isError($ret) && !isset($options['soft'])) {
+ $this->_downloader->log(0, $ret->getMessage());
+ }
+ }
+ } else {
+ $dep = $deps['required'][$packagetype];
+ if (!isset($dep['conflicts'])) {
+ // skip any package that this package conflicts with
+ $ret = $this->_detect2Dep($dep, $pname, 'required', $params);
+ if (is_array($ret)) {
+ $this->_downloadDeps[] = $ret;
+ } elseif (PEAR::isError($ret) && !isset($options['soft'])) {
+ $this->_downloader->log(0, $ret->getMessage());
+ }
+ }
+ }
+ }
+
+ // get optional dependency group, if any
+ if (isset($deps['optional'][$packagetype])) {
+ $skipnames = array();
+ if (!isset($deps['optional'][$packagetype][0])) {
+ $deps['optional'][$packagetype] = array($deps['optional'][$packagetype]);
+ }
+
+ foreach ($deps['optional'][$packagetype] as $dep) {
+ $skip = false;
+ if (!isset($options['alldeps'])) {
+ $dep['package'] = $dep['name'];
+ if (!isset($options['soft'])) {
+ $this->_downloader->log(3, 'Notice: package "' .
+ $this->_registry->parsedPackageNameToString($this->getParsedPackage(),
+ true) . '" optional dependency "' .
+ $this->_registry->parsedPackageNameToString(array('package' =>
+ $dep['name'], 'channel' => 'pear.php.net'), true) .
+ '" will not be automatically downloaded');
+ }
+ $skipnames[] = $this->_registry->parsedPackageNameToString($dep, true);
+ $skip = true;
+ unset($dep['package']);
+ }
+
+ $ret = $this->_detect2Dep($dep, $pname, 'optional', $params);
+ if (PEAR::isError($ret) && !isset($options['soft'])) {
+ $this->_downloader->log(0, $ret->getMessage());
+ }
+
+ if (!$ret) {
+ $dep['package'] = $dep['name'];
+ $skip = count($skipnames) ?
+ $skipnames[count($skipnames) - 1] : '';
+ if ($skip ==
+ $this->_registry->parsedPackageNameToString($dep, true)) {
+ array_pop($skipnames);
+ }
+ }
+
+ if (!$skip && is_array($ret)) {
+ $this->_downloadDeps[] = $ret;
+ }
+ }
+
+ if (count($skipnames)) {
+ if (!isset($options['soft'])) {
+ $this->_downloader->log(1, 'Did not download optional dependencies: ' .
+ implode(', ', $skipnames) .
+ ', use --alldeps to download automatically');
+ }
+ }
+ }
+
+ // get requested dependency group, if any
+ $groupname = $this->getGroup();
+ $explicit = $this->_explicitGroup;
+ if (!$groupname) {
+ if (!$this->canDefault()) {
+ continue;
+ }
+
+ $groupname = 'default'; // try the default dependency group
+ }
+
+ if ($groupnotfound) {
+ continue;
+ }
+
+ if (isset($deps['group'])) {
+ if (isset($deps['group']['attribs'])) {
+ if (strtolower($deps['group']['attribs']['name']) == strtolower($groupname)) {
+ $group = $deps['group'];
+ } elseif ($explicit) {
+ if (!isset($options['soft'])) {
+ $this->_downloader->log(0, 'Warning: package "' .
+ $this->_registry->parsedPackageNameToString($pname, true) .
+ '" has no dependency ' . 'group named "' . $groupname . '"');
+ }
+
+ $groupnotfound = true;
+ continue;
+ }
+ } else {
+ $found = false;
+ foreach ($deps['group'] as $group) {
+ if (strtolower($group['attribs']['name']) == strtolower($groupname)) {
+ $found = true;
+ break;
+ }
+ }
+
+ if (!$found) {
+ if ($explicit) {
+ if (!isset($options['soft'])) {
+ $this->_downloader->log(0, 'Warning: package "' .
+ $this->_registry->parsedPackageNameToString($pname, true) .
+ '" has no dependency ' . 'group named "' . $groupname . '"');
+ }
+ }
+
+ $groupnotfound = true;
+ continue;
+ }
+ }
+ }
+
+ if (isset($group) && isset($group[$packagetype])) {
+ if (isset($group[$packagetype][0])) {
+ foreach ($group[$packagetype] as $dep) {
+ $ret = $this->_detect2Dep($dep, $pname, 'dependency group "' .
+ $group['attribs']['name'] . '"', $params);
+ if (is_array($ret)) {
+ $this->_downloadDeps[] = $ret;
+ } elseif (PEAR::isError($ret) && !isset($options['soft'])) {
+ $this->_downloader->log(0, $ret->getMessage());
+ }
+ }
+ } else {
+ $ret = $this->_detect2Dep($group[$packagetype], $pname,
+ 'dependency group "' .
+ $group['attribs']['name'] . '"', $params);
+ if (is_array($ret)) {
+ $this->_downloadDeps[] = $ret;
+ } elseif (PEAR::isError($ret) && !isset($options['soft'])) {
+ $this->_downloader->log(0, $ret->getMessage());
+ }
+ }
+ }
+ }
+ }
+
+ function _detect2Dep($dep, $pname, $group, $params)
+ {
+ if (isset($dep['conflicts'])) {
+ return true;
+ }
+
+ $options = $this->_downloader->getOptions();
+ if (isset($dep['uri'])) {
+ return array('uri' => $dep['uri'], 'dep' => $dep);;
+ }
+
+ $testdep = $dep;
+ $testdep['package'] = $dep['name'];
+ if (PEAR_Downloader_Package::willDownload($testdep, $params)) {
+ $dep['package'] = $dep['name'];
+ if (!isset($options['soft'])) {
+ $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group .
+ ' dependency "' .
+ $this->_registry->parsedPackageNameToString($dep, true) .
+ '", will be installed');
+ }
+ return false;
+ }
+
+ $options = $this->_downloader->getOptions();
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ if ($this->_explicitState) {
+ $pname['state'] = $this->_explicitState;
+ }
+
+ $url = $this->_downloader->_getDepPackageDownloadUrl($dep, $pname);
+ if (PEAR::isError($url)) {
+ PEAR::popErrorHandling();
+ return $url;
+ }
+
+ $dep['package'] = $dep['name'];
+ $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params, $group == 'optional' &&
+ !isset($options['alldeps']), true);
+ PEAR::popErrorHandling();
+ if (PEAR::isError($ret)) {
+ if (!isset($options['soft'])) {
+ $this->_downloader->log(0, $ret->getMessage());
+ }
+
+ return false;
+ }
+
+ // check to see if a dep is already installed and is the same or newer
+ if (!isset($dep['min']) && !isset($dep['max']) && !isset($dep['recommended'])) {
+ $oper = 'has';
+ } else {
+ $oper = 'gt';
+ }
+
+ // do not try to move this before getDepPackageDownloadURL
+ // we can't determine whether upgrade is necessary until we know what
+ // version would be downloaded
+ if (!isset($options['force']) && $this->isInstalled($ret, $oper)) {
+ $version = $this->_installRegistry->packageInfo($dep['name'], 'version', $dep['channel']);
+ $dep['package'] = $dep['name'];
+ if (!isset($options['soft'])) {
+ $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group .
+ ' dependency "' .
+ $this->_registry->parsedPackageNameToString($dep, true) .
+ '" version ' . $url['version'] . ', already installed as version ' .
+ $version);
+ }
+
+ return false;
+ }
+
+ if (isset($dep['nodefault'])) {
+ $ret['nodefault'] = true;
+ }
+
+ return $ret;
+ }
+
+ function _detect1($deps, $pname, $options, $params)
+ {
+ $this->_downloadDeps = array();
+ $skipnames = array();
+ foreach ($deps as $dep) {
+ $nodownload = false;
+ if (isset ($dep['type']) && $dep['type'] === 'pkg') {
+ $dep['channel'] = 'pear.php.net';
+ $dep['package'] = $dep['name'];
+ switch ($dep['rel']) {
+ case 'not' :
+ continue 2;
+ case 'ge' :
+ case 'eq' :
+ case 'gt' :
+ case 'has' :
+ $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ?
+ 'required' :
+ 'optional';
+ if (PEAR_Downloader_Package::willDownload($dep, $params)) {
+ $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group
+ . ' dependency "' .
+ $this->_registry->parsedPackageNameToString($dep, true) .
+ '", will be installed');
+ continue 2;
+ }
+ $fakedp = new PEAR_PackageFile_v1;
+ $fakedp->setPackage($dep['name']);
+ // skip internet check if we are not upgrading (bug #5810)
+ if (!isset($options['upgrade']) && $this->isInstalled(
+ $fakedp, $dep['rel'])) {
+ $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group
+ . ' dependency "' .
+ $this->_registry->parsedPackageNameToString($dep, true) .
+ '", is already installed');
+ continue 2;
+ }
+ }
+
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ if ($this->_explicitState) {
+ $pname['state'] = $this->_explicitState;
+ }
+
+ $url = $this->_downloader->_getDepPackageDownloadUrl($dep, $pname);
+ $chan = 'pear.php.net';
+ if (PEAR::isError($url)) {
+ // check to see if this is a pecl package that has jumped
+ // from pear.php.net to pecl.php.net channel
+ if (!class_exists('PEAR_Dependency2')) {
+ require_once 'PEAR/Dependency2.php';
+ }
+
+ $newdep = PEAR_Dependency2::normalizeDep($dep);
+ $newdep = $newdep[0];
+ $newdep['channel'] = 'pecl.php.net';
+ $chan = 'pecl.php.net';
+ $url = $this->_downloader->_getDepPackageDownloadUrl($newdep, $pname);
+ $obj = &$this->_installRegistry->getPackage($dep['name']);
+ if (PEAR::isError($url)) {
+ PEAR::popErrorHandling();
+ if ($obj !== null && $this->isInstalled($obj, $dep['rel'])) {
+ $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ?
+ 'required' :
+ 'optional';
+ $dep['package'] = $dep['name'];
+ if (!isset($options['soft'])) {
+ $this->_downloader->log(3, $this->getShortName() .
+ ': Skipping ' . $group . ' dependency "' .
+ $this->_registry->parsedPackageNameToString($dep, true) .
+ '", already installed as version ' . $obj->getVersion());
+ }
+ $skip = count($skipnames) ?
+ $skipnames[count($skipnames) - 1] : '';
+ if ($skip ==
+ $this->_registry->parsedPackageNameToString($dep, true)) {
+ array_pop($skipnames);
+ }
+ continue;
+ } else {
+ if (isset($dep['optional']) && $dep['optional'] == 'yes') {
+ $this->_downloader->log(2, $this->getShortName() .
+ ': Skipping optional dependency "' .
+ $this->_registry->parsedPackageNameToString($dep, true) .
+ '", no releases exist');
+ continue;
+ } else {
+ return $url;
+ }
+ }
+ }
+ }
+
+ PEAR::popErrorHandling();
+ if (!isset($options['alldeps'])) {
+ if (isset($dep['optional']) && $dep['optional'] == 'yes') {
+ if (!isset($options['soft'])) {
+ $this->_downloader->log(3, 'Notice: package "' .
+ $this->getShortName() .
+ '" optional dependency "' .
+ $this->_registry->parsedPackageNameToString(
+ array('channel' => $chan, 'package' =>
+ $dep['name']), true) .
+ '" will not be automatically downloaded');
+ }
+ $skipnames[] = $this->_registry->parsedPackageNameToString(
+ array('channel' => $chan, 'package' =>
+ $dep['name']), true);
+ $nodownload = true;
+ }
+ }
+
+ if (!isset($options['alldeps']) && !isset($options['onlyreqdeps'])) {
+ if (!isset($dep['optional']) || $dep['optional'] == 'no') {
+ if (!isset($options['soft'])) {
+ $this->_downloader->log(3, 'Notice: package "' .
+ $this->getShortName() .
+ '" required dependency "' .
+ $this->_registry->parsedPackageNameToString(
+ array('channel' => $chan, 'package' =>
+ $dep['name']), true) .
+ '" will not be automatically downloaded');
+ }
+ $skipnames[] = $this->_registry->parsedPackageNameToString(
+ array('channel' => $chan, 'package' =>
+ $dep['name']), true);
+ $nodownload = true;
+ }
+ }
+
+ // check to see if a dep is already installed
+ // do not try to move this before getDepPackageDownloadURL
+ // we can't determine whether upgrade is necessary until we know what
+ // version would be downloaded
+ if (!isset($options['force']) && $this->isInstalled(
+ $url, $dep['rel'])) {
+ $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ?
+ 'required' :
+ 'optional';
+ $dep['package'] = $dep['name'];
+ if (isset($newdep)) {
+ $version = $this->_installRegistry->packageInfo($newdep['name'], 'version', $newdep['channel']);
+ } else {
+ $version = $this->_installRegistry->packageInfo($dep['name'], 'version');
+ }
+
+ $dep['version'] = $url['version'];
+ if (!isset($options['soft'])) {
+ $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group .
+ ' dependency "' .
+ $this->_registry->parsedPackageNameToString($dep, true) .
+ '", already installed as version ' . $version);
+ }
+
+ $skip = count($skipnames) ?
+ $skipnames[count($skipnames) - 1] : '';
+ if ($skip ==
+ $this->_registry->parsedPackageNameToString($dep, true)) {
+ array_pop($skipnames);
+ }
+
+ continue;
+ }
+
+ if ($nodownload) {
+ continue;
+ }
+
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ if (isset($newdep)) {
+ $dep = $newdep;
+ }
+
+ $dep['package'] = $dep['name'];
+ $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params,
+ isset($dep['optional']) && $dep['optional'] == 'yes' &&
+ !isset($options['alldeps']), true);
+ PEAR::popErrorHandling();
+ if (PEAR::isError($ret)) {
+ if (!isset($options['soft'])) {
+ $this->_downloader->log(0, $ret->getMessage());
+ }
+ continue;
+ }
+
+ $this->_downloadDeps[] = $ret;
+ }
+ }
+
+ if (count($skipnames)) {
+ if (!isset($options['soft'])) {
+ $this->_downloader->log(1, 'Did not download dependencies: ' .
+ implode(', ', $skipnames) .
+ ', use --alldeps or --onlyreqdeps to download automatically');
+ }
+ }
+ }
+
+ function setDownloadURL($pkg)
+ {
+ $this->_downloadURL = $pkg;
+ }
+
+ /**
+ * Set the package.xml object for this downloaded package
+ *
+ * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 $pkg
+ */
+ function setPackageFile(&$pkg)
+ {
+ $this->_packagefile = &$pkg;
+ }
+
+ function getShortName()
+ {
+ return $this->_registry->parsedPackageNameToString(array('channel' => $this->getChannel(),
+ 'package' => $this->getPackage()), true);
+ }
+
+ function getParsedPackage()
+ {
+ if (isset($this->_packagefile) || isset($this->_parsedname)) {
+ return array('channel' => $this->getChannel(),
+ 'package' => $this->getPackage(),
+ 'version' => $this->getVersion());
+ }
+
+ return false;
+ }
+
+ function getDownloadURL()
+ {
+ return $this->_downloadURL;
+ }
+
+ function canDefault()
+ {
+ if (isset($this->_downloadURL) && isset($this->_downloadURL['nodefault'])) {
+ return false;
+ }
+
+ return true;
+ }
+
+ function getPackage()
+ {
+ if (isset($this->_packagefile)) {
+ return $this->_packagefile->getPackage();
+ } elseif (isset($this->_downloadURL['info'])) {
+ return $this->_downloadURL['info']->getPackage();
+ }
+
+ return false;
+ }
+
+ /**
+ * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+ */
+ function isSubpackage(&$pf)
+ {
+ if (isset($this->_packagefile)) {
+ return $this->_packagefile->isSubpackage($pf);
+ } elseif (isset($this->_downloadURL['info'])) {
+ return $this->_downloadURL['info']->isSubpackage($pf);
+ }
+
+ return false;
+ }
+
+ function getPackageType()
+ {
+ if (isset($this->_packagefile)) {
+ return $this->_packagefile->getPackageType();
+ } elseif (isset($this->_downloadURL['info'])) {
+ return $this->_downloadURL['info']->getPackageType();
+ }
+
+ return false;
+ }
+
+ function isBundle()
+ {
+ if (isset($this->_packagefile)) {
+ return $this->_packagefile->getPackageType() == 'bundle';
+ }
+
+ return false;
+ }
+
+ function getPackageXmlVersion()
+ {
+ if (isset($this->_packagefile)) {
+ return $this->_packagefile->getPackagexmlVersion();
+ } elseif (isset($this->_downloadURL['info'])) {
+ return $this->_downloadURL['info']->getPackagexmlVersion();
+ }
+
+ return '1.0';
+ }
+
+ function getChannel()
+ {
+ if (isset($this->_packagefile)) {
+ return $this->_packagefile->getChannel();
+ } elseif (isset($this->_downloadURL['info'])) {
+ return $this->_downloadURL['info']->getChannel();
+ }
+
+ return false;
+ }
+
+ function getURI()
+ {
+ if (isset($this->_packagefile)) {
+ return $this->_packagefile->getURI();
+ } elseif (isset($this->_downloadURL['info'])) {
+ return $this->_downloadURL['info']->getURI();
+ }
+
+ return false;
+ }
+
+ function getVersion()
+ {
+ if (isset($this->_packagefile)) {
+ return $this->_packagefile->getVersion();
+ } elseif (isset($this->_downloadURL['version'])) {
+ return $this->_downloadURL['version'];
+ }
+
+ return false;
+ }
+
+ function isCompatible($pf)
+ {
+ if (isset($this->_packagefile)) {
+ return $this->_packagefile->isCompatible($pf);
+ } elseif (isset($this->_downloadURL['info'])) {
+ return $this->_downloadURL['info']->isCompatible($pf);
+ }
+
+ return true;
+ }
+
+ function setGroup($group)
+ {
+ $this->_parsedname['group'] = $group;
+ }
+
+ function getGroup()
+ {
+ if (isset($this->_parsedname['group'])) {
+ return $this->_parsedname['group'];
+ }
+
+ return '';
+ }
+
+ function isExtension($name)
+ {
+ if (isset($this->_packagefile)) {
+ return $this->_packagefile->isExtension($name);
+ } elseif (isset($this->_downloadURL['info'])) {
+ if ($this->_downloadURL['info']->getPackagexmlVersion() == '2.0') {
+ return $this->_downloadURL['info']->getProvidesExtension() == $name;
+ }
+
+ return false;
+ }
+
+ return false;
+ }
+
+ function getDeps()
+ {
+ if (isset($this->_packagefile)) {
+ $ver = $this->_packagefile->getPackagexmlVersion();
+ if (version_compare($ver, '2.0', '>=')) {
+ return $this->_packagefile->getDeps(true);
+ }
+
+ return $this->_packagefile->getDeps();
+ } elseif (isset($this->_downloadURL['info'])) {
+ $ver = $this->_downloadURL['info']->getPackagexmlVersion();
+ if (version_compare($ver, '2.0', '>=')) {
+ return $this->_downloadURL['info']->getDeps(true);
+ }
+
+ return $this->_downloadURL['info']->getDeps();
+ }
+
+ return array();
+ }
+
+ /**
+ * @param array Parsed array from {@link PEAR_Registry::parsePackageName()} or a dependency
+ * returned from getDepDownloadURL()
+ */
+ function isEqual($param)
+ {
+ if (is_object($param)) {
+ $channel = $param->getChannel();
+ $package = $param->getPackage();
+ if ($param->getURI()) {
+ $param = array(
+ 'channel' => $param->getChannel(),
+ 'package' => $param->getPackage(),
+ 'version' => $param->getVersion(),
+ 'uri' => $param->getURI(),
+ );
+ } else {
+ $param = array(
+ 'channel' => $param->getChannel(),
+ 'package' => $param->getPackage(),
+ 'version' => $param->getVersion(),
+ );
+ }
+ } else {
+ if (isset($param['uri'])) {
+ if ($this->getChannel() != '__uri') {
+ return false;
+ }
+ return $param['uri'] == $this->getURI();
+ }
+
+ $package = isset($param['package']) ? $param['package'] : $param['info']->getPackage();
+ $channel = isset($param['channel']) ? $param['channel'] : $param['info']->getChannel();
+ if (isset($param['rel'])) {
+ if (!class_exists('PEAR_Dependency2')) {
+ require_once 'PEAR/Dependency2.php';
+ }
+
+ $newdep = PEAR_Dependency2::normalizeDep($param);
+ $newdep = $newdep[0];
+ } elseif (isset($param['min'])) {
+ $newdep = $param;
+ }
+ }
+
+ if (isset($newdep)) {
+ if (!isset($newdep['min'])) {
+ $newdep['min'] = '0';
+ }
+
+ if (!isset($newdep['max'])) {
+ $newdep['max'] = '100000000000000000000';
+ }
+
+ // use magic to support pecl packages suddenly jumping to the pecl channel
+ // we need to support both dependency possibilities
+ if ($channel == 'pear.php.net' && $this->getChannel() == 'pecl.php.net') {
+ if ($package == $this->getPackage()) {
+ $channel = 'pecl.php.net';
+ }
+ }
+ if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') {
+ if ($package == $this->getPackage()) {
+ $channel = 'pear.php.net';
+ }
+ }
+
+ return (strtolower($package) == strtolower($this->getPackage()) &&
+ $channel == $this->getChannel() &&
+ version_compare($newdep['min'], $this->getVersion(), '<=') &&
+ version_compare($newdep['max'], $this->getVersion(), '>='));
+ }
+
+ // use magic to support pecl packages suddenly jumping to the pecl channel
+ if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') {
+ if (strtolower($package) == strtolower($this->getPackage())) {
+ $channel = 'pear.php.net';
+ }
+ }
+
+ if (isset($param['version'])) {
+ return (strtolower($package) == strtolower($this->getPackage()) &&
+ $channel == $this->getChannel() &&
+ $param['version'] == $this->getVersion());
+ }
+
+ return strtolower($package) == strtolower($this->getPackage()) &&
+ $channel == $this->getChannel();
+ }
+
+ function isInstalled($dep, $oper = '==')
+ {
+ if (!$dep) {
+ return false;
+ }
+
+ if ($oper != 'ge' && $oper != 'gt' && $oper != 'has' && $oper != '==') {
+ return false;
+ }
+
+ if (is_object($dep)) {
+ $package = $dep->getPackage();
+ $channel = $dep->getChannel();
+ if ($dep->getURI()) {
+ $dep = array(
+ 'uri' => $dep->getURI(),
+ 'version' => $dep->getVersion(),
+ );
+ } else {
+ $dep = array(
+ 'version' => $dep->getVersion(),
+ );
+ }
+ } else {
+ if (isset($dep['uri'])) {
+ $channel = '__uri';
+ $package = $dep['dep']['name'];
+ } else {
+ $channel = $dep['info']->getChannel();
+ $package = $dep['info']->getPackage();
+ }
+ }
+
+ $options = $this->_downloader->getOptions();
+ $test = $this->_installRegistry->packageExists($package, $channel);
+ if (!$test && $channel == 'pecl.php.net') {
+ // do magic to allow upgrading from old pecl packages to new ones
+ $test = $this->_installRegistry->packageExists($package, 'pear.php.net');
+ $channel = 'pear.php.net';
+ }
+
+ if ($test) {
+ if (isset($dep['uri'])) {
+ if ($this->_installRegistry->packageInfo($package, 'uri', '__uri') == $dep['uri']) {
+ return true;
+ }
+ }
+
+ if (isset($options['upgrade'])) {
+ $packageVersion = $this->_installRegistry->packageInfo($package, 'version', $channel);
+ if (version_compare($packageVersion, $dep['version'], '>=')) {
+ return true;
+ }
+
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Detect duplicate package names with differing versions
+ *
+ * If a user requests to install Date 1.4.6 and Date 1.4.7,
+ * for instance, this is a logic error. This method
+ * detects this situation.
+ *
+ * @param array $params array of PEAR_Downloader_Package objects
+ * @param array $errorparams empty array
+ * @return array array of stupid duplicated packages in PEAR_Downloader_Package obejcts
+ */
+ public static function detectStupidDuplicates($params, &$errorparams)
+ {
+ $existing = array();
+ foreach ($params as $i => $param) {
+ $package = $param->getPackage();
+ $channel = $param->getChannel();
+ $group = $param->getGroup();
+ if (!isset($existing[$channel . '/' . $package])) {
+ $existing[$channel . '/' . $package] = array();
+ }
+
+ if (!isset($existing[$channel . '/' . $package][$group])) {
+ $existing[$channel . '/' . $package][$group] = array();
+ }
+
+ $existing[$channel . '/' . $package][$group][] = $i;
+ }
+
+ $indices = array();
+ foreach ($existing as $package => $groups) {
+ foreach ($groups as $group => $dupes) {
+ if (count($dupes) > 1) {
+ $indices = $indices + $dupes;
+ }
+ }
+ }
+
+ $indices = array_unique($indices);
+ foreach ($indices as $index) {
+ $errorparams[] = $params[$index];
+ }
+
+ return count($errorparams);
+ }
+
+ /**
+ * @param array
+ * @param bool ignore install groups - for final removal of dupe packages
+ */
+ public static function removeDuplicates(&$params, $ignoreGroups = false)
+ {
+ $pnames = array();
+ foreach ($params as $i => $param) {
+ if (!$param) {
+ continue;
+ }
+
+ if ($param->getPackage()) {
+ $group = $ignoreGroups ? '' : $param->getGroup();
+ $pnames[$i] = $param->getChannel() . '/' .
+ $param->getPackage() . '-' . $param->getVersion() . '#' . $group;
+ }
+ }
+
+ $pnames = array_unique($pnames);
+ $unset = array_diff(array_keys($params), array_keys($pnames));
+ $testp = array_flip($pnames);
+ foreach ($params as $i => $param) {
+ if (!$param) {
+ $unset[] = $i;
+ continue;
+ }
+
+ if (!is_a($param, 'PEAR_Downloader_Package')) {
+ $unset[] = $i;
+ continue;
+ }
+
+ $group = $ignoreGroups ? '' : $param->getGroup();
+ if (!isset($testp[$param->getChannel() . '/' . $param->getPackage() . '-' .
+ $param->getVersion() . '#' . $group])) {
+ $unset[] = $i;
+ }
+ }
+
+ foreach ($unset as $i) {
+ unset($params[$i]);
+ }
+
+ $ret = array();
+ foreach ($params as $i => $param) {
+ $ret[] = &$params[$i];
+ }
+
+ $params = array();
+ foreach ($ret as $i => $param) {
+ $params[] = &$ret[$i];
+ }
+ }
+
+ function explicitState()
+ {
+ return $this->_explicitState;
+ }
+
+ function setExplicitState($s)
+ {
+ $this->_explicitState = $s;
+ }
+
+ /**
+ */
+ public static function mergeDependencies(&$params)
+ {
+ $bundles = $newparams = array();
+ foreach ($params as $i => $param) {
+ if (!$param->isBundle()) {
+ continue;
+ }
+
+ $bundles[] = $i;
+ $pf = &$param->getPackageFile();
+ $newdeps = array();
+ $contents = $pf->getBundledPackages();
+ if (!is_array($contents)) {
+ $contents = array($contents);
+ }
+
+ foreach ($contents as $file) {
+ $filecontents = $pf->getFileContents($file);
+ $dl = &$param->getDownloader();
+ $options = $dl->getOptions();
+ if (PEAR::isError($dir = $dl->getDownloadDir())) {
+ return $dir;
+ }
+
+ $fp = @fopen($dir . DIRECTORY_SEPARATOR . $file, 'wb');
+ if (!$fp) {
+ continue;
+ }
+
+ // FIXME do symlink check
+
+ fwrite($fp, $filecontents, strlen($filecontents));
+ fclose($fp);
+ if ($s = $params[$i]->explicitState()) {
+ $obj->setExplicitState($s);
+ }
+
+ $obj = new PEAR_Downloader_Package($params[$i]->getDownloader());
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ if (PEAR::isError($dir = $dl->getDownloadDir())) {
+ PEAR::popErrorHandling();
+ return $dir;
+ }
+ $a = $dir . DIRECTORY_SEPARATOR . $file;
+ $e = $obj->_fromFile($a);
+ PEAR::popErrorHandling();
+ if (PEAR::isError($e)) {
+ if (!isset($options['soft'])) {
+ $dl->log(0, $e->getMessage());
+ }
+ continue;
+ }
+
+ if (!PEAR_Downloader_Package::willDownload($obj,
+ array_merge($params, $newparams)) && !$param->isInstalled($obj)) {
+ $newparams[] = $obj;
+ }
+ }
+ }
+
+ foreach ($bundles as $i) {
+ unset($params[$i]); // remove bundles - only their contents matter for installation
+ }
+
+ PEAR_Downloader_Package::removeDuplicates($params); // strip any unset indices
+ if (count($newparams)) { // add in bundled packages for install
+ foreach ($newparams as $i => $unused) {
+ $params[] = &$newparams[$i];
+ }
+ $newparams = array();
+ }
+
+ foreach ($params as $i => $param) {
+ $newdeps = array();
+ foreach ($param->_downloadDeps as $dep) {
+ $merge = array_merge($params, $newparams);
+ if (!PEAR_Downloader_Package::willDownload($dep, $merge)
+ && !$param->isInstalled($dep)
+ ) {
+ $newdeps[] = $dep;
+ } else {
+ //var_dump($dep);
+ // detect versioning conflicts here
+ }
+ }
+
+ // convert the dependencies into PEAR_Downloader_Package objects for the next time around
+ $params[$i]->_downloadDeps = array();
+ foreach ($newdeps as $dep) {
+ $obj = new PEAR_Downloader_Package($params[$i]->getDownloader());
+ if ($s = $params[$i]->explicitState()) {
+ $obj->setExplicitState($s);
+ }
+
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ $e = $obj->fromDepURL($dep);
+ PEAR::popErrorHandling();
+ if (PEAR::isError($e)) {
+ if (!isset($options['soft'])) {
+ $obj->_downloader->log(0, $e->getMessage());
+ }
+ continue;
+ }
+
+ $e = $obj->detectDependencies($params);
+ if (PEAR::isError($e)) {
+ if (!isset($options['soft'])) {
+ $obj->_downloader->log(0, $e->getMessage());
+ }
+ }
+
+ $newparams[] = $obj;
+ }
+ }
+
+ if (count($newparams)) {
+ foreach ($newparams as $i => $unused) {
+ $params[] = &$newparams[$i];
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+
+ /**
+ */
+ public static function willDownload($param, $params)
+ {
+ if (!is_array($params)) {
+ return false;
+ }
+
+ foreach ($params as $obj) {
+ if ($obj->isEqual($param)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * For simpler unit-testing
+ * @param PEAR_Config
+ * @param int
+ * @param string
+ */
+ function &getPackagefileObject(&$c, $d)
+ {
+ $a = new PEAR_PackageFile($c, $d);
+ return $a;
+ }
+
+ /**
+ * This will retrieve from a local file if possible, and parse out
+ * a group name as well. The original parameter will be modified to reflect this.
+ * @param string|array can be a parsed package name as well
+ * @access private
+ */
+ function _fromFile(&$param)
+ {
+ $saveparam = $param;
+ if (is_string($param)) {
+ if (!@file_exists($param)) {
+ $test = explode('#', $param);
+ $group = array_pop($test);
+ if (@file_exists(implode('#', $test))) {
+ $this->setGroup($group);
+ $param = implode('#', $test);
+ $this->_explicitGroup = true;
+ }
+ }
+
+ if (@is_file($param)) {
+ $this->_type = 'local';
+ $options = $this->_downloader->getOptions();
+ $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->_debug);
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ $pf = &$pkg->fromAnyFile($param, PEAR_VALIDATE_INSTALLING);
+ PEAR::popErrorHandling();
+ if (PEAR::isError($pf)) {
+ $this->_valid = false;
+ $param = $saveparam;
+ return $pf;
+ }
+ $this->_packagefile = &$pf;
+ if (!$this->getGroup()) {
+ $this->setGroup('default'); // install the default dependency group
+ }
+ return $this->_valid = true;
+ }
+ }
+ $param = $saveparam;
+ return $this->_valid = false;
+ }
+
+ function _fromUrl($param, $saveparam = '')
+ {
+ if (!is_array($param) && (preg_match('#^(http|https|ftp)://#', $param))) {
+ $options = $this->_downloader->getOptions();
+ $this->_type = 'url';
+ $callback = $this->_downloader->ui ?
+ array(&$this->_downloader, '_downloadCallback') : null;
+ $this->_downloader->pushErrorHandling(PEAR_ERROR_RETURN);
+ if (PEAR::isError($dir = $this->_downloader->getDownloadDir())) {
+ $this->_downloader->popErrorHandling();
+ return $dir;
+ }
+
+ $this->_downloader->log(3, 'Downloading "' . $param . '"');
+ $file = $this->_downloader->downloadHttp($param, $this->_downloader->ui,
+ $dir, $callback, null, false, $this->getChannel());
+ $this->_downloader->popErrorHandling();
+ if (PEAR::isError($file)) {
+ if (!empty($saveparam)) {
+ $saveparam = ", cannot download \"$saveparam\"";
+ }
+ $err = PEAR::raiseError('Could not download from "' . $param .
+ '"' . $saveparam . ' (' . $file->getMessage() . ')');
+ return $err;
+ }
+
+ if ($this->_rawpackagefile) {
+ require_once 'Archive/Tar.php';
+ $tar = new Archive_Tar($file);
+ $packagexml = $tar->extractInString('package2.xml');
+ if (!$packagexml) {
+ $packagexml = $tar->extractInString('package.xml');
+ }
+
+ if (str_replace(array("\n", "\r"), array('',''), $packagexml) !=
+ str_replace(array("\n", "\r"), array('',''), $this->_rawpackagefile)) {
+ if ($this->getChannel() != 'pear.php.net') {
+ return PEAR::raiseError('CRITICAL ERROR: package.xml downloaded does ' .
+ 'not match value returned from xml-rpc');
+ }
+
+ // be more lax for the existing PEAR packages that have not-ok
+ // characters in their package.xml
+ $this->_downloader->log(0, 'CRITICAL WARNING: The "' .
+ $this->getPackage() . '" package has invalid characters in its ' .
+ 'package.xml. The next version of PEAR may not be able to install ' .
+ 'this package for security reasons. Please open a bug report at ' .
+ 'http://pear.php.net/package/' . $this->getPackage() . '/bugs');
+ }
+ }
+
+ // whew, download worked!
+ $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->debug);
+
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ $pf = &$pkg->fromAnyFile($file, PEAR_VALIDATE_INSTALLING);
+ PEAR::popErrorHandling();
+ if (PEAR::isError($pf)) {
+ if (is_array($pf->getUserInfo())) {
+ foreach ($pf->getUserInfo() as $err) {
+ if (is_array($err)) {
+ $err = $err['message'];
+ }
+
+ if (!isset($options['soft'])) {
+ $this->_downloader->log(0, "Validation Error: $err");
+ }
+ }
+ }
+
+ if (!isset($options['soft'])) {
+ $this->_downloader->log(0, $pf->getMessage());
+ }
+
+ ///FIXME need to pass back some error code that we can use to match with to cancel all further operations
+ /// At least stop all deps of this package from being installed
+ $out = $saveparam ? $saveparam : $param;
+ $err = PEAR::raiseError('Download of "' . $out . '" succeeded, but it is not a valid package archive');
+ $this->_valid = false;
+ return $err;
+ }
+
+ $this->_packagefile = &$pf;
+ $this->setGroup('default'); // install the default dependency group
+ return $this->_valid = true;
+ }
+
+ return $this->_valid = false;
+ }
+
+ /**
+ *
+ * @param string|array pass in an array of format
+ * array(
+ * 'package' => 'pname',
+ * ['channel' => 'channame',]
+ * ['version' => 'version',]
+ * ['state' => 'state',])
+ * or a string of format [channame/]pname[-version|-state]
+ */
+ function _fromString($param)
+ {
+ $options = $this->_downloader->getOptions();
+ $channel = $this->_config->get('default_channel');
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ $pname = $this->_registry->parsePackageName($param, $channel);
+ PEAR::popErrorHandling();
+ if (PEAR::isError($pname)) {
+ if ($pname->getCode() == 'invalid') {
+ $this->_valid = false;
+ return false;
+ }
+
+ if ($pname->getCode() == 'channel') {
+ $parsed = $pname->getUserInfo();
+ if ($this->_downloader->discover($parsed['channel'])) {
+ if ($this->_config->get('auto_discover')) {
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ $pname = $this->_registry->parsePackageName($param, $channel);
+ PEAR::popErrorHandling();
+ } else {
+ if (!isset($options['soft'])) {
+ $this->_downloader->log(0, 'Channel "' . $parsed['channel'] .
+ '" is not initialized, use ' .
+ '"pear channel-discover ' . $parsed['channel'] . '" to initialize' .
+ 'or pear config-set auto_discover 1');
+ }
+ }
+ }
+
+ if (PEAR::isError($pname)) {
+ if (!isset($options['soft'])) {
+ $this->_downloader->log(0, $pname->getMessage());
+ }
+
+ if (is_array($param)) {
+ $param = $this->_registry->parsedPackageNameToString($param);
+ }
+
+ $err = PEAR::raiseError('invalid package name/package file "' . $param . '"');
+ $this->_valid = false;
+ return $err;
+ }
+ } else {
+ if (!isset($options['soft'])) {
+ $this->_downloader->log(0, $pname->getMessage());
+ }
+
+ $err = PEAR::raiseError('invalid package name/package file "' . $param . '"');
+ $this->_valid = false;
+ return $err;
+ }
+ }
+
+ if (!isset($this->_type)) {
+ $this->_type = 'rest';
+ }
+
+ $this->_parsedname = $pname;
+ $this->_explicitState = isset($pname['state']) ? $pname['state'] : false;
+ $this->_explicitGroup = isset($pname['group']) ? true : false;
+
+ $info = $this->_downloader->_getPackageDownloadUrl($pname);
+ if (PEAR::isError($info)) {
+ if ($info->getCode() != -976 && $pname['channel'] == 'pear.php.net') {
+ // try pecl
+ $pname['channel'] = 'pecl.php.net';
+ if ($test = $this->_downloader->_getPackageDownloadUrl($pname)) {
+ if (!PEAR::isError($test)) {
+ $info = PEAR::raiseError($info->getMessage() . ' - package ' .
+ $this->_registry->parsedPackageNameToString($pname, true) .
+ ' can be installed with "pecl install ' . $pname['package'] .
+ '"');
+ } else {
+ $pname['channel'] = 'pear.php.net';
+ }
+ } else {
+ $pname['channel'] = 'pear.php.net';
+ }
+ }
+
+ return $info;
+ }
+
+ $this->_rawpackagefile = $info['raw'];
+ $ret = $this->_analyzeDownloadURL($info, $param, $pname);
+ if (PEAR::isError($ret)) {
+ return $ret;
+ }
+
+ if ($ret) {
+ $this->_downloadURL = $ret;
+ return $this->_valid = (bool) $ret;
+ }
+ }
+
+ /**
+ * @param array output of package.getDownloadURL
+ * @param string|array|object information for detecting packages to be downloaded, and
+ * for errors
+ * @param array name information of the package
+ * @param array|null packages to be downloaded
+ * @param bool is this an optional dependency?
+ * @param bool is this any kind of dependency?
+ * @access private
+ */
+ function _analyzeDownloadURL($info, $param, $pname, $params = null, $optional = false,
+ $isdependency = false)
+ {
+ if (!is_string($param) && PEAR_Downloader_Package::willDownload($param, $params)) {
+ return false;
+ }
+
+ if ($info === false) {
+ $saveparam = !is_string($param) ? ", cannot download \"$param\"" : '';
+
+ // no releases exist
+ return PEAR::raiseError('No releases for package "' .
+ $this->_registry->parsedPackageNameToString($pname, true) . '" exist' . $saveparam);
+ }
+
+ if (strtolower($info['info']->getChannel()) != strtolower($pname['channel'])) {
+ $err = false;
+ if ($pname['channel'] == 'pecl.php.net') {
+ if ($info['info']->getChannel() != 'pear.php.net') {
+ $err = true;
+ }
+ } elseif ($info['info']->getChannel() == 'pecl.php.net') {
+ if ($pname['channel'] != 'pear.php.net') {
+ $err = true;
+ }
+ } else {
+ $err = true;
+ }
+
+ if ($err) {
+ return PEAR::raiseError('SECURITY ERROR: package in channel "' . $pname['channel'] .
+ '" retrieved another channel\'s name for download! ("' .
+ $info['info']->getChannel() . '")');
+ }
+ }
+
+ $preferred_state = $this->_config->get('preferred_state');
+ if (!isset($info['url'])) {
+ $package_version = $this->_registry->packageInfo($info['info']->getPackage(),
+ 'version', $info['info']->getChannel());
+ if ($this->isInstalled($info)) {
+ if ($isdependency && version_compare($info['version'], $package_version, '<=')) {
+ // ignore bogus errors of "failed to download dependency"
+ // if it is already installed and the one that would be
+ // downloaded is older or the same version (Bug #7219)
+ return false;
+ }
+ }
+
+ if ($info['version'] === $package_version) {
+ if (!isset($options['soft'])) {
+ $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] .
+ '/' . $pname['package'] . '-' . $package_version. ', additionally the suggested version' .
+ ' (' . $package_version . ') is the same as the locally installed one.');
+ }
+
+ return false;
+ }
+
+ if (version_compare($info['version'], $package_version, '<=')) {
+ if (!isset($options['soft'])) {
+ $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] .
+ '/' . $pname['package'] . '-' . $package_version . ', additionally the suggested version' .
+ ' (' . $info['version'] . ') is a lower version than the locally installed one (' . $package_version . ').');
+ }
+
+ return false;
+ }
+
+ $instead = ', will instead download version ' . $info['version'] .
+ ', stability "' . $info['info']->getState() . '"';
+ // releases exist, but we failed to get any
+ if (isset($this->_downloader->_options['force'])) {
+ if (isset($pname['version'])) {
+ $vs = ', version "' . $pname['version'] . '"';
+ } elseif (isset($pname['state'])) {
+ $vs = ', stability "' . $pname['state'] . '"';
+ } elseif ($param == 'dependency') {
+ if (!class_exists('PEAR_Common')) {
+ require_once 'PEAR/Common.php';
+ }
+
+ if (!in_array($info['info']->getState(),
+ PEAR_Common::betterStates($preferred_state, true))) {
+ if ($optional) {
+ // don't spit out confusing error message
+ return $this->_downloader->_getPackageDownloadUrl(
+ array('package' => $pname['package'],
+ 'channel' => $pname['channel'],
+ 'version' => $info['version']));
+ }
+ $vs = ' within preferred state "' . $preferred_state .
+ '"';
+ } else {
+ if (!class_exists('PEAR_Dependency2')) {
+ require_once 'PEAR/Dependency2.php';
+ }
+
+ if ($optional) {
+ // don't spit out confusing error message
+ return $this->_downloader->_getPackageDownloadUrl(
+ array('package' => $pname['package'],
+ 'channel' => $pname['channel'],
+ 'version' => $info['version']));
+ }
+ $vs = PEAR_Dependency2::_getExtraString($pname);
+ $instead = '';
+ }
+ } else {
+ $vs = ' within preferred state "' . $preferred_state . '"';
+ }
+
+ if (!isset($options['soft'])) {
+ $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] .
+ '/' . $pname['package'] . $vs . $instead);
+ }
+
+ // download the latest release
+ return $this->_downloader->_getPackageDownloadUrl(
+ array('package' => $pname['package'],
+ 'channel' => $pname['channel'],
+ 'version' => $info['version']));
+ } else {
+ if (isset($info['php']) && $info['php']) {
+ $err = PEAR::raiseError('Failed to download ' .
+ $this->_registry->parsedPackageNameToString(
+ array('channel' => $pname['channel'],
+ 'package' => $pname['package']),
+ true) .
+ ', latest release is version ' . $info['php']['v'] .
+ ', but it requires PHP version "' .
+ $info['php']['m'] . '", use "' .
+ $this->_registry->parsedPackageNameToString(
+ array('channel' => $pname['channel'], 'package' => $pname['package'],
+ 'version' => $info['php']['v'])) . '" to install',
+ PEAR_DOWNLOADER_PACKAGE_PHPVERSION);
+ return $err;
+ }
+
+ // construct helpful error message
+ if (isset($pname['version'])) {
+ $vs = ', version "' . $pname['version'] . '"';
+ } elseif (isset($pname['state'])) {
+ $vs = ', stability "' . $pname['state'] . '"';
+ } elseif ($param == 'dependency') {
+ if (!class_exists('PEAR_Common')) {
+ require_once 'PEAR/Common.php';
+ }
+
+ if (!in_array($info['info']->getState(),
+ PEAR_Common::betterStates($preferred_state, true))) {
+ if ($optional) {
+ // don't spit out confusing error message, and don't die on
+ // optional dep failure!
+ return $this->_downloader->_getPackageDownloadUrl(
+ array('package' => $pname['package'],
+ 'channel' => $pname['channel'],
+ 'version' => $info['version']));
+ }
+ $vs = ' within preferred state "' . $preferred_state . '"';
+ } else {
+ if (!class_exists('PEAR_Dependency2')) {
+ require_once 'PEAR/Dependency2.php';
+ }
+
+ if ($optional) {
+ // don't spit out confusing error message, and don't die on
+ // optional dep failure!
+ return $this->_downloader->_getPackageDownloadUrl(
+ array('package' => $pname['package'],
+ 'channel' => $pname['channel'],
+ 'version' => $info['version']));
+ }
+ $vs = PEAR_Dependency2::_getExtraString($pname);
+ }
+ } else {
+ $vs = ' within preferred state "' . $this->_downloader->config->get('preferred_state') . '"';
+ }
+
+ $options = $this->_downloader->getOptions();
+ // this is only set by the "download-all" command
+ if (isset($options['ignorepreferred_state'])) {
+ $err = PEAR::raiseError(
+ 'Failed to download ' . $this->_registry->parsedPackageNameToString(
+ array('channel' => $pname['channel'], 'package' => $pname['package']),
+ true)
+ . $vs .
+ ', latest release is version ' . $info['version'] .
+ ', stability "' . $info['info']->getState() . '", use "' .
+ $this->_registry->parsedPackageNameToString(
+ array('channel' => $pname['channel'], 'package' => $pname['package'],
+ 'version' => $info['version'])) . '" to install',
+ PEAR_DOWNLOADER_PACKAGE_STATE);
+ return $err;
+ }
+
+ // Checks if the user has a package installed already and checks the release against
+ // the state against the installed package, this allows upgrades for packages
+ // with lower stability than the preferred_state
+ $stability = $this->_registry->packageInfo($pname['package'], 'stability', $pname['channel']);
+ if (!$this->isInstalled($info)
+ || !in_array($info['info']->getState(), PEAR_Common::betterStates($stability['release'], true))
+ ) {
+ $err = PEAR::raiseError(
+ 'Failed to download ' . $this->_registry->parsedPackageNameToString(
+ array('channel' => $pname['channel'], 'package' => $pname['package']),
+ true)
+ . $vs .
+ ', latest release is version ' . $info['version'] .
+ ', stability "' . $info['info']->getState() . '", use "' .
+ $this->_registry->parsedPackageNameToString(
+ array('channel' => $pname['channel'], 'package' => $pname['package'],
+ 'version' => $info['version'])) . '" to install');
+ return $err;
+ }
+ }
+ }
+
+ if (isset($info['deprecated']) && $info['deprecated']) {
+ $this->_downloader->log(0,
+ 'WARNING: "' .
+ $this->_registry->parsedPackageNameToString(
+ array('channel' => $info['info']->getChannel(),
+ 'package' => $info['info']->getPackage()), true) .
+ '" is deprecated in favor of "' .
+ $this->_registry->parsedPackageNameToString($info['deprecated'], true) .
+ '"');
+ }
+
+ return $info;
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/ErrorStack.php b/vendor/pear-pear.php.net/PEAR/PEAR/ErrorStack.php
new file mode 100644
index 000000000..b4412744a
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/ErrorStack.php
@@ -0,0 +1,979 @@
+
+ * @copyright 2004-2008 Greg Beaver
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR_ErrorStack
+ */
+
+/**
+ * Singleton storage
+ *
+ * Format:
+ *
+ * array(
+ * 'package1' => PEAR_ErrorStack object,
+ * 'package2' => PEAR_ErrorStack object,
+ * ...
+ * )
+ *
+ * @access private
+ * @global array $GLOBALS['_PEAR_ERRORSTACK_SINGLETON']
+ */
+$GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] = array();
+
+/**
+ * Global error callback (default)
+ *
+ * This is only used if set to non-false. * is the default callback for
+ * all packages, whereas specific packages may set a default callback
+ * for all instances, regardless of whether they are a singleton or not.
+ *
+ * To exclude non-singletons, only set the local callback for the singleton
+ * @see PEAR_ErrorStack::setDefaultCallback()
+ * @access private
+ * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']
+ */
+$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] = array(
+ '*' => false,
+);
+
+/**
+ * Global Log object (default)
+ *
+ * This is only used if set to non-false. Use to set a default log object for
+ * all stacks, regardless of instantiation order or location
+ * @see PEAR_ErrorStack::setDefaultLogger()
+ * @access private
+ * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']
+ */
+$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = false;
+
+/**
+ * Global Overriding Callback
+ *
+ * This callback will override any error callbacks that specific loggers have set.
+ * Use with EXTREME caution
+ * @see PEAR_ErrorStack::staticPushCallback()
+ * @access private
+ * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']
+ */
+$GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array();
+
+/**#@+
+ * One of four possible return values from the error Callback
+ * @see PEAR_ErrorStack::_errorCallback()
+ */
+/**
+ * If this is returned, then the error will be both pushed onto the stack
+ * and logged.
+ */
+define('PEAR_ERRORSTACK_PUSHANDLOG', 1);
+/**
+ * If this is returned, then the error will only be pushed onto the stack,
+ * and not logged.
+ */
+define('PEAR_ERRORSTACK_PUSH', 2);
+/**
+ * If this is returned, then the error will only be logged, but not pushed
+ * onto the error stack.
+ */
+define('PEAR_ERRORSTACK_LOG', 3);
+/**
+ * If this is returned, then the error is completely ignored.
+ */
+define('PEAR_ERRORSTACK_IGNORE', 4);
+/**
+ * If this is returned, then the error is logged and die() is called.
+ */
+define('PEAR_ERRORSTACK_DIE', 5);
+/**#@-*/
+
+/**
+ * Error code for an attempt to instantiate a non-class as a PEAR_ErrorStack in
+ * the singleton method.
+ */
+define('PEAR_ERRORSTACK_ERR_NONCLASS', 1);
+
+/**
+ * Error code for an attempt to pass an object into {@link PEAR_ErrorStack::getMessage()}
+ * that has no __toString() method
+ */
+define('PEAR_ERRORSTACK_ERR_OBJTOSTRING', 2);
+/**
+ * Error Stack Implementation
+ *
+ * Usage:
+ *
+ * // global error stack
+ * $global_stack = &PEAR_ErrorStack::singleton('MyPackage');
+ * // local error stack
+ * $local_stack = new PEAR_ErrorStack('MyPackage');
+ *
+ * @author Greg Beaver
+ * @version 1.10.3
+ * @package PEAR_ErrorStack
+ * @category Debugging
+ * @copyright 2004-2008 Greg Beaver
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR_ErrorStack
+ */
+class PEAR_ErrorStack {
+ /**
+ * Errors are stored in the order that they are pushed on the stack.
+ * @since 0.4alpha Errors are no longer organized by error level.
+ * This renders pop() nearly unusable, and levels could be more easily
+ * handled in a callback anyway
+ * @var array
+ * @access private
+ */
+ var $_errors = array();
+
+ /**
+ * Storage of errors by level.
+ *
+ * Allows easy retrieval and deletion of only errors from a particular level
+ * @since PEAR 1.4.0dev
+ * @var array
+ * @access private
+ */
+ var $_errorsByLevel = array();
+
+ /**
+ * Package name this error stack represents
+ * @var string
+ * @access protected
+ */
+ var $_package;
+
+ /**
+ * Determines whether a PEAR_Error is thrown upon every error addition
+ * @var boolean
+ * @access private
+ */
+ var $_compat = false;
+
+ /**
+ * If set to a valid callback, this will be used to generate the error
+ * message from the error code, otherwise the message passed in will be
+ * used
+ * @var false|string|array
+ * @access private
+ */
+ var $_msgCallback = false;
+
+ /**
+ * If set to a valid callback, this will be used to generate the error
+ * context for an error. For PHP-related errors, this will be a file
+ * and line number as retrieved from debug_backtrace(), but can be
+ * customized for other purposes. The error might actually be in a separate
+ * configuration file, or in a database query.
+ * @var false|string|array
+ * @access protected
+ */
+ var $_contextCallback = false;
+
+ /**
+ * If set to a valid callback, this will be called every time an error
+ * is pushed onto the stack. The return value will be used to determine
+ * whether to allow an error to be pushed or logged.
+ *
+ * The return value must be one an PEAR_ERRORSTACK_* constant
+ * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
+ * @var false|string|array
+ * @access protected
+ */
+ var $_errorCallback = array();
+
+ /**
+ * PEAR::Log object for logging errors
+ * @var false|Log
+ * @access protected
+ */
+ var $_logger = false;
+
+ /**
+ * Error messages - designed to be overridden
+ * @var array
+ * @abstract
+ */
+ var $_errorMsgs = array();
+
+ /**
+ * Set up a new error stack
+ *
+ * @param string $package name of the package this error stack represents
+ * @param callback $msgCallback callback used for error message generation
+ * @param callback $contextCallback callback used for context generation,
+ * defaults to {@link getFileLine()}
+ * @param boolean $throwPEAR_Error
+ */
+ function __construct($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
+ *
+ * @return PEAR_ErrorStack
+ */
+ public static function &singleton(
+ $package, $msgCallback = false, $contextCallback = false,
+ $throwPEAR_Error = false, $stackClass = 'PEAR_ErrorStack'
+ ) {
+ if (isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
+ return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package];
+ }
+ if (!class_exists($stackClass)) {
+ if (function_exists('debug_backtrace')) {
+ $trace = debug_backtrace();
+ }
+ PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_NONCLASS,
+ 'exception', array('stackclass' => $stackClass),
+ 'stack class "%stackclass%" is not a valid class name (should be like PEAR_ErrorStack)',
+ false, $trace);
+ }
+ $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package] =
+ new $stackClass($package, $msgCallback, $contextCallback, $throwPEAR_Error);
+
+ return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package];
+ }
+
+ /**
+ * Internal error handler for PEAR_ErrorStack class
+ *
+ * Dies if the error is an exception (and would have died anyway)
+ * @access private
+ */
+ function _handleError($err)
+ {
+ if ($err['level'] == 'exception') {
+ $message = $err['message'];
+ if (isset($_SERVER['REQUEST_URI'])) {
+ echo '
';
+ } else {
+ echo "\n";
+ }
+ var_dump($err['context']);
+ die($message);
+ }
+ }
+
+ /**
+ * Set up a PEAR::Log object for all error stacks that don't have one
+ * @param Log $log
+ */
+ public 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
+ */
+ public 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
+ */
+ public static function staticPushCallback($cb)
+ {
+ array_push($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'], $cb);
+ }
+
+ /**
+ * Remove a temporary overriding error callback
+ * @see staticPushCallback()
+ * @return array|string|false
+ */
+ public static function staticPopCallback()
+ {
+ $ret = array_pop($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK']);
+ if (!is_array($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'])) {
+ $GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array();
+ }
+ return $ret;
+ }
+
+ /**
+ * Add an error to the stack
+ *
+ * If the message generator exists, it is called with 2 parameters.
+ * - the current Error Stack object
+ * - an array that is in the same format as an error. Available indices
+ * are 'code', 'package', 'time', 'params', 'level', and 'context'
+ *
+ * Next, if the error should contain context information, this is
+ * handled by the context grabbing method.
+ * Finally, the error is pushed onto the proper error stack
+ * @param int $code Package-specific error code
+ * @param string $level Error level. This is NOT spell-checked
+ * @param array $params associative array of error parameters
+ * @param string $msg Error message, or a portion of it if the message
+ * is to be generated
+ * @param array $repackage If this error re-packages an error pushed by
+ * another package, place the array returned from
+ * {@link pop()} in this parameter
+ * @param array $backtrace Protected parameter: use this to pass in the
+ * {@link debug_backtrace()} that should be used
+ * to find error context
+ * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also
+ * thrown. If a PEAR_Error is returned, the userinfo
+ * property is set to the following array:
+ *
+ *
+ * array(
+ * 'code' => $code,
+ * 'params' => $params,
+ * 'package' => $this->_package,
+ * 'level' => $level,
+ * 'time' => time(),
+ * 'context' => $context,
+ * 'message' => $msg,
+ * //['repackage' => $err] repackaged error array/Exception class
+ * );
+ *
+ *
+ * Normally, the previous array is returned.
+ */
+ function push($code, $level = 'error', $params = array(), $msg = false,
+ $repackage = false, $backtrace = false)
+ {
+ $context = false;
+ // grab error context
+ if ($this->_contextCallback) {
+ if (!$backtrace) {
+ $backtrace = debug_backtrace();
+ }
+ $context = call_user_func($this->_contextCallback, $code, $params, $backtrace);
+ }
+
+ // save error
+ $time = explode(' ', microtime());
+ $time = $time[1] + $time[0];
+ $err = array(
+ 'code' => $code,
+ 'params' => $params,
+ 'package' => $this->_package,
+ 'level' => $level,
+ 'time' => $time,
+ 'context' => $context,
+ 'message' => $msg,
+ );
+
+ if ($repackage) {
+ $err['repackage'] = $repackage;
+ }
+
+ // set up the error message, if necessary
+ if ($this->_msgCallback) {
+ $msg = call_user_func_array($this->_msgCallback,
+ array(&$this, $err));
+ $err['message'] = $msg;
+ }
+ $push = $log = true;
+ $die = false;
+ // try the overriding callback first
+ $callback = $this->staticPopCallback();
+ if ($callback) {
+ $this->staticPushCallback($callback);
+ }
+ if (!is_callable($callback)) {
+ // try the local callback next
+ $callback = $this->popCallback();
+ if (is_callable($callback)) {
+ $this->pushCallback($callback);
+ } else {
+ // try the default callback
+ $callback = isset($GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package]) ?
+ $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package] :
+ $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']['*'];
+ }
+ }
+ if (is_callable($callback)) {
+ switch(call_user_func($callback, $err)){
+ case PEAR_ERRORSTACK_IGNORE:
+ return $err;
+ break;
+ case PEAR_ERRORSTACK_PUSH:
+ $log = false;
+ break;
+ case PEAR_ERRORSTACK_LOG:
+ $push = false;
+ break;
+ case PEAR_ERRORSTACK_DIE:
+ $die = true;
+ break;
+ // anything else returned has the same effect as pushandlog
+ }
+ }
+ if ($push) {
+ array_unshift($this->_errors, $err);
+ if (!isset($this->_errorsByLevel[$err['level']])) {
+ $this->_errorsByLevel[$err['level']] = array();
+ }
+ $this->_errorsByLevel[$err['level']][] = &$this->_errors[0];
+ }
+ if ($log) {
+ if ($this->_logger || $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']) {
+ $this->_log($err);
+ }
+ }
+ if ($die) {
+ die();
+ }
+ if ($this->_compat && $push) {
+ return $this->raiseError($msg, $code, null, null, $err);
+ }
+ return $err;
+ }
+
+ /**
+ * Static version of {@link push()}
+ *
+ * @param string $package Package name this error belongs to
+ * @param int $code Package-specific error code
+ * @param string $level Error level. This is NOT spell-checked
+ * @param array $params associative array of error parameters
+ * @param string $msg Error message, or a portion of it if the message
+ * is to be generated
+ * @param array $repackage If this error re-packages an error pushed by
+ * another package, place the array returned from
+ * {@link pop()} in this parameter
+ * @param array $backtrace Protected parameter: use this to pass in the
+ * {@link debug_backtrace()} that should be used
+ * to find error context
+ * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also
+ * thrown. see docs for {@link push()}
+ */
+ public static function staticPush(
+ $package, $code, $level = 'error', $params = array(),
+ $msg = false, $repackage = false, $backtrace = false
+ ) {
+ $s = &PEAR_ErrorStack::singleton($package);
+ if ($s->_contextCallback) {
+ if (!$backtrace) {
+ if (function_exists('debug_backtrace')) {
+ $backtrace = debug_backtrace();
+ }
+ }
+ }
+ return $s->push($code, $level, $params, $msg, $repackage, $backtrace);
+ }
+
+ /**
+ * Log an error using PEAR::Log
+ * @param array $err Error array
+ * @param array $levels Error level => Log constant map
+ * @access protected
+ */
+ function _log($err)
+ {
+ if ($this->_logger) {
+ $logger = &$this->_logger;
+ } else {
+ $logger = &$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'];
+ }
+ if (is_a($logger, 'Log')) {
+ $levels = array(
+ 'exception' => PEAR_LOG_CRIT,
+ 'alert' => PEAR_LOG_ALERT,
+ 'critical' => PEAR_LOG_CRIT,
+ 'error' => PEAR_LOG_ERR,
+ 'warning' => PEAR_LOG_WARNING,
+ 'notice' => PEAR_LOG_NOTICE,
+ 'info' => PEAR_LOG_INFO,
+ 'debug' => PEAR_LOG_DEBUG);
+ if (isset($levels[$err['level']])) {
+ $level = $levels[$err['level']];
+ } else {
+ $level = PEAR_LOG_INFO;
+ }
+ $logger->log($err['message'], $level, $err);
+ } else { // support non-standard logs
+ call_user_func($logger, $err);
+ }
+ }
+
+
+ /**
+ * Pop an error off of the error stack
+ *
+ * @return false|array
+ * @since 0.4alpha it is no longer possible to specify a specific error
+ * level to return - the last error pushed will be returned, instead
+ */
+ function pop()
+ {
+ $err = @array_shift($this->_errors);
+ if (!is_null($err)) {
+ @array_pop($this->_errorsByLevel[$err['level']]);
+ if (!count($this->_errorsByLevel[$err['level']])) {
+ unset($this->_errorsByLevel[$err['level']]);
+ }
+ }
+ return $err;
+ }
+
+ /**
+ * Pop an error off of the error stack, static method
+ *
+ * @param string package name
+ * @return boolean
+ * @since PEAR1.5.0a1
+ */
+ function staticPop($package)
+ {
+ if ($package) {
+ if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
+ return false;
+ }
+ return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->pop();
+ }
+ }
+
+ /**
+ * Determine whether there are any errors on the stack
+ * @param string|array Level name. Use to determine if any errors
+ * of level (string), or levels (array) have been pushed
+ * @return boolean
+ */
+ function hasErrors($level = false)
+ {
+ if ($level) {
+ return isset($this->_errorsByLevel[$level]);
+ }
+ return count($this->_errors);
+ }
+
+ /**
+ * Retrieve all errors since last purge
+ *
+ * @param boolean set in order to empty the error stack
+ * @param string level name, to return only errors of a particular severity
+ * @return array
+ */
+ function getErrors($purge = false, $level = false)
+ {
+ if (!$purge) {
+ if ($level) {
+ if (!isset($this->_errorsByLevel[$level])) {
+ return array();
+ } else {
+ return $this->_errorsByLevel[$level];
+ }
+ } else {
+ return $this->_errors;
+ }
+ }
+ if ($level) {
+ $ret = $this->_errorsByLevel[$level];
+ foreach ($this->_errorsByLevel[$level] as $i => $unused) {
+ // entries are references to the $_errors array
+ $this->_errorsByLevel[$level][$i] = false;
+ }
+ // array_filter removes all entries === false
+ $this->_errors = array_filter($this->_errors);
+ unset($this->_errorsByLevel[$level]);
+ return $ret;
+ }
+ $ret = $this->_errors;
+ $this->_errors = array();
+ $this->_errorsByLevel = array();
+ return $ret;
+ }
+
+ /**
+ * Determine whether there are any errors on a single error stack, or on any error stack
+ *
+ * The optional parameter can be used to test the existence of any errors without the need of
+ * singleton instantiation
+ * @param string|false Package name to check for errors
+ * @param string Level name to check for a particular severity
+ * @return boolean
+ */
+ public 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
+ *
+ * @return array
+ */
+ public static 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
+ */
+ public static 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()
+ */
+ public static function getFileLine($code, $params, $backtrace = null)
+ {
+ if ($backtrace === null) {
+ return false;
+ }
+ $frame = 0;
+ $functionframe = 1;
+ if (!isset($backtrace[1])) {
+ $functionframe = 0;
+ } else {
+ while (isset($backtrace[$functionframe]['function']) &&
+ $backtrace[$functionframe]['function'] == 'eval' &&
+ isset($backtrace[$functionframe + 1])) {
+ $functionframe++;
+ }
+ }
+ if (isset($backtrace[$frame])) {
+ if (!isset($backtrace[$frame]['file'])) {
+ $frame++;
+ }
+ $funcbacktrace = $backtrace[$functionframe];
+ $filebacktrace = $backtrace[$frame];
+ $ret = array('file' => $filebacktrace['file'],
+ 'line' => $filebacktrace['line']);
+ // rearrange for eval'd code or create function errors
+ if (strpos($filebacktrace['file'], '(') &&
+ preg_match(';^(.*?)\((\d+)\) : (.*?)\\z;', $filebacktrace['file'],
+ $matches)) {
+ $ret['file'] = $matches[1];
+ $ret['line'] = $matches[2] + 0;
+ }
+ if (isset($funcbacktrace['function']) && isset($backtrace[1])) {
+ if ($funcbacktrace['function'] != 'eval') {
+ if ($funcbacktrace['function'] == '__lambda_func') {
+ $ret['function'] = 'create_function() code';
+ } else {
+ $ret['function'] = $funcbacktrace['function'];
+ }
+ }
+ }
+ if (isset($funcbacktrace['class']) && isset($backtrace[1])) {
+ $ret['class'] = $funcbacktrace['class'];
+ }
+ return $ret;
+ }
+ return false;
+ }
+
+ /**
+ * Standard error message generation callback
+ *
+ * This method may also be called by a custom error message generator
+ * to fill in template values from the params array, simply
+ * set the third parameter to the error message template string to use
+ *
+ * The special variable %__msg% is reserved: use it only to specify
+ * where a message passed in by the user should be placed in the template,
+ * like so:
+ *
+ * Error message: %msg% - internal error
+ *
+ * If the message passed like so:
+ *
+ *
+ * $stack->push(ERROR_CODE, 'error', array(), 'server error 500');
+ *
+ *
+ * The returned error message will be "Error message: server error 500 -
+ * internal error"
+ * @param PEAR_ErrorStack
+ * @param array
+ * @param string|false Pre-generated error message template
+ *
+ * @return string
+ */
+ public static function getErrorMessage(&$stack, $err, $template = false)
+ {
+ if ($template) {
+ $mainmsg = $template;
+ } else {
+ $mainmsg = $stack->getErrorMessageTemplate($err['code']);
+ }
+ $mainmsg = str_replace('%__msg%', $err['message'], $mainmsg);
+ if (is_array($err['params']) && count($err['params'])) {
+ foreach ($err['params'] as $name => $val) {
+ if (is_array($val)) {
+ // @ is needed in case $val is a multi-dimensional array
+ $val = @implode(', ', $val);
+ }
+ if (is_object($val)) {
+ if (method_exists($val, '__toString')) {
+ $val = $val->__toString();
+ } else {
+ PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_OBJTOSTRING,
+ 'warning', array('obj' => get_class($val)),
+ 'object %obj% passed into getErrorMessage, but has no __toString() method');
+ $val = 'Object';
+ }
+ }
+ $mainmsg = str_replace('%' . $name . '%', $val, $mainmsg);
+ }
+ }
+ return $mainmsg;
+ }
+
+ /**
+ * Standard Error Message Template generator from code
+ * @return string
+ */
+ function getErrorMessageTemplate($code)
+ {
+ if (!isset($this->_errorMsgs[$code])) {
+ return '%__msg%';
+ }
+ return $this->_errorMsgs[$code];
+ }
+
+ /**
+ * Set the Error Message Template array
+ *
+ * The array format must be:
+ *
+ * array(error code => 'message template',...)
+ *
+ *
+ * Error message parameters passed into {@link push()} will be used as input
+ * for the error message. If the template is 'message %foo% was %bar%', and the
+ * parameters are array('foo' => 'one', 'bar' => 'six'), the error message returned will
+ * be 'message one was six'
+ * @return string
+ */
+ function setErrorMessageTemplate($template)
+ {
+ $this->_errorMsgs = $template;
+ }
+
+
+ /**
+ * emulate PEAR::raiseError()
+ *
+ * @return PEAR_Error
+ */
+ function raiseError()
+ {
+ require_once 'PEAR.php';
+ $args = func_get_args();
+ return call_user_func_array(array('PEAR', 'raiseError'), $args);
+ }
+}
+$stack = &PEAR_ErrorStack::singleton('PEAR_ErrorStack');
+$stack->pushCallback(array('PEAR_ErrorStack', '_handleError'));
+?>
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Exception.php b/vendor/pear-pear.php.net/PEAR/PEAR/Exception.php
new file mode 100644
index 000000000..d83950b13
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Exception.php
@@ -0,0 +1,388 @@
+
+ * @author Hans Lellelid
+ * @author Bertrand Mansion
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.3.3
+ */
+
+
+/**
+ * Base PEAR_Exception Class
+ *
+ * 1) Features:
+ *
+ * - Nestable exceptions (throw new PEAR_Exception($msg, $prev_exception))
+ * - Definable triggers, shot when exceptions occur
+ * - Pretty and informative error messages
+ * - Added more context info available (like class, method or cause)
+ * - cause can be a PEAR_Exception or an array of mixed
+ * PEAR_Exceptions/PEAR_ErrorStack warnings
+ * - callbacks for specific exception classes and their children
+ *
+ * 2) Ideas:
+ *
+ * - Maybe a way to define a 'template' for the output
+ *
+ * 3) Inherited properties from PHP Exception Class:
+ *
+ * protected $message
+ * protected $code
+ * protected $line
+ * protected $file
+ * private $trace
+ *
+ * 4) Inherited methods from PHP Exception Class:
+ *
+ * __clone
+ * __construct
+ * getMessage
+ * getCode
+ * getFile
+ * getLine
+ * getTraceSafe
+ * getTraceSafeAsString
+ * __toString
+ *
+ * 5) Usage example
+ *
+ *
+ * require_once 'PEAR/Exception.php';
+ *
+ * class Test {
+ * function foo() {
+ * throw new PEAR_Exception('Error Message', ERROR_CODE);
+ * }
+ * }
+ *
+ * function myLogger($pear_exception) {
+ * echo $pear_exception->getMessage();
+ * }
+ * // each time a exception is thrown the 'myLogger' will be called
+ * // (its use is completely optional)
+ * PEAR_Exception::addObserver('myLogger');
+ * $test = new Test;
+ * try {
+ * $test->foo();
+ * } catch (PEAR_Exception $e) {
+ * print $e;
+ * }
+ *
+ *
+ * @category pear
+ * @package PEAR
+ * @author Tomas V.V.Cox
+ * @author Hans Lellelid
+ * @author Bertrand Mansion
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.3.3
+ *
+ */
+class PEAR_Exception extends Exception
+{
+ const OBSERVER_PRINT = -2;
+ const OBSERVER_TRIGGER = -4;
+ const OBSERVER_DIE = -8;
+ protected $cause;
+ private static $_observers = array();
+ private static $_uniqueid = 0;
+ private $_trace;
+
+ /**
+ * Supported signatures:
+ * - PEAR_Exception(string $message);
+ * - PEAR_Exception(string $message, int $code);
+ * - PEAR_Exception(string $message, Exception $cause);
+ * - PEAR_Exception(string $message, Exception $cause, int $code);
+ * - PEAR_Exception(string $message, PEAR_Error $cause);
+ * - PEAR_Exception(string $message, PEAR_Error $cause, int $code);
+ * - PEAR_Exception(string $message, array $causes);
+ * - PEAR_Exception(string $message, array $causes, int $code);
+ * @param string exception message
+ * @param int|Exception|PEAR_Error|array|null exception cause
+ * @param int|null exception code or null
+ */
+ public function __construct($message, $p2 = null, $p3 = null)
+ {
+ if (is_int($p2)) {
+ $code = $p2;
+ $this->cause = null;
+ } elseif (is_object($p2) || is_array($p2)) {
+ // using is_object allows both Exception and PEAR_Error
+ if (is_object($p2) && !($p2 instanceof Exception)) {
+ if (!class_exists('PEAR_Error') || !($p2 instanceof PEAR_Error)) {
+ throw new PEAR_Exception('exception cause must be Exception, ' .
+ 'array, or PEAR_Error');
+ }
+ }
+ $code = $p3;
+ if (is_array($p2) && isset($p2['message'])) {
+ // fix potential problem of passing in a single warning
+ $p2 = array($p2);
+ }
+ $this->cause = $p2;
+ } else {
+ $code = null;
+ $this->cause = null;
+ }
+ parent::__construct($message, $code);
+ $this->signal();
+ }
+
+ /**
+ * @param mixed $callback - A valid php callback, see php func is_callable()
+ * - A PEAR_Exception::OBSERVER_* constant
+ * - An array(const PEAR_Exception::OBSERVER_*,
+ * mixed $options)
+ * @param string $label The name of the observer. Use this if you want
+ * to remove it later with removeObserver()
+ */
+ public static function addObserver($callback, $label = 'default')
+ {
+ self::$_observers[$label] = $callback;
+ }
+
+ public static function removeObserver($label = 'default')
+ {
+ unset(self::$_observers[$label]);
+ }
+
+ /**
+ * @return int unique identifier for an observer
+ */
+ public static function getUniqueId()
+ {
+ return self::$_uniqueid++;
+ }
+
+ private function signal()
+ {
+ foreach (self::$_observers as $func) {
+ if (is_callable($func)) {
+ call_user_func($func, $this);
+ continue;
+ }
+ settype($func, 'array');
+ switch ($func[0]) {
+ case self::OBSERVER_PRINT :
+ $f = (isset($func[1])) ? $func[1] : '%s';
+ printf($f, $this->getMessage());
+ break;
+ case self::OBSERVER_TRIGGER :
+ $f = (isset($func[1])) ? $func[1] : E_USER_NOTICE;
+ trigger_error($this->getMessage(), $f);
+ break;
+ case self::OBSERVER_DIE :
+ $f = (isset($func[1])) ? $func[1] : '%s';
+ die(printf($f, $this->getMessage()));
+ break;
+ default:
+ trigger_error('invalid observer type', E_USER_WARNING);
+ }
+ }
+ }
+
+ /**
+ * Return specific error information that can be used for more detailed
+ * error messages or translation.
+ *
+ * This method may be overridden in child exception classes in order
+ * to add functionality not present in PEAR_Exception and is a placeholder
+ * to define API
+ *
+ * The returned array must be an associative array of parameter => value like so:
+ *
+ * array('name' => $name, 'context' => array(...))
+ *
+ * @return array
+ */
+ public function getErrorData()
+ {
+ return array();
+ }
+
+ /**
+ * Returns the exception that caused this exception to be thrown
+ * @access public
+ * @return Exception|array The context of the exception
+ */
+ public function getCause()
+ {
+ return $this->cause;
+ }
+
+ /**
+ * Function must be public to call on caused exceptions
+ * @param array
+ */
+ public function getCauseMessage(&$causes)
+ {
+ $trace = $this->getTraceSafe();
+ $cause = array('class' => get_class($this),
+ 'message' => $this->message,
+ 'file' => 'unknown',
+ 'line' => 'unknown');
+ if (isset($trace[0])) {
+ if (isset($trace[0]['file'])) {
+ $cause['file'] = $trace[0]['file'];
+ $cause['line'] = $trace[0]['line'];
+ }
+ }
+ $causes[] = $cause;
+ if ($this->cause instanceof PEAR_Exception) {
+ $this->cause->getCauseMessage($causes);
+ } elseif ($this->cause instanceof Exception) {
+ $causes[] = array('class' => get_class($this->cause),
+ 'message' => $this->cause->getMessage(),
+ 'file' => $this->cause->getFile(),
+ 'line' => $this->cause->getLine());
+ } elseif (class_exists('PEAR_Error') && $this->cause instanceof PEAR_Error) {
+ $causes[] = array('class' => get_class($this->cause),
+ 'message' => $this->cause->getMessage(),
+ 'file' => 'unknown',
+ 'line' => 'unknown');
+ } elseif (is_array($this->cause)) {
+ foreach ($this->cause as $cause) {
+ if ($cause instanceof PEAR_Exception) {
+ $cause->getCauseMessage($causes);
+ } elseif ($cause instanceof Exception) {
+ $causes[] = array('class' => get_class($cause),
+ 'message' => $cause->getMessage(),
+ 'file' => $cause->getFile(),
+ 'line' => $cause->getLine());
+ } elseif (class_exists('PEAR_Error') && $cause instanceof PEAR_Error) {
+ $causes[] = array('class' => get_class($cause),
+ 'message' => $cause->getMessage(),
+ 'file' => 'unknown',
+ 'line' => 'unknown');
+ } elseif (is_array($cause) && isset($cause['message'])) {
+ // PEAR_ErrorStack warning
+ $causes[] = array(
+ 'class' => $cause['package'],
+ 'message' => $cause['message'],
+ 'file' => isset($cause['context']['file']) ?
+ $cause['context']['file'] :
+ 'unknown',
+ 'line' => isset($cause['context']['line']) ?
+ $cause['context']['line'] :
+ 'unknown',
+ );
+ }
+ }
+ }
+ }
+
+ public function getTraceSafe()
+ {
+ if (!isset($this->_trace)) {
+ $this->_trace = $this->getTrace();
+ if (empty($this->_trace)) {
+ $backtrace = debug_backtrace();
+ $this->_trace = array($backtrace[count($backtrace)-1]);
+ }
+ }
+ return $this->_trace;
+ }
+
+ public function getErrorClass()
+ {
+ $trace = $this->getTraceSafe();
+ return $trace[0]['class'];
+ }
+
+ public function getErrorMethod()
+ {
+ $trace = $this->getTraceSafe();
+ return $trace[0]['function'];
+ }
+
+ public function __toString()
+ {
+ if (isset($_SERVER['REQUEST_URI'])) {
+ return $this->toHtml();
+ }
+ return $this->toText();
+ }
+
+ public function toHtml()
+ {
+ $trace = $this->getTraceSafe();
+ $causes = array();
+ $this->getCauseMessage($causes);
+ $html = '' . "\n";
+ foreach ($causes as $i => $cause) {
+ $html .= ''
+ . str_repeat('-', $i) . ' ' . $cause['class'] . ': '
+ . htmlspecialchars($cause['message']) . ' in ' . $cause['file'] . ' '
+ . 'on line ' . $cause['line'] . ''
+ . " |
\n";
+ }
+ $html .= 'Exception trace |
' . "\n"
+ . '# | '
+ . 'Function | '
+ . 'Location |
' . "\n";
+
+ foreach ($trace as $k => $v) {
+ $html .= '' . $k . ' | '
+ . '';
+ if (!empty($v['class'])) {
+ $html .= $v['class'] . $v['type'];
+ }
+ $html .= $v['function'];
+ $args = array();
+ if (!empty($v['args'])) {
+ foreach ($v['args'] as $arg) {
+ if (is_null($arg)) $args[] = 'null';
+ elseif (is_array($arg)) $args[] = 'Array';
+ elseif (is_object($arg)) $args[] = 'Object('.get_class($arg).')';
+ elseif (is_bool($arg)) $args[] = $arg ? 'true' : 'false';
+ elseif (is_int($arg) || is_double($arg)) $args[] = $arg;
+ else {
+ $arg = (string)$arg;
+ $str = htmlspecialchars(substr($arg, 0, 16));
+ if (strlen($arg) > 16) $str .= '…';
+ $args[] = "'" . $str . "'";
+ }
+ }
+ }
+ $html .= '(' . implode(', ',$args) . ')'
+ . ' | '
+ . '' . (isset($v['file']) ? $v['file'] : 'unknown')
+ . ':' . (isset($v['line']) ? $v['line'] : 'unknown')
+ . ' |
' . "\n";
+ }
+ $html .= '' . ($k+1) . ' | '
+ . '{main} | '
+ . ' |
' . "\n"
+ . '
';
+ 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();
+ }
+}
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Frontend.php b/vendor/pear-pear.php.net/PEAR/PEAR/Frontend.php
new file mode 100644
index 000000000..bd002c374
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Frontend.php
@@ -0,0 +1,223 @@
+
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+
+/**
+ * Include error handling
+ */
+//require_once 'PEAR.php';
+
+/**
+ * Which user interface class is being used.
+ * @var string class name
+ */
+$GLOBALS['_PEAR_FRONTEND_CLASS'] = 'PEAR_Frontend_CLI';
+
+/**
+ * Instance of $_PEAR_Command_uiclass.
+ * @var object
+ */
+$GLOBALS['_PEAR_FRONTEND_SINGLETON'] = null;
+
+/**
+ * Singleton-based frontend for PEAR user input/output
+ *
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_Frontend extends PEAR
+{
+ /**
+ * Retrieve the frontend object
+ * @return PEAR_Frontend_CLI|PEAR_Frontend_Web|PEAR_Frontend_Gtk
+ */
+ public static function &singleton($type = null)
+ {
+ if ($type === null) {
+ if (!isset($GLOBALS['_PEAR_FRONTEND_SINGLETON'])) {
+ $a = false;
+ return $a;
+ }
+ return $GLOBALS['_PEAR_FRONTEND_SINGLETON'];
+ }
+
+ $a = PEAR_Frontend::setFrontendClass($type);
+ return $a;
+ }
+
+ /**
+ * Set the frontend class that will be used by calls to {@link singleton()}
+ *
+ * Frontends are expected to conform to the PEAR naming standard of
+ * _ => DIRECTORY_SEPARATOR (PEAR_Frontend_CLI is in PEAR/Frontend/CLI.php)
+ * @param string $uiclass full class name
+ * @return PEAR_Frontend
+ */
+ public static function &setFrontendClass($uiclass)
+ {
+ if (is_object($GLOBALS['_PEAR_FRONTEND_SINGLETON']) &&
+ is_a($GLOBALS['_PEAR_FRONTEND_SINGLETON'], $uiclass)) {
+ return $GLOBALS['_PEAR_FRONTEND_SINGLETON'];
+ }
+
+ if (!class_exists($uiclass)) {
+ $file = str_replace('_', '/', $uiclass) . '.php';
+ if (PEAR_Frontend::isIncludeable($file)) {
+ include_once $file;
+ }
+ }
+
+ if (class_exists($uiclass)) {
+ $obj = new $uiclass;
+ // quick test to see if this class implements a few of the most
+ // important frontend methods
+ if (is_a($obj, 'PEAR_Frontend')) {
+ $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = &$obj;
+ $GLOBALS['_PEAR_FRONTEND_CLASS'] = $uiclass;
+ return $obj;
+ }
+
+ $err = PEAR::raiseError("not a frontend class: $uiclass");
+ return $err;
+ }
+
+ $err = PEAR::raiseError("no such class: $uiclass");
+ return $err;
+ }
+
+ /**
+ * Set the frontend class that will be used by calls to {@link singleton()}
+ *
+ * Frontends are expected to be a descendant of PEAR_Frontend
+ * @param PEAR_Frontend
+ * @return PEAR_Frontend
+ */
+ public static function &setFrontendObject($uiobject)
+ {
+ if (is_object($GLOBALS['_PEAR_FRONTEND_SINGLETON']) &&
+ is_a($GLOBALS['_PEAR_FRONTEND_SINGLETON'], get_class($uiobject))) {
+ return $GLOBALS['_PEAR_FRONTEND_SINGLETON'];
+ }
+
+ if (!is_a($uiobject, 'PEAR_Frontend')) {
+ $err = PEAR::raiseError('not a valid frontend class: (' .
+ get_class($uiobject) . ')');
+ return $err;
+ }
+
+ $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = &$uiobject;
+ $GLOBALS['_PEAR_FRONTEND_CLASS'] = get_class($uiobject);
+ return $uiobject;
+ }
+
+ /**
+ * @param string $path relative or absolute include path
+ * @return boolean
+ */
+ public static function isIncludeable($path)
+ {
+ if (file_exists($path) && is_readable($path)) {
+ return true;
+ }
+
+ $fp = @fopen($path, 'r', true);
+ if ($fp) {
+ fclose($fp);
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @param PEAR_Config
+ */
+ function setConfig(&$config)
+ {
+ }
+
+ /**
+ * This can be overridden to allow session-based temporary file management
+ *
+ * By default, all files are deleted at the end of a session. The web installer
+ * needs to be able to sustain a list over many sessions in order to support
+ * user interaction with install scripts
+ */
+ function addTempFile($file)
+ {
+ $GLOBALS['_PEAR_Common_tempfiles'][] = $file;
+ }
+
+ /**
+ * Log an action
+ *
+ * @param string $msg the message to log
+ * @param boolean $append_crlf
+ * @return boolean true
+ * @abstract
+ */
+ function log($msg, $append_crlf = true)
+ {
+ }
+
+ /**
+ * Run a post-installation script
+ *
+ * @param array $scripts array of post-install scripts
+ * @abstract
+ */
+ function runPostinstallScripts(&$scripts)
+ {
+ }
+
+ /**
+ * Display human-friendly output formatted depending on the
+ * $command parameter.
+ *
+ * This should be able to handle basic output data with no command
+ * @param mixed $data data structure containing the information to display
+ * @param string $command command from which this method was called
+ * @abstract
+ */
+ function outputData($data, $command = '_default')
+ {
+ }
+
+ /**
+ * Display a modal form dialog and return the given input
+ *
+ * A frontend that requires multiple requests to retrieve and process
+ * data must take these needs into account, and implement the request
+ * handling code.
+ * @param string $command command from which this method was called
+ * @param array $prompts associative array. keys are the input field names
+ * and values are the description
+ * @param array $types array of input field types (text, password,
+ * etc.) keys have to be the same like in $prompts
+ * @param array $defaults array of default values. again keys have
+ * to be the same like in $prompts. Do not depend
+ * on a default value being set.
+ * @return array input sent by the user
+ * @abstract
+ */
+ function userDialog($command, $prompts, $types = array(), $defaults = array())
+ {
+ }
+}
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Frontend/CLI.php b/vendor/pear-pear.php.net/PEAR/PEAR/Frontend/CLI.php
new file mode 100644
index 000000000..4e68c065a
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Frontend/CLI.php
@@ -0,0 +1,750 @@
+
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ */
+/**
+ * base class
+ */
+require_once 'PEAR/Frontend.php';
+
+/**
+ * Command-line Frontend for the PEAR Installer
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 0.1
+ */
+class PEAR_Frontend_CLI extends PEAR_Frontend
+{
+ /**
+ * What type of user interface this frontend is for.
+ * @var string
+ * @access public
+ */
+ var $type = 'CLI';
+ var $lp = ''; // line prefix
+
+ var $params = array();
+ var $term = array(
+ 'bold' => '',
+ 'normal' => '',
+ );
+
+ function __construct()
+ {
+ parent::__construct();
+ $term = getenv('TERM'); //(cox) $_ENV is empty for me in 4.1.1
+ if (function_exists('posix_isatty') && !posix_isatty(1)) {
+ // output is being redirected to a file or through a pipe
+ } elseif ($term) {
+ if (preg_match('/^(xterm|vt220|linux)/', $term)) {
+ $this->term['bold'] = sprintf("%c%c%c%c", 27, 91, 49, 109);
+ $this->term['normal'] = sprintf("%c%c%c", 27, 91, 109);
+ } elseif (preg_match('/^vt100/', $term)) {
+ $this->term['bold'] = sprintf("%c%c%c%c%c%c", 27, 91, 49, 109, 0, 0);
+ $this->term['normal'] = sprintf("%c%c%c%c%c", 27, 91, 109, 0, 0);
+ }
+ } elseif (OS_WINDOWS) {
+ // XXX add ANSI codes here
+ }
+ }
+
+ /**
+ * @param object PEAR_Error object
+ */
+ function displayError($e)
+ {
+ return $this->_displayLine($e->getMessage());
+ }
+
+ /**
+ * @param object PEAR_Error object
+ */
+ function displayFatalError($eobj)
+ {
+ $this->displayError($eobj);
+ if (class_exists('PEAR_Config')) {
+ $config = &PEAR_Config::singleton();
+ if ($config->get('verbose') > 5) {
+ if (function_exists('debug_print_backtrace')) {
+ debug_print_backtrace();
+ exit(1);
+ }
+
+ $raised = false;
+ foreach (debug_backtrace() as $i => $frame) {
+ if (!$raised) {
+ if (isset($frame['class'])
+ && strtolower($frame['class']) == 'pear'
+ && strtolower($frame['function']) == 'raiseerror'
+ ) {
+ $raised = true;
+ } else {
+ continue;
+ }
+ }
+
+ $frame['class'] = !isset($frame['class']) ? '' : $frame['class'];
+ $frame['type'] = !isset($frame['type']) ? '' : $frame['type'];
+ $frame['function'] = !isset($frame['function']) ? '' : $frame['function'];
+ $frame['line'] = !isset($frame['line']) ? '' : $frame['line'];
+ $this->_displayLine("#$i: $frame[class]$frame[type]$frame[function] $frame[line]");
+ }
+ }
+ }
+
+ exit(1);
+ }
+
+ /**
+ * Instruct the runInstallScript method to skip a paramgroup that matches the
+ * id value passed in.
+ *
+ * This method is useful for dynamically configuring which sections of a post-install script
+ * will be run based on the user's setup, which is very useful for making flexible
+ * post-install scripts without losing the cross-Frontend ability to retrieve user input
+ * @param string
+ */
+ function skipParamgroup($id)
+ {
+ $this->_skipSections[$id] = true;
+ }
+
+ function runPostinstallScripts(&$scripts)
+ {
+ foreach ($scripts as $i => $script) {
+ $this->runInstallScript($scripts[$i]->_params, $scripts[$i]->_obj);
+ }
+ }
+
+ /**
+ * @param array $xml contents of postinstallscript tag
+ * @param object $script post-installation script
+ * @param string install|upgrade
+ */
+ function runInstallScript($xml, &$script)
+ {
+ $this->_skipSections = array();
+ if (!is_array($xml) || !isset($xml['paramgroup'])) {
+ $script->run(array(), '_default');
+ return;
+ }
+
+ $completedPhases = array();
+ if (!isset($xml['paramgroup'][0])) {
+ $xml['paramgroup'] = array($xml['paramgroup']);
+ }
+
+ foreach ($xml['paramgroup'] as $group) {
+ if (isset($this->_skipSections[$group['id']])) {
+ // the post-install script chose to skip this section dynamically
+ continue;
+ }
+
+ if (isset($group['name'])) {
+ $paramname = explode('::', $group['name']);
+ if ($lastgroup['id'] != $paramname[0]) {
+ continue;
+ }
+
+ $group['name'] = $paramname[1];
+ if (!isset($answers)) {
+ return;
+ }
+
+ if (isset($answers[$group['name']])) {
+ switch ($group['conditiontype']) {
+ case '=' :
+ if ($answers[$group['name']] != $group['value']) {
+ continue 2;
+ }
+ break;
+ case '!=' :
+ if ($answers[$group['name']] == $group['value']) {
+ continue 2;
+ }
+ break;
+ case 'preg_match' :
+ if (!@preg_match('/' . $group['value'] . '/',
+ $answers[$group['name']])) {
+ continue 2;
+ }
+ break;
+ default :
+ return;
+ }
+ }
+ }
+
+ $lastgroup = $group;
+ if (isset($group['instructions'])) {
+ $this->_display($group['instructions']);
+ }
+
+ if (!isset($group['param'][0])) {
+ $group['param'] = array($group['param']);
+ }
+
+ if (isset($group['param'])) {
+ if (method_exists($script, 'postProcessPrompts')) {
+ $prompts = $script->postProcessPrompts($group['param'], $group['id']);
+ if (!is_array($prompts) || count($prompts) != count($group['param'])) {
+ $this->outputData('postinstall', 'Error: post-install script did not ' .
+ 'return proper post-processed prompts');
+ $prompts = $group['param'];
+ } else {
+ foreach ($prompts as $i => $var) {
+ if (!is_array($var) || !isset($var['prompt']) ||
+ !isset($var['name']) ||
+ ($var['name'] != $group['param'][$i]['name']) ||
+ ($var['type'] != $group['param'][$i]['type'])
+ ) {
+ $this->outputData('postinstall', 'Error: post-install script ' .
+ 'modified the variables or prompts, severe security risk. ' .
+ 'Will instead use the defaults from the package.xml');
+ $prompts = $group['param'];
+ }
+ }
+ }
+
+ $answers = $this->confirmDialog($prompts);
+ } else {
+ $answers = $this->confirmDialog($group['param']);
+ }
+ }
+
+ if ((isset($answers) && $answers) || !isset($group['param'])) {
+ if (!isset($answers)) {
+ $answers = array();
+ }
+
+ array_unshift($completedPhases, $group['id']);
+ if (!$script->run($answers, $group['id'])) {
+ $script->run($completedPhases, '_undoOnError');
+ return;
+ }
+ } else {
+ $script->run($completedPhases, '_undoOnError');
+ return;
+ }
+ }
+ }
+
+ /**
+ * Ask for user input, confirm the answers and continue until the user is satisfied
+ * @param array an array of arrays, format array('name' => 'paramname', 'prompt' =>
+ * 'text to display', 'type' => 'string'[, default => 'default value'])
+ * @return array
+ */
+ function confirmDialog($params)
+ {
+ $answers = $prompts = $types = array();
+ foreach ($params as $param) {
+ $prompts[$param['name']] = $param['prompt'];
+ $types[$param['name']] = $param['type'];
+ $answers[$param['name']] = isset($param['default']) ? $param['default'] : '';
+ }
+
+ $tried = false;
+ do {
+ if ($tried) {
+ $i = 1;
+ foreach ($answers as $var => $value) {
+ if (!strlen($value)) {
+ echo $this->bold("* Enter an answer for #" . $i . ": ({$prompts[$var]})\n");
+ }
+ $i++;
+ }
+ }
+
+ $answers = $this->userDialog('', $prompts, $types, $answers);
+ $tried = true;
+ } while (is_array($answers) && count(array_filter($answers)) != count($prompts));
+
+ return $answers;
+ }
+
+ function userDialog($command, $prompts, $types = array(), $defaults = array(), $screensize = 20)
+ {
+ if (!is_array($prompts)) {
+ return array();
+ }
+
+ $testprompts = array_keys($prompts);
+ $result = $defaults;
+
+ reset($prompts);
+ if (count($prompts) === 1) {
+ foreach ($prompts as $key => $prompt) {
+ $type = $types[$key];
+ $default = @$defaults[$key];
+ print "$prompt ";
+ if ($default) {
+ print "[$default] ";
+ }
+ print ": ";
+
+ $line = fgets(STDIN, 2048);
+ $result[$key] = ($default && trim($line) == '') ? $default : trim($line);
+ }
+
+ return $result;
+ }
+
+ $first_run = true;
+ while (true) {
+ $descLength = max(array_map('strlen', $prompts));
+ $descFormat = "%-{$descLength}s";
+ $last = count($prompts);
+
+ $i = 0;
+ foreach ($prompts as $n => $var) {
+ $res = isset($result[$n]) ? $result[$n] : null;
+ printf("%2d. $descFormat : %s\n", ++$i, $prompts[$n], $res);
+ }
+ print "\n1-$last, 'all', 'abort', or Enter to continue: ";
+
+ $tmp = trim(fgets(STDIN, 1024));
+ if (empty($tmp)) {
+ break;
+ }
+
+ if ($tmp == 'abort') {
+ return false;
+ }
+
+ if (isset($testprompts[(int)$tmp - 1])) {
+ $var = $testprompts[(int)$tmp - 1];
+ $desc = $prompts[$var];
+ $current = @$result[$var];
+ print "$desc [$current] : ";
+ $tmp = trim(fgets(STDIN, 1024));
+ if ($tmp !== '') {
+ $result[$var] = $tmp;
+ }
+ } elseif ($tmp == 'all') {
+ foreach ($prompts as $var => $desc) {
+ $current = $result[$var];
+ print "$desc [$current] : ";
+ $tmp = trim(fgets(STDIN, 1024));
+ if (trim($tmp) !== '') {
+ $result[$var] = trim($tmp);
+ }
+ }
+ }
+
+ $first_run = false;
+ }
+
+ return $result;
+ }
+
+ function userConfirm($prompt, $default = 'yes')
+ {
+ trigger_error("PEAR_Frontend_CLI::userConfirm not yet converted", E_USER_ERROR);
+ static $positives = array('y', 'yes', 'on', '1');
+ static $negatives = array('n', 'no', 'off', '0');
+ print "$this->lp$prompt [$default] : ";
+ $fp = fopen("php://stdin", "r");
+ $line = fgets($fp, 2048);
+ fclose($fp);
+ $answer = strtolower(trim($line));
+ if (empty($answer)) {
+ $answer = $default;
+ }
+ if (in_array($answer, $positives)) {
+ return true;
+ }
+ if (in_array($answer, $negatives)) {
+ return false;
+ }
+ if (in_array($default, $positives)) {
+ return true;
+ }
+ return false;
+ }
+
+ function outputData($data, $command = '_default')
+ {
+ switch ($command) {
+ case 'channel-info':
+ foreach ($data as $type => $section) {
+ if ($type == 'main') {
+ $section['data'] = array_values($section['data']);
+ }
+
+ $this->outputData($section);
+ }
+ break;
+ case 'install':
+ case 'upgrade':
+ case 'upgrade-all':
+ if (is_array($data) && isset($data['release_warnings'])) {
+ $this->_displayLine('');
+ $this->_startTable(array(
+ 'border' => false,
+ 'caption' => 'Release Warnings'
+ ));
+ $this->_tableRow(array($data['release_warnings']), null, array(1 => array('wrap' => 55)));
+ $this->_endTable();
+ $this->_displayLine('');
+ }
+
+ $this->_displayLine(is_array($data) ? $data['data'] : $data);
+ break;
+ case 'search':
+ $this->_startTable($data);
+ if (isset($data['headline']) && is_array($data['headline'])) {
+ $this->_tableRow($data['headline'], array('bold' => true), array(1 => array('wrap' => 55)));
+ }
+
+ $packages = array();
+ foreach($data['data'] as $category) {
+ foreach($category as $name => $pkg) {
+ $packages[$pkg[0]] = $pkg;
+ }
+ }
+
+ $p = array_keys($packages);
+ natcasesort($p);
+ foreach ($p as $name) {
+ $this->_tableRow($packages[$name], null, array(1 => array('wrap' => 55)));
+ }
+
+ $this->_endTable();
+ break;
+ case 'list-all':
+ if (!isset($data['data'])) {
+ $this->_displayLine('No packages in channel');
+ break;
+ }
+
+ $this->_startTable($data);
+ if (isset($data['headline']) && is_array($data['headline'])) {
+ $this->_tableRow($data['headline'], array('bold' => true), array(1 => array('wrap' => 55)));
+ }
+
+ $packages = array();
+ foreach($data['data'] as $category) {
+ foreach($category as $name => $pkg) {
+ $packages[$pkg[0]] = $pkg;
+ }
+ }
+
+ $p = array_keys($packages);
+ natcasesort($p);
+ foreach ($p as $name) {
+ $pkg = $packages[$name];
+ unset($pkg[4], $pkg[5]);
+ $this->_tableRow($pkg, null, array(1 => array('wrap' => 55)));
+ }
+
+ $this->_endTable();
+ break;
+ case 'config-show':
+ $data['border'] = false;
+ $opts = array(
+ 0 => array('wrap' => 30),
+ 1 => array('wrap' => 20),
+ 2 => array('wrap' => 35)
+ );
+
+ $this->_startTable($data);
+ if (isset($data['headline']) && is_array($data['headline'])) {
+ $this->_tableRow($data['headline'], array('bold' => true), $opts);
+ }
+
+ foreach ($data['data'] as $group) {
+ foreach ($group as $value) {
+ if ($value[2] == '') {
+ $value[2] = "";
+ }
+
+ $this->_tableRow($value, null, $opts);
+ }
+ }
+
+ $this->_endTable();
+ break;
+ case 'remote-info':
+ $d = $data;
+ $data = array(
+ 'caption' => 'Package details:',
+ 'border' => false,
+ 'data' => array(
+ array("Latest", $data['stable']),
+ array("Installed", $data['installed']),
+ array("Package", $data['name']),
+ array("License", $data['license']),
+ array("Category", $data['category']),
+ array("Summary", $data['summary']),
+ array("Description", $data['description']),
+ ),
+ );
+
+ if (isset($d['deprecated']) && $d['deprecated']) {
+ $conf = &PEAR_Config::singleton();
+ $reg = $conf->getRegistry();
+ $name = $reg->parsedPackageNameToString($d['deprecated'], true);
+ $data['data'][] = array('Deprecated! use', $name);
+ }
+ default: {
+ if (is_array($data)) {
+ $this->_startTable($data);
+ $count = count($data['data'][0]);
+ if ($count == 2) {
+ $opts = array(0 => array('wrap' => 25),
+ 1 => array('wrap' => 48)
+ );
+ } elseif ($count == 3) {
+ $opts = array(0 => array('wrap' => 30),
+ 1 => array('wrap' => 20),
+ 2 => array('wrap' => 35)
+ );
+ } else {
+ $opts = null;
+ }
+ if (isset($data['headline']) && is_array($data['headline'])) {
+ $this->_tableRow($data['headline'],
+ array('bold' => true),
+ $opts);
+ }
+
+ if (is_array($data['data'])) {
+ foreach($data['data'] as $row) {
+ $this->_tableRow($row, null, $opts);
+ }
+ } else {
+ $this->_tableRow(array($data['data']), null, $opts);
+ }
+ $this->_endTable();
+ } else {
+ $this->_displayLine($data);
+ }
+ }
+ }
+ }
+
+ function log($text, $append_crlf = true)
+ {
+ if ($append_crlf) {
+ return $this->_displayLine($text);
+ }
+
+ return $this->_display($text);
+ }
+
+ function bold($text)
+ {
+ if (empty($this->term['bold'])) {
+ return strtoupper($text);
+ }
+
+ return $this->term['bold'] . $text . $this->term['normal'];
+ }
+
+ function _displayHeading($title)
+ {
+ print $this->lp.$this->bold($title)."\n";
+ print $this->lp.str_repeat("=", strlen($title))."\n";
+ }
+
+ function _startTable($params = array())
+ {
+ $params['table_data'] = array();
+ $params['widest'] = array(); // indexed by column
+ $params['highest'] = array(); // indexed by row
+ $params['ncols'] = 0;
+ $this->params = $params;
+ }
+
+ function _tableRow($columns, $rowparams = array(), $colparams = array())
+ {
+ $highest = 1;
+ for ($i = 0; $i < count($columns); $i++) {
+ $col = &$columns[$i];
+ if (isset($colparams[$i]) && !empty($colparams[$i]['wrap'])) {
+ $col = wordwrap($col, $colparams[$i]['wrap']);
+ }
+
+ if (strpos($col, "\n") !== false) {
+ $multiline = explode("\n", $col);
+ $w = 0;
+ foreach ($multiline as $n => $line) {
+ $len = strlen($line);
+ if ($len > $w) {
+ $w = $len;
+ }
+ }
+ $lines = count($multiline);
+ } else {
+ $w = strlen($col);
+ }
+
+ if (isset($this->params['widest'][$i])) {
+ if ($w > $this->params['widest'][$i]) {
+ $this->params['widest'][$i] = $w;
+ }
+ } else {
+ $this->params['widest'][$i] = $w;
+ }
+
+ $tmp = count_chars($columns[$i], 1);
+ // handle unix, mac and windows formats
+ $lines = (isset($tmp[10]) ? $tmp[10] : (isset($tmp[13]) ? $tmp[13] : 0)) + 1;
+ if ($lines > $highest) {
+ $highest = $lines;
+ }
+ }
+
+ if (count($columns) > $this->params['ncols']) {
+ $this->params['ncols'] = count($columns);
+ }
+
+ $new_row = array(
+ 'data' => $columns,
+ 'height' => $highest,
+ 'rowparams' => $rowparams,
+ 'colparams' => $colparams,
+ );
+ $this->params['table_data'][] = $new_row;
+ }
+
+ function _endTable()
+ {
+ extract($this->params);
+ if (!empty($caption)) {
+ $this->_displayHeading($caption);
+ }
+
+ if (count($table_data) === 0) {
+ return;
+ }
+
+ if (!isset($width)) {
+ $width = $widest;
+ } else {
+ for ($i = 0; $i < $ncols; $i++) {
+ if (!isset($width[$i])) {
+ $width[$i] = $widest[$i];
+ }
+ }
+ }
+
+ $border = false;
+ if (empty($border)) {
+ $cellstart = '';
+ $cellend = ' ';
+ $rowend = '';
+ $padrowend = false;
+ $borderline = '';
+ } else {
+ $cellstart = '| ';
+ $cellend = ' ';
+ $rowend = '|';
+ $padrowend = true;
+ $borderline = '+';
+ foreach ($width as $w) {
+ $borderline .= str_repeat('-', $w + strlen($cellstart) + strlen($cellend) - 1);
+ $borderline .= '+';
+ }
+ }
+
+ if ($borderline) {
+ $this->_displayLine($borderline);
+ }
+
+ for ($i = 0; $i < count($table_data); $i++) {
+ extract($table_data[$i]);
+ if (!is_array($rowparams)) {
+ $rowparams = array();
+ }
+
+ if (!is_array($colparams)) {
+ $colparams = array();
+ }
+
+ $rowlines = array();
+ if ($height > 1) {
+ for ($c = 0; $c < count($data); $c++) {
+ $rowlines[$c] = preg_split('/(\r?\n|\r)/', $data[$c]);
+ if (count($rowlines[$c]) < $height) {
+ $rowlines[$c] = array_pad($rowlines[$c], $height, '');
+ }
+ }
+ } else {
+ for ($c = 0; $c < count($data); $c++) {
+ $rowlines[$c] = array($data[$c]);
+ }
+ }
+
+ for ($r = 0; $r < $height; $r++) {
+ $rowtext = '';
+ for ($c = 0; $c < count($data); $c++) {
+ if (isset($colparams[$c])) {
+ $attribs = array_merge($rowparams, $colparams);
+ } else {
+ $attribs = $rowparams;
+ }
+
+ $w = isset($width[$c]) ? $width[$c] : 0;
+ //$cell = $data[$c];
+ $cell = $rowlines[$c][$r];
+ $l = strlen($cell);
+ if ($l > $w) {
+ $cell = substr($cell, 0, $w);
+ }
+
+ if (isset($attribs['bold'])) {
+ $cell = $this->bold($cell);
+ }
+
+ if ($l < $w) {
+ // not using str_pad here because we may
+ // add bold escape characters to $cell
+ $cell .= str_repeat(' ', $w - $l);
+ }
+
+ $rowtext .= $cellstart . $cell . $cellend;
+ }
+
+ if (!$border) {
+ $rowtext = rtrim($rowtext);
+ }
+
+ $rowtext .= $rowend;
+ $this->_displayLine($rowtext);
+ }
+ }
+
+ if ($borderline) {
+ $this->_displayLine($borderline);
+ }
+ }
+
+ function _displayLine($text)
+ {
+ print "$this->lp$text\n";
+ }
+
+ function _display($text)
+ {
+ print $text;
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Installer.php b/vendor/pear-pear.php.net/PEAR/PEAR/Installer.php
new file mode 100644
index 000000000..acaaa7fd0
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Installer.php
@@ -0,0 +1,1794 @@
+
+ * @author Tomas V.V. Cox
+ * @author Martin Jansen
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ */
+
+/**
+ * Used for installation groups in package.xml 2.0 and platform exceptions
+ */
+require_once 'OS/Guess.php';
+require_once 'PEAR/Downloader.php';
+
+define('PEAR_INSTALLER_NOBINARY', -240);
+/**
+ * Administration class used to install PEAR packages and maintain the
+ * installed package database.
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Tomas V.V. Cox
+ * @author Martin Jansen
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 0.1
+ */
+class PEAR_Installer extends PEAR_Downloader
+{
+ // {{{ properties
+
+ /** name of the package directory, for example Foo-1.0
+ * @var string
+ */
+ var $pkgdir;
+
+ /** directory where PHP code files go
+ * @var string
+ */
+ var $phpdir;
+
+ /** directory where PHP extension files go
+ * @var string
+ */
+ var $extdir;
+
+ /** directory where documentation goes
+ * @var string
+ */
+ var $docdir;
+
+ /** installation root directory (ala PHP's INSTALL_ROOT or
+ * automake's DESTDIR
+ * @var string
+ */
+ var $installroot = '';
+
+ /** debug level
+ * @var int
+ */
+ var $debug = 1;
+
+ /** temporary directory
+ * @var string
+ */
+ var $tmpdir;
+
+ /**
+ * PEAR_Registry object used by the installer
+ * @var PEAR_Registry
+ */
+ var $registry;
+
+ /**
+ * array of PEAR_Downloader_Packages
+ * @var array
+ */
+ var $_downloadedPackages;
+
+ /** List of file transactions queued for an install/upgrade/uninstall.
+ *
+ * Format:
+ * array(
+ * 0 => array("rename => array("from-file", "to-file")),
+ * 1 => array("delete" => array("file-to-delete")),
+ * ...
+ * )
+ *
+ * @var array
+ */
+ var $file_operations = array();
+
+ // }}}
+
+ // {{{ constructor
+
+ /**
+ * PEAR_Installer constructor.
+ *
+ * @param object $ui user interface object (instance of PEAR_Frontend_*)
+ *
+ * @access public
+ */
+ function __construct(&$ui)
+ {
+ parent::__construct($ui, array(), null);
+ $this->setFrontendObject($ui);
+ $this->debug = $this->config->get('verbose');
+ }
+
+ function setOptions($options)
+ {
+ $this->_options = $options;
+ }
+
+ function setConfig(&$config)
+ {
+ $this->config = &$config;
+ $this->_registry = &$config->getRegistry();
+ }
+
+ // }}}
+
+ function _removeBackups($files)
+ {
+ foreach ($files as $path) {
+ $this->addFileOperation('removebackup', array($path));
+ }
+ }
+
+ // {{{ _deletePackageFiles()
+
+ /**
+ * Delete a package's installed files, does not remove empty directories.
+ *
+ * @param string package name
+ * @param string channel name
+ * @param bool if true, then files are backed up first
+ * @return bool TRUE on success, or a PEAR error on failure
+ * @access protected
+ */
+ function _deletePackageFiles($package, $channel = false, $backup = false)
+ {
+ if (!$channel) {
+ $channel = 'pear.php.net';
+ }
+
+ if (!strlen($package)) {
+ return $this->raiseError("No package to uninstall given");
+ }
+
+ if (strtolower($package) == 'pear' && $channel == 'pear.php.net') {
+ // to avoid race conditions, include all possible needed files
+ require_once 'PEAR/Task/Common.php';
+ require_once 'PEAR/Task/Replace.php';
+ require_once 'PEAR/Task/Unixeol.php';
+ require_once 'PEAR/Task/Windowseol.php';
+ require_once 'PEAR/PackageFile/v1.php';
+ require_once 'PEAR/PackageFile/v2.php';
+ require_once 'PEAR/PackageFile/Generator/v1.php';
+ require_once 'PEAR/PackageFile/Generator/v2.php';
+ }
+
+ $filelist = $this->_registry->packageInfo($package, 'filelist', $channel);
+ if ($filelist == null) {
+ return $this->raiseError("$channel/$package not installed");
+ }
+
+ $ret = array();
+ foreach ($filelist as $file => $props) {
+ if (empty($props['installed_as'])) {
+ continue;
+ }
+
+ $path = $props['installed_as'];
+ if ($backup) {
+ $this->addFileOperation('backup', array($path));
+ $ret[] = $path;
+ }
+
+ $this->addFileOperation('delete', array($path));
+ }
+
+ if ($backup) {
+ return $ret;
+ }
+
+ return true;
+ }
+
+ // }}}
+ // {{{ _installFile()
+
+ /**
+ * @param string filename
+ * @param array attributes from tag in package.xml
+ * @param string path to install the file in
+ * @param array options from command-line
+ * @access private
+ */
+ function _installFile($file, $atts, $tmp_path, $options)
+ {
+ // {{{ return if this file is meant for another platform
+ static $os;
+ if (!isset($this->_registry)) {
+ $this->_registry = &$this->config->getRegistry();
+ }
+
+ if (isset($atts['platform'])) {
+ if (empty($os)) {
+ $os = new OS_Guess();
+ }
+
+ if (strlen($atts['platform']) && $atts['platform']{0} == '!') {
+ $negate = true;
+ $platform = substr($atts['platform'], 1);
+ } else {
+ $negate = false;
+ $platform = $atts['platform'];
+ }
+
+ if ((bool) $os->matchSignature($platform) === $negate) {
+ $this->log(3, "skipped $file (meant for $atts[platform], we are ".$os->getSignature().")");
+ return PEAR_INSTALLER_SKIPPED;
+ }
+ }
+ // }}}
+
+ $channel = $this->pkginfo->getChannel();
+ // {{{ assemble the destination paths
+ switch ($atts['role']) {
+ case 'src':
+ case 'extsrc':
+ $this->source_files++;
+ return;
+ case 'doc':
+ case 'data':
+ case 'test':
+ $dest_dir = $this->config->get($atts['role'] . '_dir', null, $channel) .
+ DIRECTORY_SEPARATOR . $this->pkginfo->getPackage();
+ unset($atts['baseinstalldir']);
+ break;
+ case 'ext':
+ case 'php':
+ $dest_dir = $this->config->get($atts['role'] . '_dir', null, $channel);
+ break;
+ case 'script':
+ $dest_dir = $this->config->get('bin_dir', null, $channel);
+ break;
+ default:
+ return $this->raiseError("Invalid role `$atts[role]' for file $file");
+ }
+
+ $save_destdir = $dest_dir;
+ if (!empty($atts['baseinstalldir'])) {
+ $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir'];
+ }
+
+ if (dirname($file) != '.' && empty($atts['install-as'])) {
+ $dest_dir .= DIRECTORY_SEPARATOR . dirname($file);
+ }
+
+ if (empty($atts['install-as'])) {
+ $dest_file = $dest_dir . DIRECTORY_SEPARATOR . basename($file);
+ } else {
+ $dest_file = $dest_dir . DIRECTORY_SEPARATOR . $atts['install-as'];
+ }
+ $orig_file = $tmp_path . DIRECTORY_SEPARATOR . $file;
+
+ // Clean up the DIRECTORY_SEPARATOR mess
+ $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR;
+ list($dest_file, $orig_file) = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"),
+ array(DIRECTORY_SEPARATOR,
+ DIRECTORY_SEPARATOR,
+ DIRECTORY_SEPARATOR),
+ array($dest_file, $orig_file));
+ $final_dest_file = $installed_as = $dest_file;
+ if (isset($this->_options['packagingroot'])) {
+ $installedas_dest_dir = dirname($final_dest_file);
+ $installedas_dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file);
+ $final_dest_file = $this->_prependPath($final_dest_file, $this->_options['packagingroot']);
+ } else {
+ $installedas_dest_dir = dirname($final_dest_file);
+ $installedas_dest_file = $installedas_dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file);
+ }
+
+ $dest_dir = dirname($final_dest_file);
+ $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file);
+ if (preg_match('~/\.\.(/|\\z)|^\.\./~', str_replace('\\', '/', $dest_file))) {
+ return $this->raiseError("SECURITY ERROR: file $file (installed to $dest_file) contains parent directory reference ..", PEAR_INSTALLER_FAILED);
+ }
+ // }}}
+
+ if (empty($this->_options['register-only']) &&
+ (!file_exists($dest_dir) || !is_dir($dest_dir))) {
+ if (!$this->mkDirHier($dest_dir)) {
+ return $this->raiseError("failed to mkdir $dest_dir",
+ PEAR_INSTALLER_FAILED);
+ }
+ $this->log(3, "+ mkdir $dest_dir");
+ }
+
+ // pretty much nothing happens if we are only registering the install
+ if (empty($this->_options['register-only'])) {
+ if (empty($atts['replacements'])) {
+ if (!file_exists($orig_file)) {
+ return $this->raiseError("file $orig_file does not exist",
+ PEAR_INSTALLER_FAILED);
+ }
+
+ if (!@copy($orig_file, $dest_file)) {
+ return $this->raiseError("failed to write $dest_file: $php_errormsg",
+ PEAR_INSTALLER_FAILED);
+ }
+
+ $this->log(3, "+ cp $orig_file $dest_file");
+ if (isset($atts['md5sum'])) {
+ $md5sum = md5_file($dest_file);
+ }
+ } else {
+ // {{{ file with replacements
+ if (!file_exists($orig_file)) {
+ return $this->raiseError("file does not exist",
+ PEAR_INSTALLER_FAILED);
+ }
+
+ $contents = file_get_contents($orig_file);
+ if ($contents === false) {
+ $contents = '';
+ }
+
+ if (isset($atts['md5sum'])) {
+ $md5sum = md5($contents);
+ }
+
+ $subst_from = $subst_to = array();
+ foreach ($atts['replacements'] as $a) {
+ $to = '';
+ if ($a['type'] == 'php-const') {
+ if (preg_match('/^[a-z0-9_]+\\z/i', $a['to'])) {
+ eval("\$to = $a[to];");
+ } else {
+ if (!isset($options['soft'])) {
+ $this->log(0, "invalid php-const replacement: $a[to]");
+ }
+ continue;
+ }
+ } elseif ($a['type'] == 'pear-config') {
+ if ($a['to'] == 'master_server') {
+ $chan = $this->_registry->getChannel($channel);
+ if (!PEAR::isError($chan)) {
+ $to = $chan->getServer();
+ } else {
+ $to = $this->config->get($a['to'], null, $channel);
+ }
+ } else {
+ $to = $this->config->get($a['to'], null, $channel);
+ }
+ if (is_null($to)) {
+ if (!isset($options['soft'])) {
+ $this->log(0, "invalid pear-config replacement: $a[to]");
+ }
+ continue;
+ }
+ } elseif ($a['type'] == 'package-info') {
+ if ($t = $this->pkginfo->packageInfo($a['to'])) {
+ $to = $t;
+ } else {
+ if (!isset($options['soft'])) {
+ $this->log(0, "invalid package-info replacement: $a[to]");
+ }
+ continue;
+ }
+ }
+ if (!is_null($to)) {
+ $subst_from[] = $a['from'];
+ $subst_to[] = $to;
+ }
+ }
+
+ $this->log(3, "doing ".sizeof($subst_from)." substitution(s) for $final_dest_file");
+ if (sizeof($subst_from)) {
+ $contents = str_replace($subst_from, $subst_to, $contents);
+ }
+
+ $wp = @fopen($dest_file, "wb");
+ if (!is_resource($wp)) {
+ return $this->raiseError("failed to create $dest_file: $php_errormsg",
+ PEAR_INSTALLER_FAILED);
+ }
+
+ if (@fwrite($wp, $contents) === false) {
+ return $this->raiseError("failed writing to $dest_file: $php_errormsg",
+ PEAR_INSTALLER_FAILED);
+ }
+
+ fclose($wp);
+ // }}}
+ }
+
+ // {{{ check the md5
+ if (isset($md5sum)) {
+ if (strtolower($md5sum) === strtolower($atts['md5sum'])) {
+ $this->log(2, "md5sum ok: $final_dest_file");
+ } else {
+ if (empty($options['force'])) {
+ // delete the file
+ if (file_exists($dest_file)) {
+ unlink($dest_file);
+ }
+
+ if (!isset($options['ignore-errors'])) {
+ return $this->raiseError("bad md5sum for file $final_dest_file",
+ PEAR_INSTALLER_FAILED);
+ }
+
+ if (!isset($options['soft'])) {
+ $this->log(0, "warning : bad md5sum for file $final_dest_file");
+ }
+ } else {
+ if (!isset($options['soft'])) {
+ $this->log(0, "warning : bad md5sum for file $final_dest_file");
+ }
+ }
+ }
+ }
+ // }}}
+ // {{{ set file permissions
+ if (!OS_WINDOWS) {
+ if ($atts['role'] == 'script') {
+ $mode = 0777 & ~(int)octdec($this->config->get('umask'));
+ $this->log(3, "+ chmod +x $dest_file");
+ } else {
+ $mode = 0666 & ~(int)octdec($this->config->get('umask'));
+ }
+
+ if ($atts['role'] != 'src') {
+ $this->addFileOperation("chmod", array($mode, $dest_file));
+ if (!@chmod($dest_file, $mode)) {
+ if (!isset($options['soft'])) {
+ $this->log(0, "failed to change mode of $dest_file: $php_errormsg");
+ }
+ }
+ }
+ }
+ // }}}
+
+ if ($atts['role'] == 'src') {
+ rename($dest_file, $final_dest_file);
+ $this->log(2, "renamed source file $dest_file to $final_dest_file");
+ } else {
+ $this->addFileOperation("rename", array($dest_file, $final_dest_file,
+ $atts['role'] == 'ext'));
+ }
+ }
+
+ // Store the full path where the file was installed for easy unistall
+ if ($atts['role'] != 'script') {
+ $loc = $this->config->get($atts['role'] . '_dir');
+ } else {
+ $loc = $this->config->get('bin_dir');
+ }
+
+ if ($atts['role'] != 'src') {
+ $this->addFileOperation("installed_as", array($file, $installed_as,
+ $loc,
+ dirname(substr($installedas_dest_file, strlen($loc)))));
+ }
+
+ //$this->log(2, "installed: $dest_file");
+ return PEAR_INSTALLER_OK;
+ }
+
+ // }}}
+ // {{{ _installFile2()
+
+ /**
+ * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+ * @param string filename
+ * @param array attributes from tag in package.xml
+ * @param string path to install the file in
+ * @param array options from command-line
+ * @access private
+ */
+ function _installFile2(&$pkg, $file, &$real_atts, $tmp_path, $options)
+ {
+ $atts = $real_atts;
+ if (!isset($this->_registry)) {
+ $this->_registry = &$this->config->getRegistry();
+ }
+
+ $channel = $pkg->getChannel();
+ // {{{ assemble the destination paths
+ if (!in_array($atts['attribs']['role'],
+ PEAR_Installer_Role::getValidRoles($pkg->getPackageType()))) {
+ return $this->raiseError('Invalid role `' . $atts['attribs']['role'] .
+ "' for file $file");
+ }
+
+ $role = &PEAR_Installer_Role::factory($pkg, $atts['attribs']['role'], $this->config);
+ $err = $role->setup($this, $pkg, $atts['attribs'], $file);
+ if (PEAR::isError($err)) {
+ return $err;
+ }
+
+ if (!$role->isInstallable()) {
+ return;
+ }
+
+ $info = $role->processInstallation($pkg, $atts['attribs'], $file, $tmp_path);
+ if (PEAR::isError($info)) {
+ return $info;
+ }
+
+ list($save_destdir, $dest_dir, $dest_file, $orig_file) = $info;
+ if (preg_match('~/\.\.(/|\\z)|^\.\./~', str_replace('\\', '/', $dest_file))) {
+ return $this->raiseError("SECURITY ERROR: file $file (installed to $dest_file) contains parent directory reference ..", PEAR_INSTALLER_FAILED);
+ }
+
+ $final_dest_file = $installed_as = $dest_file;
+ if (isset($this->_options['packagingroot'])) {
+ $final_dest_file = $this->_prependPath($final_dest_file,
+ $this->_options['packagingroot']);
+ }
+
+ $dest_dir = dirname($final_dest_file);
+ $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file);
+ // }}}
+
+ if (empty($this->_options['register-only'])) {
+ if (!file_exists($dest_dir) || !is_dir($dest_dir)) {
+ if (!$this->mkDirHier($dest_dir)) {
+ return $this->raiseError("failed to mkdir $dest_dir",
+ PEAR_INSTALLER_FAILED);
+ }
+ $this->log(3, "+ mkdir $dest_dir");
+ }
+ }
+
+ $attribs = $atts['attribs'];
+ unset($atts['attribs']);
+ // pretty much nothing happens if we are only registering the install
+ if (empty($this->_options['register-only'])) {
+ if (!count($atts)) { // no tasks
+ if (!file_exists($orig_file)) {
+ return $this->raiseError("file $orig_file does not exist",
+ PEAR_INSTALLER_FAILED);
+ }
+
+ if (!@copy($orig_file, $dest_file)) {
+ return $this->raiseError("failed to write $dest_file: $php_errormsg",
+ PEAR_INSTALLER_FAILED);
+ }
+
+ $this->log(3, "+ cp $orig_file $dest_file");
+ if (isset($attribs['md5sum'])) {
+ $md5sum = md5_file($dest_file);
+ }
+ } else { // file with tasks
+ if (!file_exists($orig_file)) {
+ return $this->raiseError("file $orig_file does not exist",
+ PEAR_INSTALLER_FAILED);
+ }
+
+ $contents = file_get_contents($orig_file);
+ if ($contents === false) {
+ $contents = '';
+ }
+
+ if (isset($attribs['md5sum'])) {
+ $md5sum = md5($contents);
+ }
+
+ foreach ($atts as $tag => $raw) {
+ $tag = str_replace(array($pkg->getTasksNs() . ':', '-'), array('', '_'), $tag);
+ $task = "PEAR_Task_$tag";
+ $task = new $task($this->config, $this, PEAR_TASK_INSTALL);
+ if (!$task->isScript()) { // scripts are only handled after installation
+ $task->init($raw, $attribs, $pkg->getLastInstalledVersion());
+ $res = $task->startSession($pkg, $contents, $final_dest_file);
+ if ($res === false) {
+ continue; // skip this file
+ }
+
+ if (PEAR::isError($res)) {
+ return $res;
+ }
+
+ $contents = $res; // save changes
+ }
+
+ $wp = @fopen($dest_file, "wb");
+ if (!is_resource($wp)) {
+ return $this->raiseError("failed to create $dest_file: $php_errormsg",
+ PEAR_INSTALLER_FAILED);
+ }
+
+ if (fwrite($wp, $contents) === false) {
+ return $this->raiseError("failed writing to $dest_file: $php_errormsg",
+ PEAR_INSTALLER_FAILED);
+ }
+
+ fclose($wp);
+ }
+ }
+
+ // {{{ check the md5
+ if (isset($md5sum)) {
+ // Make sure the original md5 sum matches with expected
+ if (strtolower($md5sum) === strtolower($attribs['md5sum'])) {
+ $this->log(2, "md5sum ok: $final_dest_file");
+
+ if (isset($contents)) {
+ // set md5 sum based on $content in case any tasks were run.
+ $real_atts['attribs']['md5sum'] = md5($contents);
+ }
+ } else {
+ if (empty($options['force'])) {
+ // delete the file
+ if (file_exists($dest_file)) {
+ unlink($dest_file);
+ }
+
+ if (!isset($options['ignore-errors'])) {
+ return $this->raiseError("bad md5sum for file $final_dest_file",
+ PEAR_INSTALLER_FAILED);
+ }
+
+ if (!isset($options['soft'])) {
+ $this->log(0, "warning : bad md5sum for file $final_dest_file");
+ }
+ } else {
+ if (!isset($options['soft'])) {
+ $this->log(0, "warning : bad md5sum for file $final_dest_file");
+ }
+ }
+ }
+ } else {
+ $real_atts['attribs']['md5sum'] = md5_file($dest_file);
+ }
+
+ // }}}
+ // {{{ set file permissions
+ if (!OS_WINDOWS) {
+ if ($role->isExecutable()) {
+ $mode = 0777 & ~(int)octdec($this->config->get('umask'));
+ $this->log(3, "+ chmod +x $dest_file");
+ } else {
+ $mode = 0666 & ~(int)octdec($this->config->get('umask'));
+ }
+
+ if ($attribs['role'] != 'src') {
+ $this->addFileOperation("chmod", array($mode, $dest_file));
+ if (!@chmod($dest_file, $mode)) {
+ if (!isset($options['soft'])) {
+ $this->log(0, "failed to change mode of $dest_file: $php_errormsg");
+ }
+ }
+ }
+ }
+ // }}}
+
+ if ($attribs['role'] == 'src') {
+ rename($dest_file, $final_dest_file);
+ $this->log(2, "renamed source file $dest_file to $final_dest_file");
+ } else {
+ $this->addFileOperation("rename", array($dest_file, $final_dest_file, $role->isExtension()));
+ }
+ }
+
+ // Store the full path where the file was installed for easy uninstall
+ if ($attribs['role'] != 'src') {
+ $loc = $this->config->get($role->getLocationConfig(), null, $channel);
+ $this->addFileOperation('installed_as', array($file, $installed_as,
+ $loc,
+ dirname(substr($installed_as, strlen($loc)))));
+ }
+
+ //$this->log(2, "installed: $dest_file");
+ return PEAR_INSTALLER_OK;
+ }
+
+ // }}}
+ // {{{ addFileOperation()
+
+ /**
+ * Add a file operation to the current file transaction.
+ *
+ * @see startFileTransaction()
+ * @param string $type This can be one of:
+ * - rename: rename a file ($data has 3 values)
+ * - backup: backup an existing file ($data has 1 value)
+ * - removebackup: clean up backups created during install ($data has 1 value)
+ * - chmod: change permissions on a file ($data has 2 values)
+ * - delete: delete a file ($data has 1 value)
+ * - rmdir: delete a directory if empty ($data has 1 value)
+ * - installed_as: mark a file as installed ($data has 4 values).
+ * @param array $data For all file operations, this array must contain the
+ * full path to the file or directory that is being operated on. For
+ * the rename command, the first parameter must be the file to rename,
+ * the second its new name, the third whether this is a PHP extension.
+ *
+ * The installed_as operation contains 4 elements in this order:
+ * 1. Filename as listed in the filelist element from package.xml
+ * 2. Full path to the installed file
+ * 3. Full path from the php_dir configuration variable used in this
+ * installation
+ * 4. Relative path from the php_dir that this file is installed in
+ */
+ function addFileOperation($type, $data)
+ {
+ if (!is_array($data)) {
+ return $this->raiseError('Internal Error: $data in addFileOperation'
+ . ' must be an array, was ' . gettype($data));
+ }
+
+ if ($type == 'chmod') {
+ $octmode = decoct($data[0]);
+ $this->log(3, "adding to transaction: $type $octmode $data[1]");
+ } else {
+ $this->log(3, "adding to transaction: $type " . implode(" ", $data));
+ }
+ $this->file_operations[] = array($type, $data);
+ }
+
+ // }}}
+ // {{{ startFileTransaction()
+
+ function startFileTransaction($rollback_in_case = false)
+ {
+ if (count($this->file_operations) && $rollback_in_case) {
+ $this->rollbackFileTransaction();
+ }
+ $this->file_operations = array();
+ }
+
+ // }}}
+ // {{{ commitFileTransaction()
+
+ function commitFileTransaction()
+ {
+ // {{{ first, check permissions and such manually
+ $errors = array();
+ foreach ($this->file_operations as $key => $tr) {
+ list($type, $data) = $tr;
+ switch ($type) {
+ case 'rename':
+ if (!file_exists($data[0])) {
+ $errors[] = "cannot rename file $data[0], doesn't exist";
+ }
+
+ // check that dest dir. is writable
+ if (!is_writable(dirname($data[1]))) {
+ $errors[] = "permission denied ($type): $data[1]";
+ }
+ break;
+ case 'chmod':
+ // check that file is writable
+ if (!is_writable($data[1])) {
+ $errors[] = "permission denied ($type): $data[1] " . decoct($data[0]);
+ }
+ break;
+ case 'delete':
+ if (!file_exists($data[0])) {
+ $this->log(2, "warning: file $data[0] doesn't exist, can't be deleted");
+ }
+ // check that directory is writable
+ if (file_exists($data[0])) {
+ if (!is_writable(dirname($data[0]))) {
+ $errors[] = "permission denied ($type): $data[0]";
+ } else {
+ // make sure the file to be deleted can be opened for writing
+ $fp = false;
+ if (!is_dir($data[0]) &&
+ (!is_writable($data[0]) || !($fp = @fopen($data[0], 'a')))) {
+ $errors[] = "permission denied ($type): $data[0]";
+ } elseif ($fp) {
+ fclose($fp);
+ }
+ }
+
+ /* Verify we are not deleting a file owned by another package
+ * This can happen when a file moves from package A to B in
+ * an upgrade ala http://pear.php.net/17986
+ */
+ $info = array(
+ 'package' => strtolower($this->pkginfo->getName()),
+ 'channel' => strtolower($this->pkginfo->getChannel()),
+ );
+ $result = $this->_registry->checkFileMap($data[0], $info, '1.1');
+ if (is_array($result)) {
+ $res = array_diff($result, $info);
+ if (!empty($res)) {
+ $new = $this->_registry->getPackage($result[1], $result[0]);
+ $this->file_operations[$key] = false;
+ $pkginfoName = $this->pkginfo->getName();
+ $newChannel = $new->getChannel();
+ $newPackage = $new->getName();
+ $this->log(3, "file $data[0] was scheduled for removal from $pkginfoName but is owned by $newChannel/$newPackage, removal has been cancelled.");
+ }
+ }
+ }
+ break;
+ }
+
+ }
+ // }}}
+
+ $n = count($this->file_operations);
+ $this->log(2, "about to commit $n file operations for " . $this->pkginfo->getName());
+
+ $m = count($errors);
+ if ($m > 0) {
+ foreach ($errors as $error) {
+ if (!isset($this->_options['soft'])) {
+ $this->log(1, $error);
+ }
+ }
+
+ if (!isset($this->_options['ignore-errors'])) {
+ return false;
+ }
+ }
+
+ $this->_dirtree = array();
+ // {{{ really commit the transaction
+ foreach ($this->file_operations as $i => $tr) {
+ if (!$tr) {
+ // support removal of non-existing backups
+ continue;
+ }
+
+ list($type, $data) = $tr;
+ switch ($type) {
+ case 'backup':
+ if (!file_exists($data[0])) {
+ $this->file_operations[$i] = false;
+ break;
+ }
+
+ if (!@copy($data[0], $data[0] . '.bak')) {
+ $this->log(1, 'Could not copy ' . $data[0] . ' to ' . $data[0] .
+ '.bak ' . $php_errormsg);
+ return false;
+ }
+ $this->log(3, "+ backup $data[0] to $data[0].bak");
+ break;
+ case 'removebackup':
+ if (file_exists($data[0] . '.bak') && is_writable($data[0] . '.bak')) {
+ unlink($data[0] . '.bak');
+ $this->log(3, "+ rm backup of $data[0] ($data[0].bak)");
+ }
+ break;
+ case 'rename':
+ $test = file_exists($data[1]) ? @unlink($data[1]) : null;
+ if (!$test && file_exists($data[1])) {
+ if ($data[2]) {
+ $extra = ', this extension must be installed manually. Rename to "' .
+ basename($data[1]) . '"';
+ } else {
+ $extra = '';
+ }
+
+ if (!isset($this->_options['soft'])) {
+ $this->log(1, 'Could not delete ' . $data[1] . ', cannot rename ' .
+ $data[0] . $extra);
+ }
+
+ if (!isset($this->_options['ignore-errors'])) {
+ return false;
+ }
+ }
+
+ // permissions issues with rename - copy() is far superior
+ $perms = @fileperms($data[0]);
+ if (!@copy($data[0], $data[1])) {
+ $this->log(1, 'Could not rename ' . $data[0] . ' to ' . $data[1] .
+ ' ' . $php_errormsg);
+ return false;
+ }
+
+ // copy over permissions, otherwise they are lost
+ @chmod($data[1], $perms);
+ @unlink($data[0]);
+ $this->log(3, "+ mv $data[0] $data[1]");
+ break;
+ case 'chmod':
+ if (!@chmod($data[1], $data[0])) {
+ $this->log(1, 'Could not chmod ' . $data[1] . ' to ' .
+ decoct($data[0]) . ' ' . $php_errormsg);
+ return false;
+ }
+
+ $octmode = decoct($data[0]);
+ $this->log(3, "+ chmod $octmode $data[1]");
+ break;
+ case 'delete':
+ if (file_exists($data[0])) {
+ if (!@unlink($data[0])) {
+ $this->log(1, 'Could not delete ' . $data[0] . ' ' .
+ $php_errormsg);
+ return false;
+ }
+ $this->log(3, "+ rm $data[0]");
+ }
+ break;
+ case 'rmdir':
+ if (file_exists($data[0])) {
+ do {
+ $testme = opendir($data[0]);
+ while (false !== ($entry = readdir($testme))) {
+ if ($entry == '.' || $entry == '..') {
+ continue;
+ }
+ closedir($testme);
+ break 2; // this directory is not empty and can't be
+ // deleted
+ }
+
+ closedir($testme);
+ if (!@rmdir($data[0])) {
+ $this->log(1, 'Could not rmdir ' . $data[0] . ' ' .
+ $php_errormsg);
+ return false;
+ }
+ $this->log(3, "+ rmdir $data[0]");
+ } while (false);
+ }
+ break;
+ case 'installed_as':
+ $this->pkginfo->setInstalledAs($data[0], $data[1]);
+ if (!isset($this->_dirtree[dirname($data[1])])) {
+ $this->_dirtree[dirname($data[1])] = true;
+ $this->pkginfo->setDirtree(dirname($data[1]));
+
+ while(!empty($data[3]) && dirname($data[3]) != $data[3] &&
+ $data[3] != '/' && $data[3] != '\\') {
+ $this->pkginfo->setDirtree($pp =
+ $this->_prependPath($data[3], $data[2]));
+ $this->_dirtree[$pp] = true;
+ $data[3] = dirname($data[3]);
+ }
+ }
+ break;
+ }
+ }
+ // }}}
+ $this->log(2, "successfully committed $n file operations");
+ $this->file_operations = array();
+ return true;
+ }
+
+ // }}}
+ // {{{ rollbackFileTransaction()
+
+ function rollbackFileTransaction()
+ {
+ $n = count($this->file_operations);
+ $this->log(2, "rolling back $n file operations");
+ foreach ($this->file_operations as $tr) {
+ list($type, $data) = $tr;
+ switch ($type) {
+ case 'backup':
+ if (file_exists($data[0] . '.bak')) {
+ if (file_exists($data[0] && is_writable($data[0]))) {
+ unlink($data[0]);
+ }
+ @copy($data[0] . '.bak', $data[0]);
+ $this->log(3, "+ restore $data[0] from $data[0].bak");
+ }
+ break;
+ case 'removebackup':
+ if (file_exists($data[0] . '.bak') && is_writable($data[0] . '.bak')) {
+ unlink($data[0] . '.bak');
+ $this->log(3, "+ rm backup of $data[0] ($data[0].bak)");
+ }
+ break;
+ case 'rename':
+ @unlink($data[0]);
+ $this->log(3, "+ rm $data[0]");
+ break;
+ case 'mkdir':
+ @rmdir($data[0]);
+ $this->log(3, "+ rmdir $data[0]");
+ break;
+ case 'chmod':
+ break;
+ case 'delete':
+ break;
+ case 'installed_as':
+ $this->pkginfo->setInstalledAs($data[0], false);
+ break;
+ }
+ }
+ $this->pkginfo->resetDirtree();
+ $this->file_operations = array();
+ }
+
+ // }}}
+ // {{{ mkDirHier($dir)
+
+ function mkDirHier($dir)
+ {
+ $this->addFileOperation('mkdir', array($dir));
+ return parent::mkDirHier($dir);
+ }
+
+ // }}}
+ // {{{ _parsePackageXml()
+
+ function _parsePackageXml(&$descfile)
+ {
+ // Parse xml file -----------------------------------------------
+ $pkg = new PEAR_PackageFile($this->config, $this->debug);
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $p = &$pkg->fromAnyFile($descfile, PEAR_VALIDATE_INSTALLING);
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($p)) {
+ if (is_array($p->getUserInfo())) {
+ foreach ($p->getUserInfo() as $err) {
+ $loglevel = $err['level'] == 'error' ? 0 : 1;
+ if (!isset($this->_options['soft'])) {
+ $this->log($loglevel, ucfirst($err['level']) . ': ' . $err['message']);
+ }
+ }
+ }
+ return $this->raiseError('Installation failed: invalid package file');
+ }
+
+ $descfile = $p->getPackageFile();
+ return $p;
+ }
+
+ // }}}
+ /**
+ * Set the list of PEAR_Downloader_Package objects to allow more sane
+ * dependency validation
+ * @param array
+ */
+ function setDownloadedPackages(&$pkgs)
+ {
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ $err = $this->analyzeDependencies($pkgs);
+ PEAR::popErrorHandling();
+ if (PEAR::isError($err)) {
+ return $err;
+ }
+ $this->_downloadedPackages = &$pkgs;
+ }
+
+ /**
+ * Set the list of PEAR_Downloader_Package objects to allow more sane
+ * dependency validation
+ * @param array
+ */
+ function setUninstallPackages(&$pkgs)
+ {
+ $this->_downloadedPackages = &$pkgs;
+ }
+
+ function getInstallPackages()
+ {
+ return $this->_downloadedPackages;
+ }
+
+ // {{{ install()
+
+ /**
+ * Installs the files within the package file specified.
+ *
+ * @param string|PEAR_Downloader_Package $pkgfile path to the package file,
+ * or a pre-initialized packagefile object
+ * @param array $options
+ * recognized options:
+ * - installroot : optional prefix directory for installation
+ * - force : force installation
+ * - register-only : update registry but don't install files
+ * - upgrade : upgrade existing install
+ * - soft : fail silently
+ * - nodeps : ignore dependency conflicts/missing dependencies
+ * - alldeps : install all dependencies
+ * - onlyreqdeps : install only required dependencies
+ *
+ * @return array|PEAR_Error package info if successful
+ */
+ function install($pkgfile, $options = array())
+ {
+ $this->_options = $options;
+ $this->_registry = &$this->config->getRegistry();
+ if (is_object($pkgfile)) {
+ $dlpkg = &$pkgfile;
+ $pkg = $pkgfile->getPackageFile();
+ $pkgfile = $pkg->getArchiveFile();
+ $descfile = $pkg->getPackageFile();
+ } else {
+ $descfile = $pkgfile;
+ $pkg = $this->_parsePackageXml($descfile);
+ if (PEAR::isError($pkg)) {
+ return $pkg;
+ }
+ }
+
+ $tmpdir = dirname($descfile);
+ if (realpath($descfile) != realpath($pkgfile)) {
+ // Use the temp_dir since $descfile can contain the download dir path
+ $tmpdir = $this->config->get('temp_dir', null, 'pear.php.net');
+ $tmpdir = System::mktemp('-d -t "' . $tmpdir . '"');
+
+ $tar = new Archive_Tar($pkgfile);
+ if (!$tar->extract($tmpdir)) {
+ return $this->raiseError("unable to unpack $pkgfile");
+ }
+ }
+
+ $pkgname = $pkg->getName();
+ $channel = $pkg->getChannel();
+
+ if (isset($options['installroot'])) {
+ $this->config->setInstallRoot($options['installroot']);
+ $this->_registry = &$this->config->getRegistry();
+ $installregistry = &$this->_registry;
+ $this->installroot = ''; // all done automagically now
+ $php_dir = $this->config->get('php_dir', null, $channel);
+ } else {
+ $this->config->setInstallRoot(false);
+ $this->_registry = &$this->config->getRegistry();
+ if (isset($this->_options['packagingroot'])) {
+ $regdir = $this->_prependPath(
+ $this->config->get('php_dir', null, 'pear.php.net'),
+ $this->_options['packagingroot']);
+
+ $metadata_dir = $this->config->get('metadata_dir', null, 'pear.php.net');
+ if ($metadata_dir) {
+ $metadata_dir = $this->_prependPath(
+ $metadata_dir,
+ $this->_options['packagingroot']);
+ }
+ $packrootphp_dir = $this->_prependPath(
+ $this->config->get('php_dir', null, $channel),
+ $this->_options['packagingroot']);
+
+ $installregistry = new PEAR_Registry($regdir, false, false, $metadata_dir);
+ if (!$installregistry->channelExists($channel, true)) {
+ // we need to fake a channel-discover of this channel
+ $chanobj = $this->_registry->getChannel($channel, true);
+ $installregistry->addChannel($chanobj);
+ }
+ $php_dir = $packrootphp_dir;
+ } else {
+ $installregistry = &$this->_registry;
+ $php_dir = $this->config->get('php_dir', null, $channel);
+ }
+ $this->installroot = '';
+ }
+
+ // {{{ checks to do when not in "force" mode
+ if (empty($options['force']) &&
+ (file_exists($this->config->get('php_dir')) &&
+ is_dir($this->config->get('php_dir')))) {
+ $testp = $channel == 'pear.php.net' ? $pkgname : array($channel, $pkgname);
+ $instfilelist = $pkg->getInstallationFileList(true);
+ if (PEAR::isError($instfilelist)) {
+ return $instfilelist;
+ }
+
+ // ensure we have the most accurate registry
+ $installregistry->flushFileMap();
+ $test = $installregistry->checkFileMap($instfilelist, $testp, '1.1');
+ if (PEAR::isError($test)) {
+ return $test;
+ }
+
+ if (sizeof($test)) {
+ $pkgs = $this->getInstallPackages();
+ $found = false;
+ foreach ($pkgs as $param) {
+ if ($pkg->isSubpackageOf($param)) {
+ $found = true;
+ break;
+ }
+ }
+
+ if ($found) {
+ // subpackages can conflict with earlier versions of parent packages
+ $parentreg = $installregistry->packageInfo($param->getPackage(), null, $param->getChannel());
+ $tmp = $test;
+ foreach ($tmp as $file => $info) {
+ if (is_array($info)) {
+ if (strtolower($info[1]) == strtolower($param->getPackage()) &&
+ strtolower($info[0]) == strtolower($param->getChannel())
+ ) {
+ if (isset($parentreg['filelist'][$file])) {
+ unset($parentreg['filelist'][$file]);
+ } else{
+ $pos = strpos($file, '/');
+ $basedir = substr($file, 0, $pos);
+ $file2 = substr($file, $pos + 1);
+ if (isset($parentreg['filelist'][$file2]['baseinstalldir'])
+ && $parentreg['filelist'][$file2]['baseinstalldir'] === $basedir
+ ) {
+ unset($parentreg['filelist'][$file2]);
+ }
+ }
+
+ unset($test[$file]);
+ }
+ } else {
+ if (strtolower($param->getChannel()) != 'pear.php.net') {
+ continue;
+ }
+
+ if (strtolower($info) == strtolower($param->getPackage())) {
+ if (isset($parentreg['filelist'][$file])) {
+ unset($parentreg['filelist'][$file]);
+ } else{
+ $pos = strpos($file, '/');
+ $basedir = substr($file, 0, $pos);
+ $file2 = substr($file, $pos + 1);
+ if (isset($parentreg['filelist'][$file2]['baseinstalldir'])
+ && $parentreg['filelist'][$file2]['baseinstalldir'] === $basedir
+ ) {
+ unset($parentreg['filelist'][$file2]);
+ }
+ }
+
+ unset($test[$file]);
+ }
+ }
+ }
+
+ $pfk = new PEAR_PackageFile($this->config);
+ $parentpkg = &$pfk->fromArray($parentreg);
+ $installregistry->updatePackage2($parentpkg);
+ }
+
+ if ($param->getChannel() == 'pecl.php.net' && isset($options['upgrade'])) {
+ $tmp = $test;
+ foreach ($tmp as $file => $info) {
+ if (is_string($info)) {
+ // pear.php.net packages are always stored as strings
+ if (strtolower($info) == strtolower($param->getPackage())) {
+ // upgrading existing package
+ unset($test[$file]);
+ }
+ }
+ }
+ }
+
+ if (count($test)) {
+ $msg = "$channel/$pkgname: conflicting files found:\n";
+ $longest = max(array_map("strlen", array_keys($test)));
+ $fmt = "%${longest}s (%s)\n";
+ foreach ($test as $file => $info) {
+ if (!is_array($info)) {
+ $info = array('pear.php.net', $info);
+ }
+ $info = $info[0] . '/' . $info[1];
+ $msg .= sprintf($fmt, $file, $info);
+ }
+
+ if (!isset($options['ignore-errors'])) {
+ return $this->raiseError($msg);
+ }
+
+ if (!isset($options['soft'])) {
+ $this->log(0, "WARNING: $msg");
+ }
+ }
+ }
+ }
+ // }}}
+
+ $this->startFileTransaction();
+
+ $usechannel = $channel;
+ if ($channel == 'pecl.php.net') {
+ $test = $installregistry->packageExists($pkgname, $channel);
+ if (!$test) {
+ $test = $installregistry->packageExists($pkgname, 'pear.php.net');
+ $usechannel = 'pear.php.net';
+ }
+ } else {
+ $test = $installregistry->packageExists($pkgname, $channel);
+ }
+
+ if (empty($options['upgrade']) && empty($options['soft'])) {
+ // checks to do only when installing new packages
+ if (empty($options['force']) && $test) {
+ return $this->raiseError("$channel/$pkgname is already installed");
+ }
+ } else {
+ // Upgrade
+ if ($test) {
+ $v1 = $installregistry->packageInfo($pkgname, 'version', $usechannel);
+ $v2 = $pkg->getVersion();
+ $cmp = version_compare("$v1", "$v2", 'gt');
+ if (empty($options['force']) && !version_compare("$v2", "$v1", 'gt')) {
+ return $this->raiseError("upgrade to a newer version ($v2 is not newer than $v1)");
+ }
+ }
+ }
+
+ // Do cleanups for upgrade and install, remove old release's files first
+ if ($test && empty($options['register-only'])) {
+ // when upgrading, remove old release's files first:
+ if (PEAR::isError($err = $this->_deletePackageFiles($pkgname, $usechannel,
+ true))) {
+ if (!isset($options['ignore-errors'])) {
+ return $this->raiseError($err);
+ }
+
+ if (!isset($options['soft'])) {
+ $this->log(0, 'WARNING: ' . $err->getMessage());
+ }
+ } else {
+ $backedup = $err;
+ }
+ }
+
+ // {{{ Copy files to dest dir ---------------------------------------
+
+ // info from the package it self we want to access from _installFile
+ $this->pkginfo = &$pkg;
+ // used to determine whether we should build any C code
+ $this->source_files = 0;
+
+ $savechannel = $this->config->get('default_channel');
+ if (empty($options['register-only']) && !is_dir($php_dir)) {
+ if (PEAR::isError(System::mkdir(array('-p'), $php_dir))) {
+ return $this->raiseError("no installation destination directory '$php_dir'\n");
+ }
+ }
+
+ if (substr($pkgfile, -4) != '.xml') {
+ $tmpdir .= DIRECTORY_SEPARATOR . $pkgname . '-' . $pkg->getVersion();
+ }
+
+ $this->configSet('default_channel', $channel);
+ // {{{ install files
+
+ $ver = $pkg->getPackagexmlVersion();
+ if (version_compare($ver, '2.0', '>=')) {
+ $filelist = $pkg->getInstallationFilelist();
+ } else {
+ $filelist = $pkg->getFileList();
+ }
+
+ if (PEAR::isError($filelist)) {
+ return $filelist;
+ }
+
+ $p = &$installregistry->getPackage($pkgname, $channel);
+ $dirtree = (empty($options['register-only']) && $p) ? $p->getDirTree() : false;
+
+ $pkg->resetFilelist();
+ $pkg->setLastInstalledVersion($installregistry->packageInfo($pkg->getPackage(),
+ 'version', $pkg->getChannel()));
+ foreach ($filelist as $file => $atts) {
+ $this->expectError(PEAR_INSTALLER_FAILED);
+ if ($pkg->getPackagexmlVersion() == '1.0') {
+ $res = $this->_installFile($file, $atts, $tmpdir, $options);
+ } else {
+ $res = $this->_installFile2($pkg, $file, $atts, $tmpdir, $options);
+ }
+ $this->popExpect();
+
+ if (PEAR::isError($res)) {
+ if (empty($options['ignore-errors'])) {
+ $this->rollbackFileTransaction();
+ if ($res->getMessage() == "file does not exist") {
+ $this->raiseError("file $file in package.xml does not exist");
+ }
+
+ return $this->raiseError($res);
+ }
+
+ if (!isset($options['soft'])) {
+ $this->log(0, "Warning: " . $res->getMessage());
+ }
+ }
+
+ $real = isset($atts['attribs']) ? $atts['attribs'] : $atts;
+ if ($res == PEAR_INSTALLER_OK && $real['role'] != 'src') {
+ // Register files that were installed
+ $pkg->installedFile($file, $atts);
+ }
+ }
+ // }}}
+
+ // {{{ compile and install source files
+ if ($this->source_files > 0 && empty($options['nobuild'])) {
+ if (PEAR::isError($err =
+ $this->_compileSourceFiles($savechannel, $pkg))) {
+ return $err;
+ }
+ }
+ // }}}
+
+ if (isset($backedup)) {
+ $this->_removeBackups($backedup);
+ }
+
+ if (!$this->commitFileTransaction()) {
+ $this->rollbackFileTransaction();
+ $this->configSet('default_channel', $savechannel);
+ return $this->raiseError("commit failed", PEAR_INSTALLER_FAILED);
+ }
+ // }}}
+
+ $ret = false;
+ $installphase = 'install';
+ $oldversion = false;
+ // {{{ Register that the package is installed -----------------------
+ if (empty($options['upgrade'])) {
+ // if 'force' is used, replace the info in registry
+ $usechannel = $channel;
+ if ($channel == 'pecl.php.net') {
+ $test = $installregistry->packageExists($pkgname, $channel);
+ if (!$test) {
+ $test = $installregistry->packageExists($pkgname, 'pear.php.net');
+ $usechannel = 'pear.php.net';
+ }
+ } else {
+ $test = $installregistry->packageExists($pkgname, $channel);
+ }
+
+ if (!empty($options['force']) && $test) {
+ $oldversion = $installregistry->packageInfo($pkgname, 'version', $usechannel);
+ $installregistry->deletePackage($pkgname, $usechannel);
+ }
+ $ret = $installregistry->addPackage2($pkg);
+ } else {
+ if ($dirtree) {
+ $this->startFileTransaction();
+ // attempt to delete empty directories
+ uksort($dirtree, array($this, '_sortDirs'));
+ foreach($dirtree as $dir => $notused) {
+ $this->addFileOperation('rmdir', array($dir));
+ }
+ $this->commitFileTransaction();
+ }
+
+ $usechannel = $channel;
+ if ($channel == 'pecl.php.net') {
+ $test = $installregistry->packageExists($pkgname, $channel);
+ if (!$test) {
+ $test = $installregistry->packageExists($pkgname, 'pear.php.net');
+ $usechannel = 'pear.php.net';
+ }
+ } else {
+ $test = $installregistry->packageExists($pkgname, $channel);
+ }
+
+ // new: upgrade installs a package if it isn't installed
+ if (!$test) {
+ $ret = $installregistry->addPackage2($pkg);
+ } else {
+ if ($usechannel != $channel) {
+ $installregistry->deletePackage($pkgname, $usechannel);
+ $ret = $installregistry->addPackage2($pkg);
+ } else {
+ $ret = $installregistry->updatePackage2($pkg);
+ }
+ $installphase = 'upgrade';
+ }
+ }
+
+ if (!$ret) {
+ $this->configSet('default_channel', $savechannel);
+ return $this->raiseError("Adding package $channel/$pkgname to registry failed");
+ }
+ // }}}
+
+ $this->configSet('default_channel', $savechannel);
+ if (class_exists('PEAR_Task_Common')) { // this is auto-included if any tasks exist
+ if (PEAR_Task_Common::hasPostinstallTasks()) {
+ PEAR_Task_Common::runPostinstallTasks($installphase);
+ }
+ }
+
+ return $pkg->toArray(true);
+ }
+
+ // }}}
+
+ // {{{ _compileSourceFiles()
+ /**
+ * @param string
+ * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+ */
+ function _compileSourceFiles($savechannel, &$filelist)
+ {
+ require_once 'PEAR/Builder.php';
+ $this->log(1, "$this->source_files source files, building");
+ $bob = new PEAR_Builder($this->ui);
+ $bob->debug = $this->debug;
+ $built = $bob->build($filelist, array(&$this, '_buildCallback'));
+ if (PEAR::isError($built)) {
+ $this->rollbackFileTransaction();
+ $this->configSet('default_channel', $savechannel);
+ return $built;
+ }
+
+ $this->log(1, "\nBuild process completed successfully");
+ foreach ($built as $ext) {
+ $bn = basename($ext['file']);
+ list($_ext_name, $_ext_suff) = explode('.', $bn);
+ if ($_ext_suff == '.so' || $_ext_suff == '.dll') {
+ if (extension_loaded($_ext_name)) {
+ $this->raiseError("Extension '$_ext_name' already loaded. " .
+ 'Please unload it in your php.ini file ' .
+ 'prior to install or upgrade');
+ }
+ $role = 'ext';
+ } else {
+ $role = 'src';
+ }
+
+ $dest = $ext['dest'];
+ $packagingroot = '';
+ if (isset($this->_options['packagingroot'])) {
+ $packagingroot = $this->_options['packagingroot'];
+ }
+
+ $copyto = $this->_prependPath($dest, $packagingroot);
+ $extra = $copyto != $dest ? " as '$copyto'" : '';
+ $this->log(1, "Installing '$dest'$extra");
+
+ $copydir = dirname($copyto);
+ // pretty much nothing happens if we are only registering the install
+ if (empty($this->_options['register-only'])) {
+ if (!file_exists($copydir) || !is_dir($copydir)) {
+ if (!$this->mkDirHier($copydir)) {
+ return $this->raiseError("failed to mkdir $copydir",
+ PEAR_INSTALLER_FAILED);
+ }
+
+ $this->log(3, "+ mkdir $copydir");
+ }
+
+ if (!@copy($ext['file'], $copyto)) {
+ return $this->raiseError("failed to write $copyto ($php_errormsg)", PEAR_INSTALLER_FAILED);
+ }
+
+ $this->log(3, "+ cp $ext[file] $copyto");
+ $this->addFileOperation('rename', array($ext['file'], $copyto));
+ if (!OS_WINDOWS) {
+ $mode = 0666 & ~(int)octdec($this->config->get('umask'));
+ $this->addFileOperation('chmod', array($mode, $copyto));
+ if (!@chmod($copyto, $mode)) {
+ $this->log(0, "failed to change mode of $copyto ($php_errormsg)");
+ }
+ }
+ }
+
+
+ $data = array(
+ 'role' => $role,
+ 'name' => $bn,
+ 'installed_as' => $dest,
+ 'php_api' => $ext['php_api'],
+ 'zend_mod_api' => $ext['zend_mod_api'],
+ 'zend_ext_api' => $ext['zend_ext_api'],
+ );
+
+ if ($filelist->getPackageXmlVersion() == '1.0') {
+ $filelist->installedFile($bn, $data);
+ } else {
+ $filelist->installedFile($bn, array('attribs' => $data));
+ }
+ }
+ }
+
+ // }}}
+ function &getUninstallPackages()
+ {
+ return $this->_downloadedPackages;
+ }
+ // {{{ uninstall()
+
+ /**
+ * Uninstall a package
+ *
+ * This method removes all files installed by the application, and then
+ * removes any empty directories.
+ * @param string package name
+ * @param array Command-line options. Possibilities include:
+ *
+ * - installroot: base installation dir, if not the default
+ * - register-only : update registry but don't remove files
+ * - nodeps: do not process dependencies of other packages to ensure
+ * uninstallation does not break things
+ */
+ function uninstall($package, $options = array())
+ {
+ $installRoot = isset($options['installroot']) ? $options['installroot'] : '';
+ $this->config->setInstallRoot($installRoot);
+
+ $this->installroot = '';
+ $this->_registry = &$this->config->getRegistry();
+ if (is_object($package)) {
+ $channel = $package->getChannel();
+ $pkg = $package;
+ $package = $pkg->getPackage();
+ } else {
+ $pkg = false;
+ $info = $this->_registry->parsePackageName($package,
+ $this->config->get('default_channel'));
+ $channel = $info['channel'];
+ $package = $info['package'];
+ }
+
+ $savechannel = $this->config->get('default_channel');
+ $this->configSet('default_channel', $channel);
+ if (!is_object($pkg)) {
+ $pkg = $this->_registry->getPackage($package, $channel);
+ }
+
+ if (!$pkg) {
+ $this->configSet('default_channel', $savechannel);
+ return $this->raiseError($this->_registry->parsedPackageNameToString(
+ array(
+ 'channel' => $channel,
+ 'package' => $package
+ ), true) . ' not installed');
+ }
+
+ if ($pkg->getInstalledBinary()) {
+ // this is just an alias for a binary package
+ return $this->_registry->deletePackage($package, $channel);
+ }
+
+ $filelist = $pkg->getFilelist();
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ if (!class_exists('PEAR_Dependency2')) {
+ require_once 'PEAR/Dependency2.php';
+ }
+
+ $depchecker = new PEAR_Dependency2($this->config, $options,
+ array('channel' => $channel, 'package' => $package),
+ PEAR_VALIDATE_UNINSTALLING);
+ $e = $depchecker->validatePackageUninstall($this);
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($e)) {
+ if (!isset($options['ignore-errors'])) {
+ return $this->raiseError($e);
+ }
+
+ if (!isset($options['soft'])) {
+ $this->log(0, 'WARNING: ' . $e->getMessage());
+ }
+ } elseif (is_array($e)) {
+ if (!isset($options['soft'])) {
+ $this->log(0, $e[0]);
+ }
+ }
+
+ $this->pkginfo = &$pkg;
+ // pretty much nothing happens if we are only registering the uninstall
+ if (empty($options['register-only'])) {
+ // {{{ Delete the files
+ $this->startFileTransaction();
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ if (PEAR::isError($err = $this->_deletePackageFiles($package, $channel))) {
+ PEAR::popErrorHandling();
+ $this->rollbackFileTransaction();
+ $this->configSet('default_channel', $savechannel);
+ if (!isset($options['ignore-errors'])) {
+ return $this->raiseError($err);
+ }
+
+ if (!isset($options['soft'])) {
+ $this->log(0, 'WARNING: ' . $err->getMessage());
+ }
+ } else {
+ PEAR::popErrorHandling();
+ }
+
+ if (!$this->commitFileTransaction()) {
+ $this->rollbackFileTransaction();
+ if (!isset($options['ignore-errors'])) {
+ return $this->raiseError("uninstall failed");
+ }
+
+ if (!isset($options['soft'])) {
+ $this->log(0, 'WARNING: uninstall failed');
+ }
+ } else {
+ $this->startFileTransaction();
+ $dirtree = $pkg->getDirTree();
+ if ($dirtree === false) {
+ $this->configSet('default_channel', $savechannel);
+ return $this->_registry->deletePackage($package, $channel);
+ }
+
+ // attempt to delete empty directories
+ uksort($dirtree, array($this, '_sortDirs'));
+ foreach($dirtree as $dir => $notused) {
+ $this->addFileOperation('rmdir', array($dir));
+ }
+
+ if (!$this->commitFileTransaction()) {
+ $this->rollbackFileTransaction();
+ if (!isset($options['ignore-errors'])) {
+ return $this->raiseError("uninstall failed");
+ }
+
+ if (!isset($options['soft'])) {
+ $this->log(0, 'WARNING: uninstall failed');
+ }
+ }
+ }
+ // }}}
+ }
+
+ $this->configSet('default_channel', $savechannel);
+ // Register that the package is no longer installed
+ return $this->_registry->deletePackage($package, $channel);
+ }
+
+ /**
+ * Sort a list of arrays of array(downloaded packagefilename) by dependency.
+ *
+ * It also removes duplicate dependencies
+ * @param array an array of PEAR_PackageFile_v[1/2] objects
+ * @return array|PEAR_Error array of array(packagefilename, package.xml contents)
+ */
+ function sortPackagesForUninstall(&$packages)
+ {
+ $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->config);
+ if (PEAR::isError($this->_dependencyDB)) {
+ return $this->_dependencyDB;
+ }
+ usort($packages, array(&$this, '_sortUninstall'));
+ }
+
+ function _sortUninstall($a, $b)
+ {
+ if (!$a->getDeps() && !$b->getDeps()) {
+ return 0; // neither package has dependencies, order is insignificant
+ }
+ if ($a->getDeps() && !$b->getDeps()) {
+ return -1; // $a must be installed after $b because $a has dependencies
+ }
+ if (!$a->getDeps() && $b->getDeps()) {
+ return 1; // $b must be installed after $a because $b has dependencies
+ }
+ // both packages have dependencies
+ if ($this->_dependencyDB->dependsOn($a, $b)) {
+ return -1;
+ }
+ if ($this->_dependencyDB->dependsOn($b, $a)) {
+ return 1;
+ }
+ return 0;
+ }
+
+ // }}}
+ // {{{ _sortDirs()
+ function _sortDirs($a, $b)
+ {
+ if (strnatcmp($a, $b) == -1) return 1;
+ if (strnatcmp($a, $b) == 1) return -1;
+ return 0;
+ }
+
+ // }}}
+
+ // {{{ _buildCallback()
+
+ function _buildCallback($what, $data)
+ {
+ if (($what == 'cmdoutput' && $this->debug > 1) ||
+ ($what == 'output' && $this->debug > 0)) {
+ $this->ui->outputData(rtrim($data), 'build');
+ }
+ }
+
+ // }}}
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role.php b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role.php
new file mode 100644
index 000000000..58b661bbf
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role.php
@@ -0,0 +1,266 @@
+
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+
+/**
+ * base class for installer roles
+ */
+require_once 'PEAR/Installer/Role/Common.php';
+require_once 'PEAR/XMLParser.php';
+/**
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_Installer_Role
+{
+ /**
+ * Set up any additional configuration variables that file roles require
+ *
+ * Never call this directly, it is called by the PEAR_Config constructor
+ * @param PEAR_Config
+ */
+ public static function initializeConfig(&$config)
+ {
+ if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) {
+ PEAR_Installer_Role::registerRoles();
+ }
+
+ foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $class => $info) {
+ if (!$info['config_vars']) {
+ continue;
+ }
+
+ $config->_addConfigVars($class, $info['config_vars']);
+ }
+ }
+
+ /**
+ * @param PEAR_PackageFile_v2
+ * @param string role name
+ * @param PEAR_Config
+ * @return PEAR_Installer_Role_Common
+ */
+ public static function &factory($pkg, $role, &$config)
+ {
+ if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) {
+ PEAR_Installer_Role::registerRoles();
+ }
+
+ if (!in_array($role, PEAR_Installer_Role::getValidRoles($pkg->getPackageType()))) {
+ $a = false;
+ return $a;
+ }
+
+ $a = 'PEAR_Installer_Role_' . ucfirst($role);
+ if (!class_exists($a)) {
+ require_once str_replace('_', '/', $a) . '.php';
+ }
+
+ $b = new $a($config);
+ return $b;
+ }
+
+ /**
+ * Get a list of file roles that are valid for the particular release type.
+ *
+ * For instance, src files serve no purpose in regular php releases.
+ * @param string
+ * @param bool clear cache
+ * @return array
+ */
+ public static function getValidRoles($release, $clear = false)
+ {
+ if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) {
+ PEAR_Installer_Role::registerRoles();
+ }
+
+ static $ret = array();
+ if ($clear) {
+ $ret = array();
+ }
+
+ if (isset($ret[$release])) {
+ return $ret[$release];
+ }
+
+ $ret[$release] = array();
+ foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) {
+ if (in_array($release, $okreleases['releasetypes'])) {
+ $ret[$release][] = strtolower(str_replace('PEAR_Installer_Role_', '', $role));
+ }
+ }
+
+ return $ret[$release];
+ }
+
+ /**
+ * Get a list of roles that require their files to be installed
+ *
+ * Most roles must be installed, but src and package roles, for instance
+ * are pseudo-roles. src files are compiled into a new extension. Package
+ * roles are actually fully bundled releases of a package
+ * @param bool clear cache
+ * @return array
+ */
+ public static function getInstallableRoles($clear = false)
+ {
+ if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) {
+ PEAR_Installer_Role::registerRoles();
+ }
+
+ static $ret;
+ if ($clear) {
+ unset($ret);
+ }
+
+ if (isset($ret)) {
+ return $ret;
+ }
+
+ $ret = array();
+ foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) {
+ if ($okreleases['installable']) {
+ $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role));
+ }
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Return an array of roles that are affected by the baseinstalldir attribute
+ *
+ * Most roles ignore this attribute, and instead install directly into:
+ * PackageName/filepath
+ * so a tests file tests/file.phpt is installed into PackageName/tests/filepath.php
+ * @param bool clear cache
+ * @return array
+ */
+ public static function getBaseinstallRoles($clear = false)
+ {
+ if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) {
+ PEAR_Installer_Role::registerRoles();
+ }
+
+ static $ret;
+ if ($clear) {
+ unset($ret);
+ }
+
+ if (isset($ret)) {
+ return $ret;
+ }
+
+ $ret = array();
+ foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) {
+ if ($okreleases['honorsbaseinstall']) {
+ $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role));
+ }
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Return an array of file roles that should be analyzed for PHP content at package time,
+ * like the "php" role.
+ * @param bool clear cache
+ * @return array
+ */
+ public static function getPhpRoles($clear = false)
+ {
+ if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'])) {
+ PEAR_Installer_Role::registerRoles();
+ }
+
+ static $ret;
+ if ($clear) {
+ unset($ret);
+ }
+
+ if (isset($ret)) {
+ return $ret;
+ }
+
+ $ret = array();
+ foreach ($GLOBALS['_PEAR_INSTALLER_ROLES'] as $role => $okreleases) {
+ if ($okreleases['phpfile']) {
+ $ret[] = strtolower(str_replace('PEAR_Installer_Role_', '', $role));
+ }
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Scan through the Command directory looking for classes
+ * and see what commands they implement.
+ * @param string which directory to look for classes, defaults to
+ * the Installer/Roles subdirectory of
+ * the directory from where this file (__FILE__) is
+ * included.
+ *
+ * @return bool TRUE on success, a PEAR error on failure
+ */
+ public static function registerRoles($dir = null)
+ {
+ $GLOBALS['_PEAR_INSTALLER_ROLES'] = array();
+ $parser = new PEAR_XMLParser;
+ if ($dir === null) {
+ $dir = dirname(__FILE__) . '/Role';
+ }
+
+ if (!file_exists($dir) || !is_dir($dir)) {
+ return PEAR::raiseError("registerRoles: opendir($dir) failed: does not exist/is not directory");
+ }
+
+ $dp = @opendir($dir);
+ if (empty($dp)) {
+ return PEAR::raiseError("registerRoles: opendir($dir) failed: $php_errmsg");
+ }
+
+ while ($entry = readdir($dp)) {
+ if ($entry{0} == '.' || substr($entry, -4) != '.xml') {
+ continue;
+ }
+
+ $class = "PEAR_Installer_Role_".substr($entry, 0, -4);
+ // List of roles
+ if (!isset($GLOBALS['_PEAR_INSTALLER_ROLES'][$class])) {
+ $file = "$dir/$entry";
+ $parser->parse(file_get_contents($file));
+ $data = $parser->getData();
+ if (!is_array($data['releasetypes'])) {
+ $data['releasetypes'] = array($data['releasetypes']);
+ }
+
+ $GLOBALS['_PEAR_INSTALLER_ROLES'][$class] = $data;
+ }
+ }
+
+ closedir($dp);
+ ksort($GLOBALS['_PEAR_INSTALLER_ROLES']);
+ PEAR_Installer_Role::getBaseinstallRoles(true);
+ PEAR_Installer_Role::getInstallableRoles(true);
+ PEAR_Installer_Role::getPhpRoles(true);
+ PEAR_Installer_Role::getValidRoles('****', true);
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Cfg.php b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Cfg.php
new file mode 100644
index 000000000..5b75c44cc
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Cfg.php
@@ -0,0 +1,105 @@
+
+ * @copyright 2007-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.7.0
+ */
+
+/**
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 2007-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.7.0
+ */
+class PEAR_Installer_Role_Cfg extends PEAR_Installer_Role_Common
+{
+ /**
+ * @var PEAR_Installer
+ */
+ var $installer;
+
+ /**
+ * the md5 of the original file
+ *
+ * @var unknown_type
+ */
+ var $md5 = null;
+
+ /**
+ * Do any unusual setup here
+ * @param PEAR_Installer
+ * @param PEAR_PackageFile_v2
+ * @param array file attributes
+ * @param string file name
+ */
+ function setup(&$installer, $pkg, $atts, $file)
+ {
+ $this->installer = &$installer;
+ $reg = &$this->installer->config->getRegistry();
+ $package = $reg->getPackage($pkg->getPackage(), $pkg->getChannel());
+ if ($package) {
+ $filelist = $package->getFilelist();
+ if (isset($filelist[$file]) && isset($filelist[$file]['md5sum'])) {
+ $this->md5 = $filelist[$file]['md5sum'];
+ }
+ }
+ }
+
+ function processInstallation($pkg, $atts, $file, $tmp_path, $layer = null)
+ {
+ $test = parent::processInstallation($pkg, $atts, $file, $tmp_path, $layer);
+ if (@file_exists($test[2]) && @file_exists($test[3])) {
+ $md5 = md5_file($test[2]);
+ // configuration has already been installed, check for mods
+ if ($md5 !== $this->md5 && $md5 !== md5_file($test[3])) {
+ // configuration has been modified, so save our version as
+ // configfile-version
+ $old = $test[2];
+ $test[2] .= '.new-' . $pkg->getVersion();
+ // backup original and re-install it
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ $tmpcfg = $this->config->get('temp_dir');
+ $newloc = System::mkdir(array('-p', $tmpcfg));
+ if (!$newloc) {
+ // try temp_dir
+ $newloc = System::mktemp(array('-d'));
+ if (!$newloc || PEAR::isError($newloc)) {
+ PEAR::popErrorHandling();
+ return PEAR::raiseError('Could not save existing configuration file '.
+ $old . ', unable to install. Please set temp_dir ' .
+ 'configuration variable to a writeable location and try again');
+ }
+ } else {
+ $newloc = $tmpcfg;
+ }
+
+ $temp_file = $newloc . DIRECTORY_SEPARATOR . uniqid('savefile');
+ if (!@copy($old, $temp_file)) {
+ PEAR::popErrorHandling();
+ return PEAR::raiseError('Could not save existing configuration file '.
+ $old . ', unable to install. Please set temp_dir ' .
+ 'configuration variable to a writeable location and try again');
+ }
+
+ PEAR::popErrorHandling();
+ $this->installer->log(0, "WARNING: configuration file $old is being installed as $test[2], you should manually merge in changes to the existing configuration file");
+ $this->installer->addFileOperation('rename', array($temp_file, $old, false));
+ $this->installer->addFileOperation('delete', array($temp_file));
+ }
+ }
+
+ return $test;
+ }
+}
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Cfg.xml b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Cfg.xml
new file mode 100644
index 000000000..7a415dc46
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Cfg.xml
@@ -0,0 +1,15 @@
+
+ php
+ extsrc
+ extbin
+ zendextsrc
+ zendextbin
+ 1
+ cfg_dir
+
+ 1
+
+
+
+
+
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Common.php b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Common.php
new file mode 100644
index 000000000..3e15d8778
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Common.php
@@ -0,0 +1,173 @@
+
+ * @copyright 1997-2006 The PHP Group
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+/**
+ * Base class for all installation roles.
+ *
+ * This class allows extensibility of file roles. Packages with complex
+ * customization can now provide custom file roles along with the possibility of
+ * adding configuration values to match.
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2006 The PHP Group
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_Installer_Role_Common
+{
+ /**
+ * @var PEAR_Config
+ * @access protected
+ */
+ var $config;
+
+ /**
+ * @param PEAR_Config
+ */
+ function __construct(&$config)
+ {
+ $this->config = $config;
+ }
+
+ /**
+ * Retrieve configuration information about a file role from its XML info
+ *
+ * @param string $role Role Classname, as in "PEAR_Installer_Role_Data"
+ * @return array
+ */
+ function getInfo($role)
+ {
+ if (empty($GLOBALS['_PEAR_INSTALLER_ROLES'][$role])) {
+ return PEAR::raiseError('Unknown Role class: "' . $role . '"');
+ }
+ return $GLOBALS['_PEAR_INSTALLER_ROLES'][$role];
+ }
+
+ /**
+ * This is called for each file to set up the directories and files
+ * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+ * @param array attributes from the tag
+ * @param string file name
+ * @return array an array consisting of:
+ *
+ * 1 the original, pre-baseinstalldir installation directory
+ * 2 the final installation directory
+ * 3 the full path to the final location of the file
+ * 4 the location of the pre-installation file
+ */
+ function processInstallation($pkg, $atts, $file, $tmp_path, $layer = null)
+ {
+ $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' .
+ ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this)))));
+ if (PEAR::isError($roleInfo)) {
+ return $roleInfo;
+ }
+ if (!$roleInfo['locationconfig']) {
+ return false;
+ }
+ if ($roleInfo['honorsbaseinstall']) {
+ $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'], $layer,
+ $pkg->getChannel());
+ if (!empty($atts['baseinstalldir'])) {
+ $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir'];
+ }
+ } elseif ($roleInfo['unusualbaseinstall']) {
+ $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'],
+ $layer, $pkg->getChannel()) . DIRECTORY_SEPARATOR . $pkg->getPackage();
+ if (!empty($atts['baseinstalldir'])) {
+ $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir'];
+ }
+ } else {
+ $dest_dir = $save_destdir = $this->config->get($roleInfo['locationconfig'],
+ $layer, $pkg->getChannel()) . DIRECTORY_SEPARATOR . $pkg->getPackage();
+ }
+ if (dirname($file) != '.' && empty($atts['install-as'])) {
+ $dest_dir .= DIRECTORY_SEPARATOR . dirname($file);
+ }
+ if (empty($atts['install-as'])) {
+ $dest_file = $dest_dir . DIRECTORY_SEPARATOR . basename($file);
+ } else {
+ $dest_file = $dest_dir . DIRECTORY_SEPARATOR . $atts['install-as'];
+ }
+ $orig_file = $tmp_path . DIRECTORY_SEPARATOR . $file;
+
+ // Clean up the DIRECTORY_SEPARATOR mess
+ $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR;
+
+ list($dest_dir, $dest_file, $orig_file) = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"),
+ array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR,
+ DIRECTORY_SEPARATOR),
+ array($dest_dir, $dest_file, $orig_file));
+ return array($save_destdir, $dest_dir, $dest_file, $orig_file);
+ }
+
+ /**
+ * Get the name of the configuration variable that specifies the location of this file
+ * @return string|false
+ */
+ function getLocationConfig()
+ {
+ $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' .
+ ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this)))));
+ if (PEAR::isError($roleInfo)) {
+ return $roleInfo;
+ }
+ return $roleInfo['locationconfig'];
+ }
+
+ /**
+ * Do any unusual setup here
+ * @param PEAR_Installer
+ * @param PEAR_PackageFile_v2
+ * @param array file attributes
+ * @param string file name
+ */
+ function setup(&$installer, $pkg, $atts, $file)
+ {
+ }
+
+ function isExecutable()
+ {
+ $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' .
+ ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this)))));
+ if (PEAR::isError($roleInfo)) {
+ return $roleInfo;
+ }
+ return $roleInfo['executable'];
+ }
+
+ function isInstallable()
+ {
+ $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' .
+ ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this)))));
+ if (PEAR::isError($roleInfo)) {
+ return $roleInfo;
+ }
+ return $roleInfo['installable'];
+ }
+
+ function isExtension()
+ {
+ $roleInfo = PEAR_Installer_Role_Common::getInfo('PEAR_Installer_Role_' .
+ ucfirst(str_replace('pear_installer_role_', '', strtolower(get_class($this)))));
+ if (PEAR::isError($roleInfo)) {
+ return $roleInfo;
+ }
+ return $roleInfo['phpextension'];
+ }
+}
+?>
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Data.php b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Data.php
new file mode 100644
index 000000000..75acfef80
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Data.php
@@ -0,0 +1,27 @@
+
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+
+/**
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_Installer_Role_Data extends PEAR_Installer_Role_Common {}
+?>
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Data.xml b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Data.xml
new file mode 100644
index 000000000..eae63720d
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Data.xml
@@ -0,0 +1,15 @@
+
+ php
+ extsrc
+ extbin
+ zendextsrc
+ zendextbin
+ 1
+ data_dir
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Doc.php b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Doc.php
new file mode 100644
index 000000000..9374990c4
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Doc.php
@@ -0,0 +1,27 @@
+
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+
+/**
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_Installer_Role_Doc extends PEAR_Installer_Role_Common {}
+?>
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Doc.xml b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Doc.xml
new file mode 100644
index 000000000..173afba01
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Doc.xml
@@ -0,0 +1,15 @@
+
+ php
+ extsrc
+ extbin
+ zendextsrc
+ zendextbin
+ 1
+ doc_dir
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Ext.php b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Ext.php
new file mode 100644
index 000000000..6cd4d2b0a
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Ext.php
@@ -0,0 +1,27 @@
+
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+
+/**
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_Installer_Role_Ext extends PEAR_Installer_Role_Common {}
+?>
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Ext.xml b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Ext.xml
new file mode 100644
index 000000000..e2940fe1f
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Ext.xml
@@ -0,0 +1,12 @@
+
+ extbin
+ zendextbin
+ 1
+ ext_dir
+ 1
+
+
+
+ 1
+
+
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Man.php b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Man.php
new file mode 100644
index 000000000..68b79366a
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Man.php
@@ -0,0 +1,28 @@
+
+ * @copyright 2011 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version SVN: $Id: $
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.10.0
+ */
+
+/**
+ * @category pear
+ * @package PEAR
+ * @author Hannes Magnusson
+ * @copyright 2011 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.10.0
+ */
+class PEAR_Installer_Role_Man extends PEAR_Installer_Role_Common {}
+?>
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Man.xml b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Man.xml
new file mode 100644
index 000000000..ec2bd76c3
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Man.xml
@@ -0,0 +1,15 @@
+
+ php
+ extsrc
+ extbin
+ zendextsrc
+ zendextbin
+ 1
+ man_dir
+ 1
+
+
+
+
+
+
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Php.php b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Php.php
new file mode 100644
index 000000000..6a7a937de
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Php.php
@@ -0,0 +1,27 @@
+
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+
+/**
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_Installer_Role_Php extends PEAR_Installer_Role_Common {}
+?>
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Php.xml b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Php.xml
new file mode 100644
index 000000000..6b9a0e67a
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Php.xml
@@ -0,0 +1,15 @@
+
+ php
+ extsrc
+ extbin
+ zendextsrc
+ zendextbin
+ 1
+ php_dir
+ 1
+
+ 1
+
+
+
+
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Script.php b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Script.php
new file mode 100644
index 000000000..387fdb3f5
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Script.php
@@ -0,0 +1,27 @@
+
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+
+/**
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_Installer_Role_Script extends PEAR_Installer_Role_Common {}
+?>
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Script.xml b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Script.xml
new file mode 100644
index 000000000..e732cf2af
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Script.xml
@@ -0,0 +1,15 @@
+
+ php
+ extsrc
+ extbin
+ zendextsrc
+ zendextbin
+ 1
+ bin_dir
+ 1
+
+
+ 1
+
+
+
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Src.php b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Src.php
new file mode 100644
index 000000000..c92f2cf0b
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Src.php
@@ -0,0 +1,33 @@
+
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+
+/**
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_Installer_Role_Src extends PEAR_Installer_Role_Common
+{
+ function setup(&$installer, $pkg, $atts, $file)
+ {
+ $installer->source_files++;
+ }
+}
+?>
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Src.xml b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Src.xml
new file mode 100644
index 000000000..103483402
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Src.xml
@@ -0,0 +1,12 @@
+
+ extsrc
+ zendextsrc
+ 1
+ temp_dir
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Test.php b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Test.php
new file mode 100644
index 000000000..87133af46
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Test.php
@@ -0,0 +1,27 @@
+
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+
+/**
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_Installer_Role_Test extends PEAR_Installer_Role_Common {}
+?>
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Test.xml b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Test.xml
new file mode 100644
index 000000000..51d5b894e
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Test.xml
@@ -0,0 +1,15 @@
+
+ php
+ extsrc
+ extbin
+ zendextsrc
+ zendextbin
+ 1
+ test_dir
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Www.php b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Www.php
new file mode 100644
index 000000000..e211c1e8f
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Www.php
@@ -0,0 +1,27 @@
+
+ * @copyright 2007-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.7.0
+ */
+
+/**
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 2007-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.7.0
+ */
+class PEAR_Installer_Role_Www extends PEAR_Installer_Role_Common {}
+?>
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Www.xml b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Www.xml
new file mode 100644
index 000000000..7598be388
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Installer/Role/Www.xml
@@ -0,0 +1,15 @@
+
+ php
+ extsrc
+ extbin
+ zendextsrc
+ zendextbin
+ 1
+ www_dir
+ 1
+
+
+
+
+
+
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/PackageFile.php b/vendor/pear-pear.php.net/PEAR/PEAR/PackageFile.php
new file mode 100644
index 000000000..21d26b6df
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/PackageFile.php
@@ -0,0 +1,491 @@
+
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+
+/**
+ * needed for PEAR_VALIDATE_* constants
+ */
+require_once 'PEAR/Validate.php';
+/**
+ * Error code if the package.xml tag does not contain a valid version
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_PACKAGEVERSION', 1);
+/**
+ * Error code if the package.xml tag version is not supported (version 1.0 and 1.1 are the only supported versions,
+ * currently
+ */
+define('PEAR_PACKAGEFILE_ERROR_INVALID_PACKAGEVERSION', 2);
+/**
+ * Abstraction for the package.xml package description file
+ *
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_PackageFile
+{
+ /**
+ * @var PEAR_Config
+ */
+ var $_config;
+ var $_debug;
+
+ var $_logger = false;
+ /**
+ * @var boolean
+ */
+ var $_rawReturn = false;
+
+ /**
+ * helper for extracting Archive_Tar errors
+ * @var array
+ * @access private
+ */
+ var $_extractErrors = array();
+
+ /**
+ *
+ * @param PEAR_Config $config
+ * @param ? $debug
+ * @param string @tmpdir Optional temporary directory for uncompressing
+ * files
+ */
+ function __construct(&$config, $debug = false)
+ {
+ $this->_config = $config;
+ $this->_debug = $debug;
+ }
+
+ /**
+ * Turn off validation - return a parsed package.xml without checking it
+ *
+ * This is used by the package-validate command
+ */
+ function rawReturn()
+ {
+ $this->_rawReturn = true;
+ }
+
+ function setLogger(&$l)
+ {
+ $this->_logger = &$l;
+ }
+
+ /**
+ * Create a PEAR_PackageFile_Parser_v* of a given version.
+ * @param int $version
+ * @return PEAR_PackageFile_Parser_v1|PEAR_PackageFile_Parser_v1
+ */
+ function &parserFactory($version)
+ {
+ if (!in_array($version{0}, array('1', '2'))) {
+ $a = false;
+ return $a;
+ }
+
+ include_once 'PEAR/PackageFile/Parser/v' . $version{0} . '.php';
+ $version = $version{0};
+ $class = "PEAR_PackageFile_Parser_v$version";
+ $a = new $class;
+ return $a;
+ }
+
+ /**
+ * For simpler unit-testing
+ * @return string
+ */
+ function getClassPrefix()
+ {
+ return 'PEAR_PackageFile_v';
+ }
+
+ /**
+ * Create a PEAR_PackageFile_v* of a given version.
+ * @param int $version
+ * @return PEAR_PackageFile_v1|PEAR_PackageFile_v1
+ */
+ function &factory($version)
+ {
+ if (!in_array($version{0}, array('1', '2'))) {
+ $a = false;
+ return $a;
+ }
+
+ include_once 'PEAR/PackageFile/v' . $version{0} . '.php';
+ $version = $version{0};
+ $class = $this->getClassPrefix() . $version;
+ $a = new $class;
+ return $a;
+ }
+
+ /**
+ * Create a PEAR_PackageFile_v* from its toArray() method
+ *
+ * WARNING: no validation is performed, the array is assumed to be valid,
+ * always parse from xml if you want validation.
+ * @param array $arr
+ * @return PEAR_PackageFileManager_v1|PEAR_PackageFileManager_v2
+ * @uses factory() to construct the returned object.
+ */
+ function &fromArray($arr)
+ {
+ if (isset($arr['xsdversion'])) {
+ $obj = &$this->factory($arr['xsdversion']);
+ if ($this->_logger) {
+ $obj->setLogger($this->_logger);
+ }
+
+ $obj->setConfig($this->_config);
+ $obj->fromArray($arr);
+ return $obj;
+ }
+
+ if (isset($arr['package']['attribs']['version'])) {
+ $obj = &$this->factory($arr['package']['attribs']['version']);
+ } else {
+ $obj = &$this->factory('1.0');
+ }
+
+ if ($this->_logger) {
+ $obj->setLogger($this->_logger);
+ }
+
+ $obj->setConfig($this->_config);
+ $obj->fromArray($arr);
+ return $obj;
+ }
+
+ /**
+ * Create a PEAR_PackageFile_v* from an XML string.
+ * @access public
+ * @param string $data contents of package.xml file
+ * @param int $state package state (one of PEAR_VALIDATE_* constants)
+ * @param string $file full path to the package.xml file (and the files
+ * it references)
+ * @param string $archive optional name of the archive that the XML was
+ * extracted from, if any
+ * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2
+ * @uses parserFactory() to construct a parser to load the package.
+ */
+ function &fromXmlString($data, $state, $file, $archive = false)
+ {
+ if (preg_match('/]+version=[\'"]([0-9]+\.[0-9]+)[\'"]/', $data, $packageversion)) {
+ if (!in_array($packageversion[1], array('1.0', '2.0', '2.1'))) {
+ return PEAR::raiseError('package.xml version "' . $packageversion[1] .
+ '" is not supported, only 1.0, 2.0, and 2.1 are supported.');
+ }
+
+ $object = &$this->parserFactory($packageversion[1]);
+ if ($this->_logger) {
+ $object->setLogger($this->_logger);
+ }
+
+ $object->setConfig($this->_config);
+ $pf = $object->parse($data, $file, $archive);
+ if (PEAR::isError($pf)) {
+ return $pf;
+ }
+
+ if ($this->_rawReturn) {
+ return $pf;
+ }
+
+ if (!$pf->validate($state)) {;
+ if ($this->_config->get('verbose') > 0
+ && $this->_logger && $pf->getValidationWarnings(false)
+ ) {
+ foreach ($pf->getValidationWarnings(false) as $warning) {
+ $this->_logger->log(0, 'ERROR: ' . $warning['message']);
+ }
+ }
+
+ $a = PEAR::raiseError('Parsing of package.xml from file "' . $file . '" failed',
+ 2, null, null, $pf->getValidationWarnings());
+ return $a;
+ }
+
+ if ($this->_logger && $pf->getValidationWarnings(false)) {
+ foreach ($pf->getValidationWarnings() as $warning) {
+ $this->_logger->log(0, 'WARNING: ' . $warning['message']);
+ }
+ }
+
+ if (method_exists($pf, 'flattenFilelist')) {
+ $pf->flattenFilelist(); // for v2
+ }
+
+ return $pf;
+ } elseif (preg_match('/]+version=[\'"]([^"\']+)[\'"]/', $data, $packageversion)) {
+ $a = PEAR::raiseError('package.xml file "' . $file .
+ '" has unsupported package.xml version "' . $packageversion[1] . '"');
+ return $a;
+ } else {
+ if (!class_exists('PEAR_ErrorStack')) {
+ require_once 'PEAR/ErrorStack.php';
+ }
+
+ PEAR_ErrorStack::staticPush('PEAR_PackageFile',
+ PEAR_PACKAGEFILE_ERROR_NO_PACKAGEVERSION,
+ 'warning', array('xml' => $data), 'package.xml "' . $file .
+ '" has no package.xml version');
+ $object = &$this->parserFactory('1.0');
+ $object->setConfig($this->_config);
+ $pf = $object->parse($data, $file, $archive);
+ if (PEAR::isError($pf)) {
+ return $pf;
+ }
+
+ if ($this->_rawReturn) {
+ return $pf;
+ }
+
+ if (!$pf->validate($state)) {
+ $a = PEAR::raiseError('Parsing of package.xml from file "' . $file . '" failed',
+ 2, null, null, $pf->getValidationWarnings());
+ return $a;
+ }
+
+ if ($this->_logger && $pf->getValidationWarnings(false)) {
+ foreach ($pf->getValidationWarnings() as $warning) {
+ $this->_logger->log(0, 'WARNING: ' . $warning['message']);
+ }
+ }
+
+ if (method_exists($pf, 'flattenFilelist')) {
+ $pf->flattenFilelist(); // for v2
+ }
+
+ return $pf;
+ }
+ }
+
+ /**
+ * Register a temporary file or directory. When the destructor is
+ * executed, all registered temporary files and directories are
+ * removed.
+ *
+ * @param string $file name of file or directory
+ * @return void
+ */
+ function addTempFile($file)
+ {
+ $GLOBALS['_PEAR_Common_tempfiles'][] = $file;
+ }
+
+ /**
+ * Create a PEAR_PackageFile_v* from a compressed Tar or Tgz file.
+ * @access public
+ * @param string contents of package.xml file
+ * @param int package state (one of PEAR_VALIDATE_* constants)
+ * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2
+ * @using Archive_Tar to extract the files
+ * @using fromPackageFile() to load the package after the package.xml
+ * file is extracted.
+ */
+ function &fromTgzFile($file, $state)
+ {
+ if (!class_exists('Archive_Tar')) {
+ require_once 'Archive/Tar.php';
+ }
+
+ $tar = new Archive_Tar($file);
+ if ($this->_debug <= 1) {
+ $tar->pushErrorHandling(PEAR_ERROR_RETURN);
+ }
+
+ $content = $tar->listContent();
+ if ($this->_debug <= 1) {
+ $tar->popErrorHandling();
+ }
+
+ if (!is_array($content)) {
+ if (is_string($file) && strlen($file < 255) &&
+ (!file_exists($file) || !@is_file($file))) {
+ $ret = PEAR::raiseError("could not open file \"$file\"");
+ return $ret;
+ }
+
+ $file = realpath($file);
+ $ret = PEAR::raiseError("Could not get contents of package \"$file\"".
+ '. Invalid tgz file.');
+ return $ret;
+ }
+
+ if (!count($content) && !@is_file($file)) {
+ $ret = PEAR::raiseError("could not open file \"$file\"");
+ return $ret;
+ }
+
+ $xml = null;
+ $origfile = $file;
+ foreach ($content as $file) {
+ $name = $file['filename'];
+ if ($name == 'package2.xml') { // allow a .tgz to distribute both versions
+ $xml = $name;
+ break;
+ }
+
+ if ($name == 'package.xml') {
+ $xml = $name;
+ break;
+ } elseif (preg_match('/package.xml$/', $name, $match)) {
+ $xml = $name;
+ break;
+ }
+ }
+
+ $tmpdir = System::mktemp('-t "' . $this->_config->get('temp_dir') . '" -d pear');
+ if ($tmpdir === false) {
+ $ret = PEAR::raiseError("there was a problem with getting the configured temp directory");
+ return $ret;
+ }
+
+ PEAR_PackageFile::addTempFile($tmpdir);
+
+ $this->_extractErrors();
+ PEAR::staticPushErrorHandling(PEAR_ERROR_CALLBACK, array($this, '_extractErrors'));
+
+ if (!$xml || !$tar->extractList(array($xml), $tmpdir)) {
+ $extra = implode("\n", $this->_extractErrors());
+ if ($extra) {
+ $extra = ' ' . $extra;
+ }
+
+ PEAR::staticPopErrorHandling();
+ $ret = PEAR::raiseError('could not extract the package.xml file from "' .
+ $origfile . '"' . $extra);
+ return $ret;
+ }
+
+ PEAR::staticPopErrorHandling();
+ $ret = &PEAR_PackageFile::fromPackageFile("$tmpdir/$xml", $state, $origfile);
+ return $ret;
+ }
+
+ /**
+ * helper callback for extracting Archive_Tar errors
+ *
+ * @param PEAR_Error|null $err
+ * @return array
+ * @access private
+ */
+ function _extractErrors($err = null)
+ {
+ static $errors = array();
+ if ($err === null) {
+ $e = $errors;
+ $errors = array();
+ return $e;
+ }
+ $errors[] = $err->getMessage();
+ }
+
+ /**
+ * Create a PEAR_PackageFile_v* from a package.xml file.
+ *
+ * @access public
+ * @param string $descfile name of package xml file
+ * @param int $state package state (one of PEAR_VALIDATE_* constants)
+ * @param string|false $archive name of the archive this package.xml came
+ * from, if any
+ * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2
+ * @uses PEAR_PackageFile::fromXmlString to create the oject after the
+ * XML is loaded from the package.xml file.
+ */
+ function &fromPackageFile($descfile, $state, $archive = false)
+ {
+ $fp = false;
+ if (is_string($descfile) && strlen($descfile) < 255 &&
+ (
+ !file_exists($descfile) || !is_file($descfile) || !is_readable($descfile)
+ || (!$fp = @fopen($descfile, 'r'))
+ )
+ ) {
+ $a = PEAR::raiseError("Unable to open $descfile");
+ return $a;
+ }
+
+ // read the whole thing so we only get one cdata callback
+ // for each block of cdata
+ fclose($fp);
+ $data = file_get_contents($descfile);
+ $ret = &PEAR_PackageFile::fromXmlString($data, $state, $descfile, $archive);
+ return $ret;
+ }
+
+ /**
+ * Create a PEAR_PackageFile_v* from a .tgz archive or package.xml file.
+ *
+ * This method is able to extract information about a package from a .tgz
+ * archive or from a XML package definition file.
+ *
+ * @access public
+ * @param string $info file name
+ * @param int $state package state (one of PEAR_VALIDATE_* constants)
+ * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2
+ * @uses fromPackageFile() if the file appears to be XML
+ * @uses fromTgzFile() to load all non-XML files
+ */
+ function &fromAnyFile($info, $state)
+ {
+ if (is_dir($info)) {
+ $dir_name = realpath($info);
+ if (file_exists($dir_name . '/package.xml')) {
+ $info = PEAR_PackageFile::fromPackageFile($dir_name . '/package.xml', $state);
+ } elseif (file_exists($dir_name . '/package2.xml')) {
+ $info = PEAR_PackageFile::fromPackageFile($dir_name . '/package2.xml', $state);
+ } else {
+ $info = PEAR::raiseError("No package definition found in '$info' directory");
+ }
+
+ return $info;
+ }
+
+ $fp = false;
+ if (is_string($info) && strlen($info) < 255 &&
+ (file_exists($info) || ($fp = @fopen($info, 'r')))
+ ) {
+
+ if ($fp) {
+ fclose($fp);
+ }
+
+ $tmp = substr($info, -4);
+ if ($tmp == '.xml') {
+ $info = &PEAR_PackageFile::fromPackageFile($info, $state);
+ } elseif ($tmp == '.tar' || $tmp == '.tgz') {
+ $info = &PEAR_PackageFile::fromTgzFile($info, $state);
+ } else {
+ $fp = fopen($info, 'r');
+ $test = fread($fp, 5);
+ fclose($fp);
+ if ($test == '
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+/**
+ * needed for PEAR_VALIDATE_* constants
+ */
+require_once 'PEAR/Validate.php';
+require_once 'System.php';
+require_once 'PEAR/PackageFile/v2.php';
+/**
+ * This class converts a PEAR_PackageFile_v1 object into any output format.
+ *
+ * Supported output formats include array, XML string, and a PEAR_PackageFile_v2
+ * object, for converting package.xml 1.0 into package.xml 2.0 with no sweat.
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_PackageFile_Generator_v1
+{
+ /**
+ * @var PEAR_PackageFile_v1
+ */
+ var $_packagefile;
+ function __construct(&$packagefile)
+ {
+ $this->_packagefile = &$packagefile;
+ }
+
+ function getPackagerVersion()
+ {
+ return '1.10.3';
+ }
+
+ /**
+ * @param PEAR_Packager
+ * @param bool if true, a .tgz is written, otherwise a .tar is written
+ * @param string|null directory in which to save the .tgz
+ * @return string|PEAR_Error location of package or error object
+ */
+ function toTgz(&$packager, $compress = true, $where = null)
+ {
+ require_once 'Archive/Tar.php';
+ if ($where === null) {
+ if (!($where = System::mktemp(array('-d')))) {
+ return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: mktemp failed');
+ }
+ } elseif (!@System::mkDir(array('-p', $where))) {
+ return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: "' . $where . '" could' .
+ ' not be created');
+ }
+ if (file_exists($where . DIRECTORY_SEPARATOR . 'package.xml') &&
+ !is_file($where . DIRECTORY_SEPARATOR . 'package.xml')) {
+ return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: unable to save package.xml as' .
+ ' "' . $where . DIRECTORY_SEPARATOR . 'package.xml"');
+ }
+ if (!$this->_packagefile->validate(PEAR_VALIDATE_PACKAGING)) {
+ return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: invalid package file');
+ }
+ $pkginfo = $this->_packagefile->getArray();
+ $ext = $compress ? '.tgz' : '.tar';
+ $pkgver = $pkginfo['package'] . '-' . $pkginfo['version'];
+ $dest_package = getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext;
+ if (file_exists(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext) &&
+ !is_file(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext)) {
+ return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: cannot create tgz file "' .
+ getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext . '"');
+ }
+ if ($pkgfile = $this->_packagefile->getPackageFile()) {
+ $pkgdir = dirname(realpath($pkgfile));
+ $pkgfile = basename($pkgfile);
+ } else {
+ return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: package file object must ' .
+ 'be created from a real file');
+ }
+ // {{{ Create the package file list
+ $filelist = array();
+ $i = 0;
+
+ foreach ($this->_packagefile->getFilelist() as $fname => $atts) {
+ $file = $pkgdir . DIRECTORY_SEPARATOR . $fname;
+ if (!file_exists($file)) {
+ return PEAR::raiseError("File does not exist: $fname");
+ } else {
+ $filelist[$i++] = $file;
+ if (!isset($atts['md5sum'])) {
+ $this->_packagefile->setFileAttribute($fname, 'md5sum', md5_file($file));
+ }
+ $packager->log(2, "Adding file $fname");
+ }
+ }
+ // }}}
+ $packagexml = $this->toPackageFile($where, PEAR_VALIDATE_PACKAGING, 'package.xml', true);
+ if ($packagexml) {
+ $tar = new Archive_Tar($dest_package, $compress);
+ $tar->setErrorHandling(PEAR_ERROR_RETURN); // XXX Don't print errors
+ // ----- Creates with the package.xml file
+ $ok = $tar->createModify(array($packagexml), '', $where);
+ if (PEAR::isError($ok)) {
+ return $ok;
+ } elseif (!$ok) {
+ return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: tarball creation failed');
+ }
+ // ----- Add the content of the package
+ if (!$tar->addModify($filelist, $pkgver, $pkgdir)) {
+ return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: tarball creation failed');
+ }
+ return $dest_package;
+ }
+ }
+
+ /**
+ * @param string|null directory to place the package.xml in, or null for a temporary dir
+ * @param int one of the PEAR_VALIDATE_* constants
+ * @param string name of the generated file
+ * @param bool if true, then no analysis will be performed on role="php" files
+ * @return string|PEAR_Error path to the created file on success
+ */
+ function toPackageFile($where = null, $state = PEAR_VALIDATE_NORMAL, $name = 'package.xml',
+ $nofilechecking = false)
+ {
+ if (!$this->_packagefile->validate($state, $nofilechecking)) {
+ return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: invalid package.xml',
+ null, null, null, $this->_packagefile->getValidationWarnings());
+ }
+ if ($where === null) {
+ if (!($where = System::mktemp(array('-d')))) {
+ return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: mktemp failed');
+ }
+ } elseif (!@System::mkDir(array('-p', $where))) {
+ return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: "' . $where . '" could' .
+ ' not be created');
+ }
+ $newpkgfile = $where . DIRECTORY_SEPARATOR . $name;
+ $np = @fopen($newpkgfile, 'wb');
+ if (!$np) {
+ return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: unable to save ' .
+ "$name as $newpkgfile");
+ }
+ fwrite($np, $this->toXml($state, true));
+ fclose($np);
+ return $newpkgfile;
+ }
+
+ /**
+ * fix both XML encoding to be UTF8, and replace standard XML entities < > " & '
+ *
+ * @param string $string
+ * @return string
+ * @access private
+ */
+ function _fixXmlEncoding($string)
+ {
+ return strtr($string, array(
+ '&' => '&',
+ '>' => '>',
+ '<' => '<',
+ '"' => '"',
+ '\'' => ''' ));
+ }
+
+ /**
+ * Return an XML document based on the package info (as returned
+ * by the PEAR_Common::infoFrom* methods).
+ *
+ * @return string XML data
+ */
+ function toXml($state = PEAR_VALIDATE_NORMAL, $nofilevalidation = false)
+ {
+ $this->_packagefile->setDate(date('Y-m-d'));
+ if (!$this->_packagefile->validate($state, $nofilevalidation)) {
+ return false;
+ }
+ $pkginfo = $this->_packagefile->getArray();
+ static $maint_map = array(
+ "handle" => "user",
+ "name" => "name",
+ "email" => "email",
+ "role" => "role",
+ );
+ $ret = "\n";
+ $ret .= "\n";
+ $ret .= "\n" .
+" $pkginfo[package]";
+ if (isset($pkginfo['extends'])) {
+ $ret .= "\n$pkginfo[extends]";
+ }
+ $ret .=
+ "\n ".$this->_fixXmlEncoding($pkginfo['summary'])."\n" .
+" ".trim($this->_fixXmlEncoding($pkginfo['description']))."\n \n" .
+" \n";
+ foreach ($pkginfo['maintainers'] as $maint) {
+ $ret .= " \n";
+ foreach ($maint_map as $idx => $elm) {
+ $ret .= " <$elm>";
+ $ret .= $this->_fixXmlEncoding($maint[$idx]);
+ $ret .= "$elm>\n";
+ }
+ $ret .= " \n";
+ }
+ $ret .= " \n";
+ $ret .= $this->_makeReleaseXml($pkginfo, false, $state);
+ if (isset($pkginfo['changelog']) && count($pkginfo['changelog']) > 0) {
+ $ret .= " \n";
+ foreach ($pkginfo['changelog'] as $oldrelease) {
+ $ret .= $this->_makeReleaseXml($oldrelease, true);
+ }
+ $ret .= " \n";
+ }
+ $ret .= "\n";
+ return $ret;
+ }
+
+ // }}}
+ // {{{ _makeReleaseXml()
+
+ /**
+ * Generate part of an XML description with release information.
+ *
+ * @param array $pkginfo array with release information
+ * @param bool $changelog whether the result will be in a changelog element
+ *
+ * @return string XML data
+ *
+ * @access private
+ */
+ function _makeReleaseXml($pkginfo, $changelog = false, $state = PEAR_VALIDATE_NORMAL)
+ {
+ // XXX QUOTE ENTITIES IN PCDATA, OR EMBED IN CDATA BLOCKS!!
+ $indent = $changelog ? " " : "";
+ $ret = "$indent \n";
+ if (!empty($pkginfo['version'])) {
+ $ret .= "$indent $pkginfo[version]\n";
+ }
+ if (!empty($pkginfo['release_date'])) {
+ $ret .= "$indent $pkginfo[release_date]\n";
+ }
+ if (!empty($pkginfo['release_license'])) {
+ $ret .= "$indent $pkginfo[release_license]\n";
+ }
+ if (!empty($pkginfo['release_state'])) {
+ $ret .= "$indent $pkginfo[release_state]\n";
+ }
+ if (!empty($pkginfo['release_notes'])) {
+ $ret .= "$indent ".trim($this->_fixXmlEncoding($pkginfo['release_notes']))
+ ."\n$indent \n";
+ }
+ if (!empty($pkginfo['release_warnings'])) {
+ $ret .= "$indent ".$this->_fixXmlEncoding($pkginfo['release_warnings'])."\n";
+ }
+ if (isset($pkginfo['release_deps']) && sizeof($pkginfo['release_deps']) > 0) {
+ $ret .= "$indent \n";
+ foreach ($pkginfo['release_deps'] as $dep) {
+ $ret .= "$indent _fixXmlEncoding($c['name']) . "\"";
+ if (isset($c['default'])) {
+ $ret .= " default=\"" . $this->_fixXmlEncoding($c['default']) . "\"";
+ }
+ $ret .= " prompt=\"" . $this->_fixXmlEncoding($c['prompt']) . "\"";
+ $ret .= "/>\n";
+ }
+ $ret .= "$indent \n";
+ }
+ if (isset($pkginfo['provides'])) {
+ foreach ($pkginfo['provides'] as $key => $what) {
+ $ret .= "$indent recursiveXmlFilelist($pkginfo['filelist']);
+ } else {
+ foreach ($pkginfo['filelist'] as $file => $fa) {
+ if (!isset($fa['role'])) {
+ $fa['role'] = '';
+ }
+ $ret .= "$indent _fixXmlEncoding($fa['baseinstalldir']) . '"';
+ }
+ if (isset($fa['md5sum'])) {
+ $ret .= " md5sum=\"$fa[md5sum]\"";
+ }
+ if (isset($fa['platform'])) {
+ $ret .= " platform=\"$fa[platform]\"";
+ }
+ if (!empty($fa['install-as'])) {
+ $ret .= ' install-as="' .
+ $this->_fixXmlEncoding($fa['install-as']) . '"';
+ }
+ $ret .= ' name="' . $this->_fixXmlEncoding($file) . '"';
+ if (empty($fa['replacements'])) {
+ $ret .= "/>\n";
+ } else {
+ $ret .= ">\n";
+ foreach ($fa['replacements'] as $r) {
+ $ret .= "$indent $v) {
+ $ret .= " $k=\"" . $this->_fixXmlEncoding($v) .'"';
+ }
+ $ret .= "/>\n";
+ }
+ $ret .= "$indent \n";
+ }
+ }
+ }
+ $ret .= "$indent \n";
+ }
+ $ret .= "$indent \n";
+ return $ret;
+ }
+
+ /**
+ * @param array
+ * @access protected
+ */
+ function recursiveXmlFilelist($list)
+ {
+ $this->_dirs = array();
+ foreach ($list as $file => $attributes) {
+ $this->_addDir($this->_dirs, explode('/', dirname($file)), $file, $attributes);
+ }
+ return $this->_formatDir($this->_dirs);
+ }
+
+ /**
+ * @param array
+ * @param array
+ * @param string|null
+ * @param array|null
+ * @access private
+ */
+ function _addDir(&$dirs, $dir, $file = null, $attributes = null)
+ {
+ if ($dir == array() || $dir == array('.')) {
+ $dirs['files'][basename($file)] = $attributes;
+ return;
+ }
+ $curdir = array_shift($dir);
+ if (!isset($dirs['dirs'][$curdir])) {
+ $dirs['dirs'][$curdir] = array();
+ }
+ $this->_addDir($dirs['dirs'][$curdir], $dir, $file, $attributes);
+ }
+
+ /**
+ * @param array
+ * @param string
+ * @param string
+ * @access private
+ */
+ function _formatDir($dirs, $indent = '', $curdir = '')
+ {
+ $ret = '';
+ if (!count($dirs)) {
+ return '';
+ }
+ if (isset($dirs['dirs'])) {
+ uksort($dirs['dirs'], 'strnatcasecmp');
+ foreach ($dirs['dirs'] as $dir => $contents) {
+ $usedir = "$curdir/$dir";
+ $ret .= "$indent \n";
+ $ret .= $this->_formatDir($contents, "$indent ", $usedir);
+ $ret .= "$indent \n";
+ }
+ }
+ if (isset($dirs['files'])) {
+ uksort($dirs['files'], 'strnatcasecmp');
+ foreach ($dirs['files'] as $file => $attribs) {
+ $ret .= $this->_formatFile($file, $attribs, $indent);
+ }
+ }
+ return $ret;
+ }
+
+ /**
+ * @param string
+ * @param array
+ * @param string
+ * @access private
+ */
+ function _formatFile($file, $attributes, $indent)
+ {
+ $ret = "$indent _fixXmlEncoding($attributes['baseinstalldir']) . '"';
+ }
+ if (isset($attributes['md5sum'])) {
+ $ret .= " md5sum=\"$attributes[md5sum]\"";
+ }
+ if (isset($attributes['platform'])) {
+ $ret .= " platform=\"$attributes[platform]\"";
+ }
+ if (!empty($attributes['install-as'])) {
+ $ret .= ' install-as="' .
+ $this->_fixXmlEncoding($attributes['install-as']) . '"';
+ }
+ $ret .= ' name="' . $this->_fixXmlEncoding($file) . '"';
+ if (empty($attributes['replacements'])) {
+ $ret .= "/>\n";
+ } else {
+ $ret .= ">\n";
+ foreach ($attributes['replacements'] as $r) {
+ $ret .= "$indent $v) {
+ $ret .= " $k=\"" . $this->_fixXmlEncoding($v) .'"';
+ }
+ $ret .= "/>\n";
+ }
+ $ret .= "$indent \n";
+ }
+ return $ret;
+ }
+
+ // {{{ _unIndent()
+
+ /**
+ * Unindent given string (?)
+ *
+ * @param string $str The string that has to be unindented.
+ * @return string
+ * @access private
+ */
+ function _unIndent($str)
+ {
+ // remove leading newlines
+ $str = preg_replace('/^[\r\n]+/', '', $str);
+ // find whitespace at the beginning of the first line
+ $indent_len = strspn($str, " \t");
+ $indent = substr($str, 0, $indent_len);
+ $data = '';
+ // remove the same amount of whitespace from following lines
+ foreach (explode("\n", $str) as $line) {
+ if (substr($line, 0, $indent_len) == $indent) {
+ $data .= substr($line, $indent_len) . "\n";
+ }
+ }
+ return $data;
+ }
+
+ /**
+ * @return array
+ */
+ function dependenciesToV2()
+ {
+ $arr = array();
+ $this->_convertDependencies2_0($arr);
+ return $arr['dependencies'];
+ }
+
+ /**
+ * Convert a package.xml version 1.0 into version 2.0
+ *
+ * Note that this does a basic conversion, to allow more advanced
+ * features like bundles and multiple releases
+ * @param string the classname to instantiate and return. This must be
+ * PEAR_PackageFile_v2 or a descendant
+ * @param boolean if true, only valid, deterministic package.xml 1.0 as defined by the
+ * strictest parameters will be converted
+ * @return PEAR_PackageFile_v2|PEAR_Error
+ */
+ function &toV2($class = 'PEAR_PackageFile_v2', $strict = false)
+ {
+ if ($strict) {
+ if (!$this->_packagefile->validate()) {
+ $a = PEAR::raiseError('invalid package.xml version 1.0 cannot be converted' .
+ ' to version 2.0', null, null, null,
+ $this->_packagefile->getValidationWarnings(true));
+ return $a;
+ }
+ }
+
+ $arr = array(
+ 'attribs' => array(
+ 'version' => '2.0',
+ 'xmlns' => 'http://pear.php.net/dtd/package-2.0',
+ 'xmlns:tasks' => 'http://pear.php.net/dtd/tasks-1.0',
+ 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
+ 'xsi:schemaLocation' => "http://pear.php.net/dtd/tasks-1.0\n" .
+"http://pear.php.net/dtd/tasks-1.0.xsd\n" .
+"http://pear.php.net/dtd/package-2.0\n" .
+'http://pear.php.net/dtd/package-2.0.xsd',
+ ),
+ 'name' => $this->_packagefile->getPackage(),
+ 'channel' => 'pear.php.net',
+ );
+ $arr['summary'] = $this->_packagefile->getSummary();
+ $arr['description'] = $this->_packagefile->getDescription();
+ $maintainers = $this->_packagefile->getMaintainers();
+ foreach ($maintainers as $maintainer) {
+ if ($maintainer['role'] != 'lead') {
+ continue;
+ }
+ $new = array(
+ 'name' => $maintainer['name'],
+ 'user' => $maintainer['handle'],
+ 'email' => $maintainer['email'],
+ 'active' => 'yes',
+ );
+ $arr['lead'][] = $new;
+ }
+
+ if (!isset($arr['lead'])) { // some people... you know?
+ $arr['lead'] = array(
+ 'name' => 'unknown',
+ 'user' => 'unknown',
+ 'email' => 'noleadmaintainer@example.com',
+ 'active' => 'no',
+ );
+ }
+
+ if (count($arr['lead']) == 1) {
+ $arr['lead'] = $arr['lead'][0];
+ }
+
+ foreach ($maintainers as $maintainer) {
+ if ($maintainer['role'] == 'lead') {
+ continue;
+ }
+ $new = array(
+ 'name' => $maintainer['name'],
+ 'user' => $maintainer['handle'],
+ 'email' => $maintainer['email'],
+ 'active' => 'yes',
+ );
+ $arr[$maintainer['role']][] = $new;
+ }
+
+ if (isset($arr['developer']) && count($arr['developer']) == 1) {
+ $arr['developer'] = $arr['developer'][0];
+ }
+
+ if (isset($arr['contributor']) && count($arr['contributor']) == 1) {
+ $arr['contributor'] = $arr['contributor'][0];
+ }
+
+ if (isset($arr['helper']) && count($arr['helper']) == 1) {
+ $arr['helper'] = $arr['helper'][0];
+ }
+
+ $arr['date'] = $this->_packagefile->getDate();
+ $arr['version'] =
+ array(
+ 'release' => $this->_packagefile->getVersion(),
+ 'api' => $this->_packagefile->getVersion(),
+ );
+ $arr['stability'] =
+ array(
+ 'release' => $this->_packagefile->getState(),
+ 'api' => $this->_packagefile->getState(),
+ );
+ $licensemap =
+ array(
+ 'php' => 'http://www.php.net/license',
+ 'php license' => 'http://www.php.net/license',
+ 'lgpl' => 'http://www.gnu.org/copyleft/lesser.html',
+ 'bsd' => 'http://www.opensource.org/licenses/bsd-license.php',
+ 'bsd style' => 'http://www.opensource.org/licenses/bsd-license.php',
+ 'bsd-style' => 'http://www.opensource.org/licenses/bsd-license.php',
+ 'mit' => 'http://www.opensource.org/licenses/mit-license.php',
+ 'gpl' => 'http://www.gnu.org/copyleft/gpl.html',
+ 'apache' => 'http://www.opensource.org/licenses/apache2.0.php'
+ );
+
+ if (isset($licensemap[strtolower($this->_packagefile->getLicense())])) {
+ $arr['license'] = array(
+ 'attribs' => array('uri' =>
+ $licensemap[strtolower($this->_packagefile->getLicense())]),
+ '_content' => $this->_packagefile->getLicense()
+ );
+ } else {
+ // don't use bogus uri
+ $arr['license'] = $this->_packagefile->getLicense();
+ }
+
+ $arr['notes'] = $this->_packagefile->getNotes();
+ $temp = array();
+ $arr['contents'] = $this->_convertFilelist2_0($temp);
+ $this->_convertDependencies2_0($arr);
+ $release = ($this->_packagefile->getConfigureOptions() || $this->_isExtension) ?
+ 'extsrcrelease' : 'phprelease';
+ if ($release == 'extsrcrelease') {
+ $arr['channel'] = 'pecl.php.net';
+ $arr['providesextension'] = $arr['name']; // assumption
+ }
+
+ $arr[$release] = array();
+ if ($this->_packagefile->getConfigureOptions()) {
+ $arr[$release]['configureoption'] = $this->_packagefile->getConfigureOptions();
+ foreach ($arr[$release]['configureoption'] as $i => $opt) {
+ $arr[$release]['configureoption'][$i] = array('attribs' => $opt);
+ }
+ if (count($arr[$release]['configureoption']) == 1) {
+ $arr[$release]['configureoption'] = $arr[$release]['configureoption'][0];
+ }
+ }
+
+ $this->_convertRelease2_0($arr[$release], $temp);
+ if ($release == 'extsrcrelease' && count($arr[$release]) > 1) {
+ // multiple extsrcrelease tags added in PEAR 1.4.1
+ $arr['dependencies']['required']['pearinstaller']['min'] = '1.4.1';
+ }
+
+ if ($cl = $this->_packagefile->getChangelog()) {
+ foreach ($cl as $release) {
+ $rel = array();
+ $rel['version'] =
+ array(
+ 'release' => $release['version'],
+ 'api' => $release['version'],
+ );
+ if (!isset($release['release_state'])) {
+ $release['release_state'] = 'stable';
+ }
+
+ $rel['stability'] =
+ array(
+ 'release' => $release['release_state'],
+ 'api' => $release['release_state'],
+ );
+ if (isset($release['release_date'])) {
+ $rel['date'] = $release['release_date'];
+ } else {
+ $rel['date'] = date('Y-m-d');
+ }
+
+ if (isset($release['release_license'])) {
+ if (isset($licensemap[strtolower($release['release_license'])])) {
+ $uri = $licensemap[strtolower($release['release_license'])];
+ } else {
+ $uri = 'http://www.example.com';
+ }
+ $rel['license'] = array(
+ 'attribs' => array('uri' => $uri),
+ '_content' => $release['release_license']
+ );
+ } else {
+ $rel['license'] = $arr['license'];
+ }
+
+ if (!isset($release['release_notes'])) {
+ $release['release_notes'] = 'no release notes';
+ }
+
+ $rel['notes'] = $release['release_notes'];
+ $arr['changelog']['release'][] = $rel;
+ }
+ }
+
+ $ret = new $class;
+ $ret->setConfig($this->_packagefile->_config);
+ if (isset($this->_packagefile->_logger) && is_object($this->_packagefile->_logger)) {
+ $ret->setLogger($this->_packagefile->_logger);
+ }
+
+ $ret->fromArray($arr);
+ return $ret;
+ }
+
+ /**
+ * @param array
+ * @param bool
+ * @access private
+ */
+ function _convertDependencies2_0(&$release, $internal = false)
+ {
+ $peardep = array('pearinstaller' =>
+ array('min' => '1.4.0b1')); // this is a lot safer
+ $required = $optional = array();
+ $release['dependencies'] = array('required' => array());
+ if ($this->_packagefile->hasDeps()) {
+ foreach ($this->_packagefile->getDeps() as $dep) {
+ if (!isset($dep['optional']) || $dep['optional'] == 'no') {
+ $required[] = $dep;
+ } else {
+ $optional[] = $dep;
+ }
+ }
+ foreach (array('required', 'optional') as $arr) {
+ $deps = array();
+ foreach ($$arr as $dep) {
+ // organize deps by dependency type and name
+ if (!isset($deps[$dep['type']])) {
+ $deps[$dep['type']] = array();
+ }
+ if (isset($dep['name'])) {
+ $deps[$dep['type']][$dep['name']][] = $dep;
+ } else {
+ $deps[$dep['type']][] = $dep;
+ }
+ }
+ do {
+ if (isset($deps['php'])) {
+ $php = array();
+ if (count($deps['php']) > 1) {
+ $php = $this->_processPhpDeps($deps['php']);
+ } else {
+ if (!isset($deps['php'][0])) {
+ list($key, $blah) = each ($deps['php']); // stupid buggy versions
+ $deps['php'] = array($blah[0]);
+ }
+ $php = $this->_processDep($deps['php'][0]);
+ if (!$php) {
+ break; // poor mans throw
+ }
+ }
+ $release['dependencies'][$arr]['php'] = $php;
+ }
+ } while (false);
+ do {
+ if (isset($deps['pkg'])) {
+ $pkg = array();
+ $pkg = $this->_processMultipleDepsName($deps['pkg']);
+ if (!$pkg) {
+ break; // poor mans throw
+ }
+ $release['dependencies'][$arr]['package'] = $pkg;
+ }
+ } while (false);
+ do {
+ if (isset($deps['ext'])) {
+ $pkg = array();
+ $pkg = $this->_processMultipleDepsName($deps['ext']);
+ $release['dependencies'][$arr]['extension'] = $pkg;
+ }
+ } while (false);
+ // skip sapi - it's not supported so nobody will have used it
+ // skip os - it's not supported in 1.0
+ }
+ }
+ if (isset($release['dependencies']['required'])) {
+ $release['dependencies']['required'] =
+ array_merge($peardep, $release['dependencies']['required']);
+ } else {
+ $release['dependencies']['required'] = $peardep;
+ }
+ if (!isset($release['dependencies']['required']['php'])) {
+ $release['dependencies']['required']['php'] =
+ array('min' => '4.0.0');
+ }
+ $order = array();
+ $bewm = $release['dependencies']['required'];
+ $order['php'] = $bewm['php'];
+ $order['pearinstaller'] = $bewm['pearinstaller'];
+ isset($bewm['package']) ? $order['package'] = $bewm['package'] :0;
+ isset($bewm['extension']) ? $order['extension'] = $bewm['extension'] :0;
+ $release['dependencies']['required'] = $order;
+ }
+
+ /**
+ * @param array
+ * @access private
+ */
+ function _convertFilelist2_0(&$package)
+ {
+ $ret = array('dir' =>
+ array(
+ 'attribs' => array('name' => '/'),
+ 'file' => array()
+ )
+ );
+ $package['platform'] =
+ $package['install-as'] = array();
+ $this->_isExtension = false;
+ foreach ($this->_packagefile->getFilelist() as $name => $file) {
+ $file['name'] = $name;
+ if (isset($file['role']) && $file['role'] == 'src') {
+ $this->_isExtension = true;
+ }
+ if (isset($file['replacements'])) {
+ $repl = $file['replacements'];
+ unset($file['replacements']);
+ } else {
+ unset($repl);
+ }
+ if (isset($file['install-as'])) {
+ $package['install-as'][$name] = $file['install-as'];
+ unset($file['install-as']);
+ }
+ if (isset($file['platform'])) {
+ $package['platform'][$name] = $file['platform'];
+ unset($file['platform']);
+ }
+ $file = array('attribs' => $file);
+ if (isset($repl)) {
+ foreach ($repl as $replace ) {
+ $file['tasks:replace'][] = array('attribs' => $replace);
+ }
+ if (count($repl) == 1) {
+ $file['tasks:replace'] = $file['tasks:replace'][0];
+ }
+ }
+ $ret['dir']['file'][] = $file;
+ }
+ return $ret;
+ }
+
+ /**
+ * Post-process special files with install-as/platform attributes and
+ * make the release tag.
+ *
+ * This complex method follows this work-flow to create the release tags:
+ *
+ *
+ * - if any install-as/platform exist, create a generic release and fill it with
+ * o tags for
+ * o tags for
+ * o tags for
+ * o tags for
+ * - create a release for each platform encountered and fill with
+ * o tags for
+ * o tags for
+ * o tags for
+ * o tags for
+ * o tags for
+ * o tags for
+ * o tags for
+ *
+ *
+ * It does this by accessing the $package parameter, which contains an array with
+ * indices:
+ *
+ * - platform: mapping of file => OS the file should be installed on
+ * - install-as: mapping of file => installed name
+ * - osmap: mapping of OS => list of files that should be installed
+ * on that OS
+ * - notosmap: mapping of OS => list of files that should not be
+ * installed on that OS
+ *
+ * @param array
+ * @param array
+ * @access private
+ */
+ function _convertRelease2_0(&$release, $package)
+ {
+ //- if any install-as/platform exist, create a generic release and fill it with
+ if (count($package['platform']) || count($package['install-as'])) {
+ $generic = array();
+ $genericIgnore = array();
+ foreach ($package['install-as'] as $file => $as) {
+ //o tags for
+ if (!isset($package['platform'][$file])) {
+ $generic[] = $file;
+ continue;
+ }
+ //o tags for
+ if (isset($package['platform'][$file]) &&
+ $package['platform'][$file]{0} == '!') {
+ $generic[] = $file;
+ continue;
+ }
+ //o tags for
+ if (isset($package['platform'][$file]) &&
+ $package['platform'][$file]{0} != '!') {
+ $genericIgnore[] = $file;
+ continue;
+ }
+ }
+ foreach ($package['platform'] as $file => $platform) {
+ if (isset($package['install-as'][$file])) {
+ continue;
+ }
+ if ($platform{0} != '!') {
+ //o tags for
+ $genericIgnore[] = $file;
+ }
+ }
+ if (count($package['platform'])) {
+ $oses = $notplatform = $platform = array();
+ foreach ($package['platform'] as $file => $os) {
+ // get a list of oses
+ if ($os{0} == '!') {
+ if (isset($oses[substr($os, 1)])) {
+ continue;
+ }
+ $oses[substr($os, 1)] = count($oses);
+ } else {
+ if (isset($oses[$os])) {
+ continue;
+ }
+ $oses[$os] = count($oses);
+ }
+ }
+ //- create a release for each platform encountered and fill with
+ foreach ($oses as $os => $releaseNum) {
+ $release[$releaseNum]['installconditions']['os']['name'] = $os;
+ $release[$releaseNum]['filelist'] = array('install' => array(),
+ 'ignore' => array());
+ foreach ($package['install-as'] as $file => $as) {
+ //o tags for
+ if (!isset($package['platform'][$file])) {
+ $release[$releaseNum]['filelist']['install'][] =
+ array(
+ 'attribs' => array(
+ 'name' => $file,
+ 'as' => $as,
+ ),
+ );
+ continue;
+ }
+ //o tags for
+ //
+ if (isset($package['platform'][$file]) &&
+ $package['platform'][$file] == $os) {
+ $release[$releaseNum]['filelist']['install'][] =
+ array(
+ 'attribs' => array(
+ 'name' => $file,
+ 'as' => $as,
+ ),
+ );
+ continue;
+ }
+ //o tags for
+ //
+ if (isset($package['platform'][$file]) &&
+ $package['platform'][$file] != "!$os" &&
+ $package['platform'][$file]{0} == '!') {
+ $release[$releaseNum]['filelist']['install'][] =
+ array(
+ 'attribs' => array(
+ 'name' => $file,
+ 'as' => $as,
+ ),
+ );
+ continue;
+ }
+ //o tags for
+ //
+ if (isset($package['platform'][$file]) &&
+ $package['platform'][$file] == "!$os") {
+ $release[$releaseNum]['filelist']['ignore'][] =
+ array(
+ 'attribs' => array(
+ 'name' => $file,
+ ),
+ );
+ continue;
+ }
+ //o tags for
+ //
+ if (isset($package['platform'][$file]) &&
+ $package['platform'][$file]{0} != '!' &&
+ $package['platform'][$file] != $os) {
+ $release[$releaseNum]['filelist']['ignore'][] =
+ array(
+ 'attribs' => array(
+ 'name' => $file,
+ ),
+ );
+ continue;
+ }
+ }
+ foreach ($package['platform'] as $file => $platform) {
+ if (isset($package['install-as'][$file])) {
+ continue;
+ }
+ //o tags for
+ if ($platform == "!$os") {
+ $release[$releaseNum]['filelist']['ignore'][] =
+ array(
+ 'attribs' => array(
+ 'name' => $file,
+ ),
+ );
+ continue;
+ }
+ //o tags for
+ if ($platform{0} != '!' && $platform != $os) {
+ $release[$releaseNum]['filelist']['ignore'][] =
+ array(
+ 'attribs' => array(
+ 'name' => $file,
+ ),
+ );
+ }
+ }
+ if (!count($release[$releaseNum]['filelist']['install'])) {
+ unset($release[$releaseNum]['filelist']['install']);
+ }
+ if (!count($release[$releaseNum]['filelist']['ignore'])) {
+ unset($release[$releaseNum]['filelist']['ignore']);
+ }
+ }
+ if (count($generic) || count($genericIgnore)) {
+ $release[count($oses)] = array();
+ if (count($generic)) {
+ foreach ($generic as $file) {
+ if (isset($package['install-as'][$file])) {
+ $installas = $package['install-as'][$file];
+ } else {
+ $installas = $file;
+ }
+ $release[count($oses)]['filelist']['install'][] =
+ array(
+ 'attribs' => array(
+ 'name' => $file,
+ 'as' => $installas,
+ )
+ );
+ }
+ }
+ if (count($genericIgnore)) {
+ foreach ($genericIgnore as $file) {
+ $release[count($oses)]['filelist']['ignore'][] =
+ array(
+ 'attribs' => array(
+ 'name' => $file,
+ )
+ );
+ }
+ }
+ }
+ // cleanup
+ foreach ($release as $i => $rel) {
+ if (isset($rel['filelist']['install']) &&
+ count($rel['filelist']['install']) == 1) {
+ $release[$i]['filelist']['install'] =
+ $release[$i]['filelist']['install'][0];
+ }
+ if (isset($rel['filelist']['ignore']) &&
+ count($rel['filelist']['ignore']) == 1) {
+ $release[$i]['filelist']['ignore'] =
+ $release[$i]['filelist']['ignore'][0];
+ }
+ }
+ if (count($release) == 1) {
+ $release = $release[0];
+ }
+ } else {
+ // no platform atts, but some install-as atts
+ foreach ($package['install-as'] as $file => $value) {
+ $release['filelist']['install'][] =
+ array(
+ 'attribs' => array(
+ 'name' => $file,
+ 'as' => $value
+ )
+ );
+ }
+ if (count($release['filelist']['install']) == 1) {
+ $release['filelist']['install'] = $release['filelist']['install'][0];
+ }
+ }
+ }
+ }
+
+ /**
+ * @param array
+ * @return array
+ * @access private
+ */
+ function _processDep($dep)
+ {
+ if ($dep['type'] == 'php') {
+ if ($dep['rel'] == 'has') {
+ // come on - everyone has php!
+ return false;
+ }
+ }
+ $php = array();
+ if ($dep['type'] != 'php') {
+ $php['name'] = $dep['name'];
+ if ($dep['type'] == 'pkg') {
+ $php['channel'] = 'pear.php.net';
+ }
+ }
+ switch ($dep['rel']) {
+ case 'gt' :
+ $php['min'] = $dep['version'];
+ $php['exclude'] = $dep['version'];
+ break;
+ case 'ge' :
+ if (!isset($dep['version'])) {
+ if ($dep['type'] == 'php') {
+ if (isset($dep['name'])) {
+ $dep['version'] = $dep['name'];
+ }
+ }
+ }
+ $php['min'] = $dep['version'];
+ break;
+ case 'lt' :
+ $php['max'] = $dep['version'];
+ $php['exclude'] = $dep['version'];
+ break;
+ case 'le' :
+ $php['max'] = $dep['version'];
+ break;
+ case 'eq' :
+ $php['min'] = $dep['version'];
+ $php['max'] = $dep['version'];
+ break;
+ case 'ne' :
+ $php['exclude'] = $dep['version'];
+ break;
+ case 'not' :
+ $php['conflicts'] = 'yes';
+ break;
+ }
+ return $php;
+ }
+
+ /**
+ * @param array
+ * @return array
+ */
+ function _processPhpDeps($deps)
+ {
+ $test = array();
+ foreach ($deps as $dep) {
+ $test[] = $this->_processDep($dep);
+ }
+ $min = array();
+ $max = array();
+ foreach ($test as $dep) {
+ if (!$dep) {
+ continue;
+ }
+ if (isset($dep['min'])) {
+ $min[$dep['min']] = count($min);
+ }
+ if (isset($dep['max'])) {
+ $max[$dep['max']] = count($max);
+ }
+ }
+ if (count($min) > 0) {
+ uksort($min, 'version_compare');
+ }
+ if (count($max) > 0) {
+ uksort($max, 'version_compare');
+ }
+ if (count($min)) {
+ // get the highest minimum
+ $a = array_flip($min);
+ $min = array_pop($a);
+ } else {
+ $min = false;
+ }
+ if (count($max)) {
+ // get the lowest maximum
+ $a = array_flip($max);
+ $max = array_shift($a);
+ } else {
+ $max = false;
+ }
+ if ($min) {
+ $php['min'] = $min;
+ }
+ if ($max) {
+ $php['max'] = $max;
+ }
+ $exclude = array();
+ foreach ($test as $dep) {
+ if (!isset($dep['exclude'])) {
+ continue;
+ }
+ $exclude[] = $dep['exclude'];
+ }
+ if (count($exclude)) {
+ $php['exclude'] = $exclude;
+ }
+ return $php;
+ }
+
+ /**
+ * process multiple dependencies that have a name, like package deps
+ * @param array
+ * @return array
+ * @access private
+ */
+ function _processMultipleDepsName($deps)
+ {
+ $ret = $tests = array();
+ foreach ($deps as $name => $dep) {
+ foreach ($dep as $d) {
+ $tests[$name][] = $this->_processDep($d);
+ }
+ }
+
+ foreach ($tests as $name => $test) {
+ $max = $min = $php = array();
+ $php['name'] = $name;
+ foreach ($test as $dep) {
+ if (!$dep) {
+ continue;
+ }
+ if (isset($dep['channel'])) {
+ $php['channel'] = 'pear.php.net';
+ }
+ if (isset($dep['conflicts']) && $dep['conflicts'] == 'yes') {
+ $php['conflicts'] = 'yes';
+ }
+ if (isset($dep['min'])) {
+ $min[$dep['min']] = count($min);
+ }
+ if (isset($dep['max'])) {
+ $max[$dep['max']] = count($max);
+ }
+ }
+ if (count($min) > 0) {
+ uksort($min, 'version_compare');
+ }
+ if (count($max) > 0) {
+ uksort($max, 'version_compare');
+ }
+ if (count($min)) {
+ // get the highest minimum
+ $a = array_flip($min);
+ $min = array_pop($a);
+ } else {
+ $min = false;
+ }
+ if (count($max)) {
+ // get the lowest maximum
+ $a = array_flip($max);
+ $max = array_shift($a);
+ } else {
+ $max = false;
+ }
+ if ($min) {
+ $php['min'] = $min;
+ }
+ if ($max) {
+ $php['max'] = $max;
+ }
+ $exclude = array();
+ foreach ($test as $dep) {
+ if (!isset($dep['exclude'])) {
+ continue;
+ }
+ $exclude[] = $dep['exclude'];
+ }
+ if (count($exclude)) {
+ $php['exclude'] = $exclude;
+ }
+ $ret[] = $php;
+ }
+ return $ret;
+ }
+}
+?>
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/PackageFile/Generator/v2.php b/vendor/pear-pear.php.net/PEAR/PEAR/PackageFile/Generator/v2.php
new file mode 100644
index 000000000..1c97296b7
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/PackageFile/Generator/v2.php
@@ -0,0 +1,886 @@
+
+ * @author Stephan Schmidt (original XML_Serializer code)
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+/**
+ * file/dir manipulation routines
+ */
+require_once 'System.php';
+require_once 'XML/Util.php';
+
+/**
+ * This class converts a PEAR_PackageFile_v2 object into any output format.
+ *
+ * Supported output formats include array, XML string (using S. Schmidt's
+ * XML_Serializer, slightly customized)
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @author Stephan Schmidt (original XML_Serializer code)
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_PackageFile_Generator_v2
+{
+ /**
+ * default options for the serialization
+ * @access private
+ * @var array $_defaultOptions
+ */
+ var $_defaultOptions = array(
+ 'indent' => ' ', // string used for indentation
+ 'linebreak' => "\n", // string used for newlines
+ 'typeHints' => false, // automatically add type hin attributes
+ 'addDecl' => true, // add an XML declaration
+ 'defaultTagName' => 'XML_Serializer_Tag', // tag used for indexed arrays or invalid names
+ 'classAsTagName' => false, // use classname for objects in indexed arrays
+ 'keyAttribute' => '_originalKey', // attribute where original key is stored
+ 'typeAttribute' => '_type', // attribute for type (only if typeHints => true)
+ 'classAttribute' => '_class', // attribute for class of objects (only if typeHints => true)
+ 'scalarAsAttributes' => false, // scalar values (strings, ints,..) will be serialized as attribute
+ 'prependAttributes' => '', // prepend string for attributes
+ 'indentAttributes' => false, // indent the attributes, if set to '_auto', it will indent attributes so they all start at the same column
+ 'mode' => 'simplexml', // use 'simplexml' to use parent name as tagname if transforming an indexed array
+ 'addDoctype' => false, // add a doctype declaration
+ 'doctype' => null, // supply a string or an array with id and uri ({@see XML_Util::getDoctypeDeclaration()}
+ 'rootName' => 'package', // name of the root tag
+ 'rootAttributes' => array(
+ 'version' => '2.0',
+ 'xmlns' => 'http://pear.php.net/dtd/package-2.0',
+ 'xmlns:tasks' => 'http://pear.php.net/dtd/tasks-1.0',
+ 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
+ 'xsi:schemaLocation' => 'http://pear.php.net/dtd/tasks-1.0
+http://pear.php.net/dtd/tasks-1.0.xsd
+http://pear.php.net/dtd/package-2.0
+http://pear.php.net/dtd/package-2.0.xsd',
+ ), // attributes of the root tag
+ 'attributesArray' => 'attribs', // all values in this key will be treated as attributes
+ 'contentName' => '_content', // this value will be used directly as content, instead of creating a new tag, may only be used in conjunction with attributesArray
+ 'beautifyFilelist' => false,
+ 'encoding' => 'UTF-8',
+ );
+
+ /**
+ * options for the serialization
+ * @access private
+ * @var array $options
+ */
+ var $options = array();
+
+ /**
+ * current tag depth
+ * @var integer $_tagDepth
+ */
+ var $_tagDepth = 0;
+
+ /**
+ * serilialized representation of the data
+ * @var string $_serializedData
+ */
+ var $_serializedData = null;
+ /**
+ * @var PEAR_PackageFile_v2
+ */
+ var $_packagefile;
+ /**
+ * @param PEAR_PackageFile_v2
+ */
+ function __construct(&$packagefile)
+ {
+ $this->_packagefile = &$packagefile;
+ if (isset($this->_packagefile->encoding)) {
+ $this->_defaultOptions['encoding'] = $this->_packagefile->encoding;
+ }
+ }
+
+ /**
+ * @return string
+ */
+ function getPackagerVersion()
+ {
+ return '1.10.3';
+ }
+
+ /**
+ * @param PEAR_Packager
+ * @param bool generate a .tgz or a .tar
+ * @param string|null temporary directory to package in
+ */
+ function toTgz(&$packager, $compress = true, $where = null)
+ {
+ $a = null;
+ return $this->toTgz2($packager, $a, $compress, $where);
+ }
+
+ /**
+ * Package up both a package.xml and package2.xml for the same release
+ * @param PEAR_Packager
+ * @param PEAR_PackageFile_v1
+ * @param bool generate a .tgz or a .tar
+ * @param string|null temporary directory to package in
+ */
+ function toTgz2(&$packager, &$pf1, $compress = true, $where = null)
+ {
+ require_once 'Archive/Tar.php';
+ if (!$this->_packagefile->isEquivalent($pf1)) {
+ return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: "' .
+ basename($pf1->getPackageFile()) .
+ '" is not equivalent to "' . basename($this->_packagefile->getPackageFile())
+ . '"');
+ }
+
+ if ($where === null) {
+ if (!($where = System::mktemp(array('-d')))) {
+ return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: mktemp failed');
+ }
+ } elseif (!@System::mkDir(array('-p', $where))) {
+ return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: "' . $where . '" could' .
+ ' not be created');
+ }
+
+ $file = $where . DIRECTORY_SEPARATOR . 'package.xml';
+ if (file_exists($file) && !is_file($file)) {
+ return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: unable to save package.xml as' .
+ ' "' . $file .'"');
+ }
+
+ if (!$this->_packagefile->validate(PEAR_VALIDATE_PACKAGING)) {
+ return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: invalid package.xml');
+ }
+
+ $ext = $compress ? '.tgz' : '.tar';
+ $pkgver = $this->_packagefile->getPackage() . '-' . $this->_packagefile->getVersion();
+ $dest_package = getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext;
+ if (file_exists($dest_package) && !is_file($dest_package)) {
+ return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: cannot create tgz file "' .
+ $dest_package . '"');
+ }
+
+ $pkgfile = $this->_packagefile->getPackageFile();
+ if (!$pkgfile) {
+ return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: package file object must ' .
+ 'be created from a real file');
+ }
+
+ $pkgdir = dirname(realpath($pkgfile));
+ $pkgfile = basename($pkgfile);
+
+ // {{{ Create the package file list
+ $filelist = array();
+ $i = 0;
+ $this->_packagefile->flattenFilelist();
+ $contents = $this->_packagefile->getContents();
+ if (isset($contents['bundledpackage'])) { // bundles of packages
+ $contents = $contents['bundledpackage'];
+ if (!isset($contents[0])) {
+ $contents = array($contents);
+ }
+
+ $packageDir = $where;
+ foreach ($contents as $i => $package) {
+ $fname = $package;
+ $file = $pkgdir . DIRECTORY_SEPARATOR . $fname;
+ if (!file_exists($file)) {
+ return $packager->raiseError("File does not exist: $fname");
+ }
+
+ $tfile = $packageDir . DIRECTORY_SEPARATOR . $fname;
+ System::mkdir(array('-p', dirname($tfile)));
+ copy($file, $tfile);
+ $filelist[$i++] = $tfile;
+ $packager->log(2, "Adding package $fname");
+ }
+ } else { // normal packages
+ $contents = $contents['dir']['file'];
+ if (!isset($contents[0])) {
+ $contents = array($contents);
+ }
+
+ $packageDir = $where;
+ foreach ($contents as $i => $file) {
+ $fname = $file['attribs']['name'];
+ $atts = $file['attribs'];
+ $orig = $file;
+ $file = $pkgdir . DIRECTORY_SEPARATOR . $fname;
+ if (!file_exists($file)) {
+ return $packager->raiseError("File does not exist: $fname");
+ }
+
+ $origperms = fileperms($file);
+ $tfile = $packageDir . DIRECTORY_SEPARATOR . $fname;
+ unset($orig['attribs']);
+ if (count($orig)) { // file with tasks
+ // run any package-time tasks
+ $contents = file_get_contents($file);
+ foreach ($orig as $tag => $raw) {
+ $tag = str_replace(
+ array($this->_packagefile->getTasksNs() . ':', '-'),
+ array('', '_'), $tag);
+ $task = "PEAR_Task_$tag";
+ $task = new $task($this->_packagefile->_config,
+ $this->_packagefile->_logger,
+ PEAR_TASK_PACKAGE);
+ $task->init($raw, $atts, null);
+ $res = $task->startSession($this->_packagefile, $contents, $tfile);
+ if (!$res) {
+ continue; // skip this task
+ }
+
+ if (PEAR::isError($res)) {
+ return $res;
+ }
+
+ $contents = $res; // save changes
+ System::mkdir(array('-p', dirname($tfile)));
+ $wp = fopen($tfile, "wb");
+ fwrite($wp, $contents);
+ fclose($wp);
+ }
+ }
+
+ if (!file_exists($tfile)) {
+ System::mkdir(array('-p', dirname($tfile)));
+ copy($file, $tfile);
+ }
+
+ chmod($tfile, $origperms);
+ $filelist[$i++] = $tfile;
+ $this->_packagefile->setFileAttribute($fname, 'md5sum', md5_file($tfile), $i - 1);
+ $packager->log(2, "Adding file $fname");
+ }
+ }
+ // }}}
+
+ $name = $pf1 !== null ? 'package2.xml' : 'package.xml';
+ $packagexml = $this->toPackageFile($where, PEAR_VALIDATE_PACKAGING, $name);
+ if ($packagexml) {
+ $tar = new Archive_Tar($dest_package, $compress);
+ $tar->setErrorHandling(PEAR_ERROR_RETURN); // XXX Don't print errors
+ // ----- Creates with the package.xml file
+ $ok = $tar->createModify(array($packagexml), '', $where);
+ if (PEAR::isError($ok)) {
+ return $packager->raiseError($ok);
+ } elseif (!$ok) {
+ return $packager->raiseError('PEAR_Packagefile_v2::toTgz(): adding ' . $name .
+ ' failed');
+ }
+
+ // ----- Add the content of the package
+ if (!$tar->addModify($filelist, $pkgver, $where)) {
+ return $packager->raiseError(
+ 'PEAR_Packagefile_v2::toTgz(): tarball creation failed');
+ }
+
+ // add the package.xml version 1.0
+ if ($pf1 !== null) {
+ $pfgen = &$pf1->getDefaultGenerator();
+ $packagexml1 = $pfgen->toPackageFile($where, PEAR_VALIDATE_PACKAGING, 'package.xml', true);
+ if (!$tar->addModify(array($packagexml1), '', $where)) {
+ return $packager->raiseError(
+ 'PEAR_Packagefile_v2::toTgz(): adding package.xml failed');
+ }
+ }
+
+ return $dest_package;
+ }
+ }
+
+ function toPackageFile($where = null, $state = PEAR_VALIDATE_NORMAL, $name = 'package.xml')
+ {
+ if (!$this->_packagefile->validate($state)) {
+ return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: invalid package.xml',
+ null, null, null, $this->_packagefile->getValidationWarnings());
+ }
+
+ if ($where === null) {
+ if (!($where = System::mktemp(array('-d')))) {
+ return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: mktemp failed');
+ }
+ } elseif (!@System::mkDir(array('-p', $where))) {
+ return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: "' . $where . '" could' .
+ ' not be created');
+ }
+
+ $newpkgfile = $where . DIRECTORY_SEPARATOR . $name;
+ $np = @fopen($newpkgfile, 'wb');
+ if (!$np) {
+ return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: unable to save ' .
+ "$name as $newpkgfile");
+ }
+ fwrite($np, $this->toXml($state));
+ fclose($np);
+ return $newpkgfile;
+ }
+
+ function &toV2()
+ {
+ return $this->_packagefile;
+ }
+
+ /**
+ * Return an XML document based on the package info (as returned
+ * by the PEAR_Common::infoFrom* methods).
+ *
+ * @return string XML data
+ */
+ function toXml($state = PEAR_VALIDATE_NORMAL, $options = array())
+ {
+ $this->_packagefile->setDate(date('Y-m-d'));
+ $this->_packagefile->setTime(date('H:i:s'));
+ if (!$this->_packagefile->validate($state)) {
+ return false;
+ }
+
+ if (is_array($options)) {
+ $this->options = array_merge($this->_defaultOptions, $options);
+ } else {
+ $this->options = $this->_defaultOptions;
+ }
+
+ $arr = $this->_packagefile->getArray();
+ if (isset($arr['filelist'])) {
+ unset($arr['filelist']);
+ }
+
+ if (isset($arr['_lastversion'])) {
+ unset($arr['_lastversion']);
+ }
+
+ // Fix the notes a little bit
+ if (isset($arr['notes'])) {
+ // This trims out the indenting, needs fixing
+ $arr['notes'] = "\n" . trim($arr['notes']) . "\n";
+ }
+
+ if (isset($arr['changelog']) && !empty($arr['changelog'])) {
+ // Fix for inconsistency how the array is filled depending on the changelog release amount
+ if (!isset($arr['changelog']['release'][0])) {
+ $release = $arr['changelog']['release'];
+ unset($arr['changelog']['release']);
+
+ $arr['changelog']['release'] = array();
+ $arr['changelog']['release'][0] = $release;
+ }
+
+ foreach (array_keys($arr['changelog']['release']) as $key) {
+ $c =& $arr['changelog']['release'][$key];
+ if (isset($c['notes'])) {
+ // This trims out the indenting, needs fixing
+ $c['notes'] = "\n" . trim($c['notes']) . "\n";
+ }
+ }
+ }
+
+ if ($state ^ PEAR_VALIDATE_PACKAGING && !isset($arr['bundle'])) {
+ $use = $this->_recursiveXmlFilelist($arr['contents']['dir']['file']);
+ unset($arr['contents']['dir']['file']);
+ if (isset($use['dir'])) {
+ $arr['contents']['dir']['dir'] = $use['dir'];
+ }
+ if (isset($use['file'])) {
+ $arr['contents']['dir']['file'] = $use['file'];
+ }
+ $this->options['beautifyFilelist'] = true;
+ }
+
+ $arr['attribs']['packagerversion'] = '1.10.3';
+ if ($this->serialize($arr, $options)) {
+ return $this->_serializedData . "\n";
+ }
+
+ return false;
+ }
+
+
+ function _recursiveXmlFilelist($list)
+ {
+ $dirs = array();
+ if (isset($list['attribs'])) {
+ $file = $list['attribs']['name'];
+ unset($list['attribs']['name']);
+ $attributes = $list['attribs'];
+ $this->_addDir($dirs, explode('/', dirname($file)), $file, $attributes);
+ } else {
+ foreach ($list as $a) {
+ $file = $a['attribs']['name'];
+ $attributes = $a['attribs'];
+ unset($a['attribs']);
+ $this->_addDir($dirs, explode('/', dirname($file)), $file, $attributes, $a);
+ }
+ }
+ $this->_formatDir($dirs);
+ $this->_deFormat($dirs);
+ return $dirs;
+ }
+
+ function _addDir(&$dirs, $dir, $file = null, $attributes = null, $tasks = null)
+ {
+ if (!$tasks) {
+ $tasks = array();
+ }
+ if ($dir == array() || $dir == array('.')) {
+ $dirs['file'][basename($file)] = $tasks;
+ $attributes['name'] = basename($file);
+ $dirs['file'][basename($file)]['attribs'] = $attributes;
+ return;
+ }
+ $curdir = array_shift($dir);
+ if (!isset($dirs['dir'][$curdir])) {
+ $dirs['dir'][$curdir] = array();
+ }
+ $this->_addDir($dirs['dir'][$curdir], $dir, $file, $attributes, $tasks);
+ }
+
+ function _formatDir(&$dirs)
+ {
+ if (!count($dirs)) {
+ return array();
+ }
+ $newdirs = array();
+ if (isset($dirs['dir'])) {
+ $newdirs['dir'] = $dirs['dir'];
+ }
+ if (isset($dirs['file'])) {
+ $newdirs['file'] = $dirs['file'];
+ }
+ $dirs = $newdirs;
+ if (isset($dirs['dir'])) {
+ uksort($dirs['dir'], 'strnatcasecmp');
+ foreach ($dirs['dir'] as $dir => $contents) {
+ $this->_formatDir($dirs['dir'][$dir]);
+ }
+ }
+ if (isset($dirs['file'])) {
+ uksort($dirs['file'], 'strnatcasecmp');
+ };
+ }
+
+ function _deFormat(&$dirs)
+ {
+ if (!count($dirs)) {
+ return array();
+ }
+ $newdirs = array();
+ if (isset($dirs['dir'])) {
+ foreach ($dirs['dir'] as $dir => $contents) {
+ $newdir = array();
+ $newdir['attribs']['name'] = $dir;
+ $this->_deFormat($contents);
+ foreach ($contents as $tag => $val) {
+ $newdir[$tag] = $val;
+ }
+ $newdirs['dir'][] = $newdir;
+ }
+ if (count($newdirs['dir']) == 1) {
+ $newdirs['dir'] = $newdirs['dir'][0];
+ }
+ }
+ if (isset($dirs['file'])) {
+ foreach ($dirs['file'] as $name => $file) {
+ $newdirs['file'][] = $file;
+ }
+ if (count($newdirs['file']) == 1) {
+ $newdirs['file'] = $newdirs['file'][0];
+ }
+ }
+ $dirs = $newdirs;
+ }
+
+ /**
+ * reset all options to default options
+ *
+ * @access public
+ * @see setOption(), XML_Unserializer()
+ */
+ function resetOptions()
+ {
+ $this->options = $this->_defaultOptions;
+ }
+
+ /**
+ * set an option
+ *
+ * You can use this method if you do not want to set all options in the constructor
+ *
+ * @access public
+ * @see resetOption(), XML_Serializer()
+ */
+ function setOption($name, $value)
+ {
+ $this->options[$name] = $value;
+ }
+
+ /**
+ * sets several options at once
+ *
+ * You can use this method if you do not want to set all options in the constructor
+ *
+ * @access public
+ * @see resetOption(), XML_Unserializer(), setOption()
+ */
+ function setOptions($options)
+ {
+ $this->options = array_merge($this->options, $options);
+ }
+
+ /**
+ * serialize data
+ *
+ * @access public
+ * @param mixed $data data to serialize
+ * @return boolean true on success, pear error on failure
+ */
+ function serialize($data, $options = null)
+ {
+ // if options have been specified, use them instead
+ // of the previously defined ones
+ if (is_array($options)) {
+ $optionsBak = $this->options;
+ if (isset($options['overrideOptions']) && $options['overrideOptions'] == true) {
+ $this->options = array_merge($this->_defaultOptions, $options);
+ } else {
+ $this->options = array_merge($this->options, $options);
+ }
+ } else {
+ $optionsBak = null;
+ }
+
+ // start depth is zero
+ $this->_tagDepth = 0;
+ $this->_serializedData = '';
+ // serialize an array
+ if (is_array($data)) {
+ $tagName = isset($this->options['rootName']) ? $this->options['rootName'] : 'array';
+ $this->_serializedData .= $this->_serializeArray($data, $tagName, $this->options['rootAttributes']);
+ }
+
+ // add doctype declaration
+ if ($this->options['addDoctype'] === true) {
+ $this->_serializedData = XML_Util::getDoctypeDeclaration($tagName, $this->options['doctype'])
+ . $this->options['linebreak']
+ . $this->_serializedData;
+ }
+
+ // build xml declaration
+ if ($this->options['addDecl']) {
+ $atts = array();
+ $encoding = isset($this->options['encoding']) ? $this->options['encoding'] : null;
+ $this->_serializedData = XML_Util::getXMLDeclaration('1.0', $encoding)
+ . $this->options['linebreak']
+ . $this->_serializedData;
+ }
+
+
+ if ($optionsBak !== null) {
+ $this->options = $optionsBak;
+ }
+
+ return true;
+ }
+
+ /**
+ * get the result of the serialization
+ *
+ * @access public
+ * @return string serialized XML
+ */
+ function getSerializedData()
+ {
+ if ($this->_serializedData === null) {
+ return $this->raiseError('No serialized data available. Use XML_Serializer::serialize() first.', XML_SERIALIZER_ERROR_NO_SERIALIZATION);
+ }
+ return $this->_serializedData;
+ }
+
+ /**
+ * serialize any value
+ *
+ * This method checks for the type of the value and calls the appropriate method
+ *
+ * @access private
+ * @param mixed $value
+ * @param string $tagName
+ * @param array $attributes
+ * @return string
+ */
+ function _serializeValue($value, $tagName = null, $attributes = array())
+ {
+ if (is_array($value)) {
+ $xml = $this->_serializeArray($value, $tagName, $attributes);
+ } elseif (is_object($value)) {
+ $xml = $this->_serializeObject($value, $tagName);
+ } else {
+ $tag = array(
+ 'qname' => $tagName,
+ 'attributes' => $attributes,
+ 'content' => $value
+ );
+ $xml = $this->_createXMLTag($tag);
+ }
+ return $xml;
+ }
+
+ /**
+ * serialize an array
+ *
+ * @access private
+ * @param array $array array to serialize
+ * @param string $tagName name of the root tag
+ * @param array $attributes attributes for the root tag
+ * @return string $string serialized data
+ * @uses XML_Util::isValidName() to check, whether key has to be substituted
+ */
+ function _serializeArray(&$array, $tagName = null, $attributes = array())
+ {
+ $_content = null;
+
+ /**
+ * check for special attributes
+ */
+ if ($this->options['attributesArray'] !== null) {
+ if (isset($array[$this->options['attributesArray']])) {
+ $attributes = $array[$this->options['attributesArray']];
+ unset($array[$this->options['attributesArray']]);
+ }
+ /**
+ * check for special content
+ */
+ if ($this->options['contentName'] !== null) {
+ if (isset($array[$this->options['contentName']])) {
+ $_content = $array[$this->options['contentName']];
+ unset($array[$this->options['contentName']]);
+ }
+ }
+ }
+
+ /*
+ * if mode is set to simpleXML, check whether
+ * the array is associative or indexed
+ */
+ if (is_array($array) && $this->options['mode'] == 'simplexml') {
+ $indexed = true;
+ if (!count($array)) {
+ $indexed = false;
+ }
+ foreach ($array as $key => $val) {
+ if (!is_int($key)) {
+ $indexed = false;
+ break;
+ }
+ }
+
+ if ($indexed && $this->options['mode'] == 'simplexml') {
+ $string = '';
+ foreach ($array as $key => $val) {
+ if ($this->options['beautifyFilelist'] && $tagName == 'dir') {
+ if (!isset($this->_curdir)) {
+ $this->_curdir = '';
+ }
+ $savedir = $this->_curdir;
+ if (isset($val['attribs'])) {
+ if ($val['attribs']['name'] == '/') {
+ $this->_curdir = '/';
+ } else {
+ if ($this->_curdir == '/') {
+ $this->_curdir = '';
+ }
+ $this->_curdir .= '/' . $val['attribs']['name'];
+ }
+ }
+ }
+ $string .= $this->_serializeValue( $val, $tagName, $attributes);
+ if ($this->options['beautifyFilelist'] && $tagName == 'dir') {
+ $string .= ' ';
+ if (empty($savedir)) {
+ unset($this->_curdir);
+ } else {
+ $this->_curdir = $savedir;
+ }
+ }
+
+ $string .= $this->options['linebreak'];
+ // do indentation
+ if ($this->options['indent'] !== null && $this->_tagDepth > 0) {
+ $string .= str_repeat($this->options['indent'], $this->_tagDepth);
+ }
+ }
+ return rtrim($string);
+ }
+ }
+
+ if ($this->options['scalarAsAttributes'] === true) {
+ foreach ($array as $key => $value) {
+ if (is_scalar($value) && (XML_Util::isValidName($key) === true)) {
+ unset($array[$key]);
+ $attributes[$this->options['prependAttributes'].$key] = $value;
+ }
+ }
+ }
+
+ // check for empty array => create empty tag
+ if (empty($array)) {
+ $tag = array(
+ 'qname' => $tagName,
+ 'content' => $_content,
+ 'attributes' => $attributes
+ );
+
+ } else {
+ $this->_tagDepth++;
+ $tmp = $this->options['linebreak'];
+ foreach ($array as $key => $value) {
+ // do indentation
+ if ($this->options['indent'] !== null && $this->_tagDepth > 0) {
+ $tmp .= str_repeat($this->options['indent'], $this->_tagDepth);
+ }
+
+ // copy key
+ $origKey = $key;
+ // key cannot be used as tagname => use default tag
+ $valid = XML_Util::isValidName($key);
+ if (PEAR::isError($valid)) {
+ if ($this->options['classAsTagName'] && is_object($value)) {
+ $key = get_class($value);
+ } else {
+ $key = $this->options['defaultTagName'];
+ }
+ }
+ $atts = array();
+ if ($this->options['typeHints'] === true) {
+ $atts[$this->options['typeAttribute']] = gettype($value);
+ if ($key !== $origKey) {
+ $atts[$this->options['keyAttribute']] = (string)$origKey;
+ }
+
+ }
+ if ($this->options['beautifyFilelist'] && $key == 'dir') {
+ if (!isset($this->_curdir)) {
+ $this->_curdir = '';
+ }
+ $savedir = $this->_curdir;
+ if (isset($value['attribs'])) {
+ if ($value['attribs']['name'] == '/') {
+ $this->_curdir = '/';
+ } else {
+ $this->_curdir .= '/' . $value['attribs']['name'];
+ }
+ }
+ }
+
+ if (is_string($value) && $value && ($value{strlen($value) - 1} == "\n")) {
+ $value .= str_repeat($this->options['indent'], $this->_tagDepth);
+ }
+ $tmp .= $this->_createXMLTag(array(
+ 'qname' => $key,
+ 'attributes' => $atts,
+ 'content' => $value )
+ );
+ if ($this->options['beautifyFilelist'] && $key == 'dir') {
+ if (isset($value['attribs'])) {
+ $tmp .= ' ';
+ if (empty($savedir)) {
+ unset($this->_curdir);
+ } else {
+ $this->_curdir = $savedir;
+ }
+ }
+ }
+ $tmp .= $this->options['linebreak'];
+ }
+
+ $this->_tagDepth--;
+ if ($this->options['indent']!==null && $this->_tagDepth>0) {
+ $tmp .= str_repeat($this->options['indent'], $this->_tagDepth);
+ }
+
+ if (trim($tmp) === '') {
+ $tmp = null;
+ }
+
+ $tag = array(
+ 'qname' => $tagName,
+ 'content' => $tmp,
+ 'attributes' => $attributes
+ );
+ }
+ if ($this->options['typeHints'] === true) {
+ if (!isset($tag['attributes'][$this->options['typeAttribute']])) {
+ $tag['attributes'][$this->options['typeAttribute']] = 'array';
+ }
+ }
+
+ $string = $this->_createXMLTag($tag, false);
+ return $string;
+ }
+
+ /**
+ * create a tag from an array
+ * this method awaits an array in the following format
+ * array(
+ * 'qname' => $tagName,
+ * 'attributes' => array(),
+ * 'content' => $content, // optional
+ * 'namespace' => $namespace // optional
+ * 'namespaceUri' => $namespaceUri // optional
+ * )
+ *
+ * @access private
+ * @param array $tag tag definition
+ * @param boolean $replaceEntities whether to replace XML entities in content or not
+ * @return string $string XML tag
+ */
+ function _createXMLTag($tag, $replaceEntities = true)
+ {
+ if ($this->options['indentAttributes'] !== false) {
+ $multiline = true;
+ $indent = str_repeat($this->options['indent'], $this->_tagDepth);
+
+ if ($this->options['indentAttributes'] == '_auto') {
+ $indent .= str_repeat(' ', (strlen($tag['qname'])+2));
+
+ } else {
+ $indent .= $this->options['indentAttributes'];
+ }
+ } else {
+ $indent = $multiline = false;
+ }
+
+ if (is_array($tag['content'])) {
+ if (empty($tag['content'])) {
+ $tag['content'] = '';
+ }
+ } elseif(is_scalar($tag['content']) && (string)$tag['content'] == '') {
+ $tag['content'] = '';
+ }
+
+ if (is_scalar($tag['content']) || is_null($tag['content'])) {
+ if ($replaceEntities === true) {
+ $replaceEntities = XML_UTIL_ENTITIES_XML;
+ }
+
+ $tag = XML_Util::createTagFromArray($tag, $replaceEntities, $multiline, $indent, $this->options['linebreak']);
+ } elseif (is_array($tag['content'])) {
+ $tag = $this->_serializeArray($tag['content'], $tag['qname'], $tag['attributes']);
+ } elseif (is_object($tag['content'])) {
+ $tag = $this->_serializeObject($tag['content'], $tag['qname'], $tag['attributes']);
+ } elseif (is_resource($tag['content'])) {
+ settype($tag['content'], 'string');
+ $tag = XML_Util::createTagFromArray($tag, $replaceEntities);
+ }
+ return $tag;
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/PackageFile/Parser/v1.php b/vendor/pear-pear.php.net/PEAR/PEAR/PackageFile/Parser/v1.php
new file mode 100644
index 000000000..8e08e0b42
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/PackageFile/Parser/v1.php
@@ -0,0 +1,458 @@
+
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+/**
+ * package.xml abstraction class
+ */
+require_once 'PEAR/PackageFile/v1.php';
+/**
+ * Parser for package.xml version 1.0
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: @PEAR-VER@
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_PackageFile_Parser_v1
+{
+ var $_registry;
+ var $_config;
+ var $_logger;
+ /**
+ * BC hack to allow PEAR_Common::infoFromString() to sort of
+ * work with the version 2.0 format - there's no filelist though
+ * @param PEAR_PackageFile_v2
+ */
+ function fromV2($packagefile)
+ {
+ $info = $packagefile->getArray(true);
+ $ret = new PEAR_PackageFile_v1;
+ $ret->fromArray($info['old']);
+ }
+
+ function setConfig(&$c)
+ {
+ $this->_config = &$c;
+ $this->_registry = &$c->getRegistry();
+ }
+
+ function setLogger(&$l)
+ {
+ $this->_logger = &$l;
+ }
+
+ /**
+ * @param string contents of package.xml file, version 1.0
+ * @return bool success of parsing
+ */
+ function &parse($data, $file, $archive = false)
+ {
+ if (!extension_loaded('xml')) {
+ return PEAR::raiseError('Cannot create xml parser for parsing package.xml, no xml extension');
+ }
+ $xp = xml_parser_create();
+ if (!$xp) {
+ $a = &PEAR::raiseError('Cannot create xml parser for parsing package.xml');
+ return $a;
+ }
+ xml_set_object($xp, $this);
+ xml_set_element_handler($xp, '_element_start_1_0', '_element_end_1_0');
+ xml_set_character_data_handler($xp, '_pkginfo_cdata_1_0');
+ xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, false);
+
+ $this->element_stack = array();
+ $this->_packageInfo = array('provides' => array());
+ $this->current_element = false;
+ unset($this->dir_install);
+ $this->_packageInfo['filelist'] = array();
+ $this->filelist =& $this->_packageInfo['filelist'];
+ $this->dir_names = array();
+ $this->in_changelog = false;
+ $this->d_i = 0;
+ $this->cdata = '';
+ $this->_isValid = true;
+
+ if (!xml_parse($xp, $data, 1)) {
+ $code = xml_get_error_code($xp);
+ $line = xml_get_current_line_number($xp);
+ xml_parser_free($xp);
+ $a = PEAR::raiseError(sprintf("XML error: %s at line %d",
+ $str = xml_error_string($code), $line), 2);
+ return $a;
+ }
+
+ xml_parser_free($xp);
+
+ $pf = new PEAR_PackageFile_v1;
+ $pf->setConfig($this->_config);
+ if (isset($this->_logger)) {
+ $pf->setLogger($this->_logger);
+ }
+ $pf->setPackagefile($file, $archive);
+ $pf->fromArray($this->_packageInfo);
+ return $pf;
+ }
+ // {{{ _unIndent()
+
+ /**
+ * Unindent given string
+ *
+ * @param string $str The string that has to be unindented.
+ * @return string
+ * @access private
+ */
+ function _unIndent($str)
+ {
+ // remove leading newlines
+ $str = preg_replace('/^[\r\n]+/', '', $str);
+ // find whitespace at the beginning of the first line
+ $indent_len = strspn($str, " \t");
+ $indent = substr($str, 0, $indent_len);
+ $data = '';
+ // remove the same amount of whitespace from following lines
+ foreach (explode("\n", $str) as $line) {
+ if (substr($line, 0, $indent_len) == $indent) {
+ $data .= substr($line, $indent_len) . "\n";
+ } elseif (trim(substr($line, 0, $indent_len))) {
+ $data .= ltrim($line);
+ }
+ }
+ return $data;
+ }
+
+ // Support for package DTD v1.0:
+ // {{{ _element_start_1_0()
+
+ /**
+ * XML parser callback for ending elements. Used for version 1.0
+ * packages.
+ *
+ * @param resource $xp XML parser resource
+ * @param string $name name of ending element
+ *
+ * @return void
+ *
+ * @access private
+ */
+ function _element_start_1_0($xp, $name, $attribs)
+ {
+ array_push($this->element_stack, $name);
+ $this->current_element = $name;
+ $spos = sizeof($this->element_stack) - 2;
+ $this->prev_element = ($spos >= 0) ? $this->element_stack[$spos] : '';
+ $this->current_attributes = $attribs;
+ $this->cdata = '';
+ switch ($name) {
+ case 'dir':
+ if ($this->in_changelog) {
+ break;
+ }
+ if (array_key_exists('name', $attribs) && $attribs['name'] != '/') {
+ $attribs['name'] = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'),
+ $attribs['name']);
+ if (strrpos($attribs['name'], '/') === strlen($attribs['name']) - 1) {
+ $attribs['name'] = substr($attribs['name'], 0,
+ strlen($attribs['name']) - 1);
+ }
+ if (strpos($attribs['name'], '/') === 0) {
+ $attribs['name'] = substr($attribs['name'], 1);
+ }
+ $this->dir_names[] = $attribs['name'];
+ }
+ if (isset($attribs['baseinstalldir'])) {
+ $this->dir_install = $attribs['baseinstalldir'];
+ }
+ if (isset($attribs['role'])) {
+ $this->dir_role = $attribs['role'];
+ }
+ break;
+ case 'file':
+ if ($this->in_changelog) {
+ break;
+ }
+ if (isset($attribs['name'])) {
+ $path = '';
+ if (count($this->dir_names)) {
+ foreach ($this->dir_names as $dir) {
+ $path .= $dir . '/';
+ }
+ }
+ $path .= preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'),
+ $attribs['name']);
+ unset($attribs['name']);
+ $this->current_path = $path;
+ $this->filelist[$path] = $attribs;
+ // Set the baseinstalldir only if the file don't have this attrib
+ if (!isset($this->filelist[$path]['baseinstalldir']) &&
+ isset($this->dir_install))
+ {
+ $this->filelist[$path]['baseinstalldir'] = $this->dir_install;
+ }
+ // Set the Role
+ if (!isset($this->filelist[$path]['role']) && isset($this->dir_role)) {
+ $this->filelist[$path]['role'] = $this->dir_role;
+ }
+ }
+ break;
+ case 'replace':
+ if (!$this->in_changelog) {
+ $this->filelist[$this->current_path]['replacements'][] = $attribs;
+ }
+ break;
+ case 'maintainers':
+ $this->_packageInfo['maintainers'] = array();
+ $this->m_i = 0; // maintainers array index
+ break;
+ case 'maintainer':
+ // compatibility check
+ if (!isset($this->_packageInfo['maintainers'])) {
+ $this->_packageInfo['maintainers'] = array();
+ $this->m_i = 0;
+ }
+ $this->_packageInfo['maintainers'][$this->m_i] = array();
+ $this->current_maintainer =& $this->_packageInfo['maintainers'][$this->m_i];
+ break;
+ case 'changelog':
+ $this->_packageInfo['changelog'] = array();
+ $this->c_i = 0; // changelog array index
+ $this->in_changelog = true;
+ break;
+ case 'release':
+ if ($this->in_changelog) {
+ $this->_packageInfo['changelog'][$this->c_i] = array();
+ $this->current_release = &$this->_packageInfo['changelog'][$this->c_i];
+ } else {
+ $this->current_release = &$this->_packageInfo;
+ }
+ break;
+ case 'deps':
+ if (!$this->in_changelog) {
+ $this->_packageInfo['release_deps'] = array();
+ }
+ break;
+ case 'dep':
+ // dependencies array index
+ if (!$this->in_changelog) {
+ $this->d_i++;
+ isset($attribs['type']) ? ($attribs['type'] = strtolower($attribs['type'])) : false;
+ $this->_packageInfo['release_deps'][$this->d_i] = $attribs;
+ }
+ break;
+ case 'configureoptions':
+ if (!$this->in_changelog) {
+ $this->_packageInfo['configure_options'] = array();
+ }
+ break;
+ case 'configureoption':
+ if (!$this->in_changelog) {
+ $this->_packageInfo['configure_options'][] = $attribs;
+ }
+ break;
+ case 'provides':
+ if (empty($attribs['type']) || empty($attribs['name'])) {
+ break;
+ }
+ $attribs['explicit'] = true;
+ $this->_packageInfo['provides']["$attribs[type];$attribs[name]"] = $attribs;
+ break;
+ case 'package' :
+ if (isset($attribs['version'])) {
+ $this->_packageInfo['xsdversion'] = trim($attribs['version']);
+ } else {
+ $this->_packageInfo['xsdversion'] = '1.0';
+ }
+ if (isset($attribs['packagerversion'])) {
+ $this->_packageInfo['packagerversion'] = $attribs['packagerversion'];
+ }
+ break;
+ }
+ }
+
+ // }}}
+ // {{{ _element_end_1_0()
+
+ /**
+ * XML parser callback for ending elements. Used for version 1.0
+ * packages.
+ *
+ * @param resource $xp XML parser resource
+ * @param string $name name of ending element
+ *
+ * @return void
+ *
+ * @access private
+ */
+ function _element_end_1_0($xp, $name)
+ {
+ $data = trim($this->cdata);
+ switch ($name) {
+ case 'name':
+ switch ($this->prev_element) {
+ case 'package':
+ $this->_packageInfo['package'] = $data;
+ break;
+ case 'maintainer':
+ $this->current_maintainer['name'] = $data;
+ break;
+ }
+ break;
+ case 'extends' :
+ $this->_packageInfo['extends'] = $data;
+ break;
+ case 'summary':
+ $this->_packageInfo['summary'] = $data;
+ break;
+ case 'description':
+ $data = $this->_unIndent($this->cdata);
+ $this->_packageInfo['description'] = $data;
+ break;
+ case 'user':
+ $this->current_maintainer['handle'] = $data;
+ break;
+ case 'email':
+ $this->current_maintainer['email'] = $data;
+ break;
+ case 'role':
+ $this->current_maintainer['role'] = $data;
+ break;
+ case 'version':
+ if ($this->in_changelog) {
+ $this->current_release['version'] = $data;
+ } else {
+ $this->_packageInfo['version'] = $data;
+ }
+ break;
+ case 'date':
+ if ($this->in_changelog) {
+ $this->current_release['release_date'] = $data;
+ } else {
+ $this->_packageInfo['release_date'] = $data;
+ }
+ break;
+ case 'notes':
+ // try to "de-indent" release notes in case someone
+ // has been over-indenting their xml ;-)
+ // Trim only on the right side
+ $data = rtrim($this->_unIndent($this->cdata));
+ if ($this->in_changelog) {
+ $this->current_release['release_notes'] = $data;
+ } else {
+ $this->_packageInfo['release_notes'] = $data;
+ }
+ break;
+ case 'warnings':
+ if ($this->in_changelog) {
+ $this->current_release['release_warnings'] = $data;
+ } else {
+ $this->_packageInfo['release_warnings'] = $data;
+ }
+ break;
+ case 'state':
+ if ($this->in_changelog) {
+ $this->current_release['release_state'] = $data;
+ } else {
+ $this->_packageInfo['release_state'] = $data;
+ }
+ break;
+ case 'license':
+ if ($this->in_changelog) {
+ $this->current_release['release_license'] = $data;
+ } else {
+ $this->_packageInfo['release_license'] = $data;
+ }
+ break;
+ case 'dep':
+ if ($data && !$this->in_changelog) {
+ $this->_packageInfo['release_deps'][$this->d_i]['name'] = $data;
+ }
+ break;
+ case 'dir':
+ if ($this->in_changelog) {
+ break;
+ }
+ array_pop($this->dir_names);
+ break;
+ case 'file':
+ if ($this->in_changelog) {
+ break;
+ }
+ if ($data) {
+ $path = '';
+ if (count($this->dir_names)) {
+ foreach ($this->dir_names as $dir) {
+ $path .= $dir . '/';
+ }
+ }
+ $path .= $data;
+ $this->filelist[$path] = $this->current_attributes;
+ // Set the baseinstalldir only if the file don't have this attrib
+ if (!isset($this->filelist[$path]['baseinstalldir']) &&
+ isset($this->dir_install))
+ {
+ $this->filelist[$path]['baseinstalldir'] = $this->dir_install;
+ }
+ // Set the Role
+ if (!isset($this->filelist[$path]['role']) && isset($this->dir_role)) {
+ $this->filelist[$path]['role'] = $this->dir_role;
+ }
+ }
+ break;
+ case 'maintainer':
+ if (empty($this->_packageInfo['maintainers'][$this->m_i]['role'])) {
+ $this->_packageInfo['maintainers'][$this->m_i]['role'] = 'lead';
+ }
+ $this->m_i++;
+ break;
+ case 'release':
+ if ($this->in_changelog) {
+ $this->c_i++;
+ }
+ break;
+ case 'changelog':
+ $this->in_changelog = false;
+ break;
+ }
+ array_pop($this->element_stack);
+ $spos = sizeof($this->element_stack) - 1;
+ $this->current_element = ($spos > 0) ? $this->element_stack[$spos] : '';
+ $this->cdata = '';
+ }
+
+ // }}}
+ // {{{ _pkginfo_cdata_1_0()
+
+ /**
+ * XML parser callback for character data. Used for version 1.0
+ * packages.
+ *
+ * @param resource $xp XML parser resource
+ * @param string $name character data
+ *
+ * @return void
+ *
+ * @access private
+ */
+ function _pkginfo_cdata_1_0($xp, $data)
+ {
+ if (isset($this->cdata)) {
+ $this->cdata .= $data;
+ }
+ }
+
+ // }}}
+}
+?>
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/PackageFile/Parser/v2.php b/vendor/pear-pear.php.net/PEAR/PEAR/PackageFile/Parser/v2.php
new file mode 100644
index 000000000..49a29f1aa
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/PackageFile/Parser/v2.php
@@ -0,0 +1,112 @@
+
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+/**
+ * base xml parser class
+ */
+require_once 'PEAR/XMLParser.php';
+require_once 'PEAR/PackageFile/v2.php';
+/**
+ * Parser for package.xml version 2.0
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: @PEAR-VER@
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_PackageFile_Parser_v2 extends PEAR_XMLParser
+{
+ var $_config;
+ var $_logger;
+ var $_registry;
+
+ function setConfig(&$c)
+ {
+ $this->_config = &$c;
+ $this->_registry = &$c->getRegistry();
+ }
+
+ function setLogger(&$l)
+ {
+ $this->_logger = &$l;
+ }
+ /**
+ * Unindent given string
+ *
+ * @param string $str The string that has to be unindented.
+ * @return string
+ * @access private
+ */
+ function _unIndent($str)
+ {
+ // remove leading newlines
+ $str = preg_replace('/^[\r\n]+/', '', $str);
+ // find whitespace at the beginning of the first line
+ $indent_len = strspn($str, " \t");
+ $indent = substr($str, 0, $indent_len);
+ $data = '';
+ // remove the same amount of whitespace from following lines
+ foreach (explode("\n", $str) as $line) {
+ if (substr($line, 0, $indent_len) == $indent) {
+ $data .= substr($line, $indent_len) . "\n";
+ } else {
+ $data .= $line . "\n";
+ }
+ }
+ return $data;
+ }
+
+ /**
+ * post-process data
+ *
+ * @param string $data
+ * @param string $element element name
+ */
+ function postProcess($data, $element)
+ {
+ if ($element == 'notes') {
+ return trim($this->_unIndent($data));
+ }
+ return trim($data);
+ }
+
+ /**
+ * @param string
+ * @param string file name of the package.xml
+ * @param string|false name of the archive this package.xml came from, if any
+ * @param string class name to instantiate and return. This must be PEAR_PackageFile_v2 or
+ * a subclass
+ * @return PEAR_PackageFile_v2
+ */
+ function parse($data, $file = null, $archive = false, $class = 'PEAR_PackageFile_v2')
+ {
+ if (PEAR::isError($err = parent::parse($data))) {
+ return $err;
+ }
+
+ $ret = new $class;
+ $ret->encoding = $this->encoding;
+ $ret->setConfig($this->_config);
+ if (isset($this->_logger)) {
+ $ret->setLogger($this->_logger);
+ }
+
+ $ret->fromArray($this->_unserializedData);
+ $ret->setPackagefile($file, $archive);
+ return $ret;
+ }
+}
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/PackageFile/v1.php b/vendor/pear-pear.php.net/PEAR/PEAR/PackageFile/v1.php
new file mode 100644
index 000000000..6bb3276ee
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/PackageFile/v1.php
@@ -0,0 +1,1602 @@
+
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+/**
+ * For error handling
+ */
+require_once 'PEAR/ErrorStack.php';
+
+/**
+ * Error code if parsing is attempted with no xml extension
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_XML_EXT', 3);
+
+/**
+ * Error code if creating the xml parser resource fails
+ */
+define('PEAR_PACKAGEFILE_ERROR_CANT_MAKE_PARSER', 4);
+
+/**
+ * Error code used for all sax xml parsing errors
+ */
+define('PEAR_PACKAGEFILE_ERROR_PARSER_ERROR', 5);
+
+/**
+ * Error code used when there is no name
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_NAME', 6);
+
+/**
+ * Error code when a package name is not valid
+ */
+define('PEAR_PACKAGEFILE_ERROR_INVALID_NAME', 7);
+
+/**
+ * Error code used when no summary is parsed
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_SUMMARY', 8);
+
+/**
+ * Error code for summaries that are more than 1 line
+ */
+define('PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY', 9);
+
+/**
+ * Error code used when no description is present
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION', 10);
+
+/**
+ * Error code used when no license is present
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_LICENSE', 11);
+
+/**
+ * Error code used when a version number is not present
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_VERSION', 12);
+
+/**
+ * Error code used when a version number is invalid
+ */
+define('PEAR_PACKAGEFILE_ERROR_INVALID_VERSION', 13);
+
+/**
+ * Error code when release state is missing
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_STATE', 14);
+
+/**
+ * Error code when release state is invalid
+ */
+define('PEAR_PACKAGEFILE_ERROR_INVALID_STATE', 15);
+
+/**
+ * Error code when release state is missing
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_DATE', 16);
+
+/**
+ * Error code when release state is invalid
+ */
+define('PEAR_PACKAGEFILE_ERROR_INVALID_DATE', 17);
+
+/**
+ * Error code when no release notes are found
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_NOTES', 18);
+
+/**
+ * Error code when no maintainers are found
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS', 19);
+
+/**
+ * Error code when a maintainer has no handle
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE', 20);
+
+/**
+ * Error code when a maintainer has no handle
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE', 21);
+
+/**
+ * Error code when a maintainer has no name
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME', 22);
+
+/**
+ * Error code when a maintainer has no email
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL', 23);
+
+/**
+ * Error code when a maintainer has no handle
+ */
+define('PEAR_PACKAGEFILE_ERROR_INVALID_MAINTROLE', 24);
+
+/**
+ * Error code when a dependency is not a PHP dependency, but has no name
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_DEPNAME', 25);
+
+/**
+ * Error code when a dependency has no type (pkg, php, etc.)
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE', 26);
+
+/**
+ * Error code when a dependency has no relation (lt, ge, has, etc.)
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_DEPREL', 27);
+
+/**
+ * Error code when a dependency is not a 'has' relation, but has no version
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION', 28);
+
+/**
+ * Error code when a dependency has an invalid relation
+ */
+define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPREL', 29);
+
+/**
+ * Error code when a dependency has an invalid type
+ */
+define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPTYPE', 30);
+
+/**
+ * Error code when a dependency has an invalid optional option
+ */
+define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL', 31);
+
+/**
+ * Error code when a dependency is a pkg dependency, and has an invalid package name
+ */
+define('PEAR_PACKAGEFILE_ERROR_INVALID_DEPNAME', 32);
+
+/**
+ * Error code when a dependency has a channel="foo" attribute, and foo is not a registered channel
+ */
+define('PEAR_PACKAGEFILE_ERROR_UNKNOWN_DEPCHANNEL', 33);
+
+/**
+ * Error code when rel="has" and version attribute is present.
+ */
+define('PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED', 34);
+
+/**
+ * Error code when type="php" and dependency name is present
+ */
+define('PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED', 35);
+
+/**
+ * Error code when a configure option has no name
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_CONFNAME', 36);
+
+/**
+ * Error code when a configure option has no name
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT', 37);
+
+/**
+ * Error code when a file in the filelist has an invalid role
+ */
+define('PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE', 38);
+
+/**
+ * Error code when a file in the filelist has no role
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_FILEROLE', 39);
+
+/**
+ * Error code when analyzing a php source file that has parse errors
+ */
+define('PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE', 40);
+
+/**
+ * Error code when analyzing a php source file reveals a source element
+ * without a package name prefix
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX', 41);
+
+/**
+ * Error code when an unknown channel is specified
+ */
+define('PEAR_PACKAGEFILE_ERROR_UNKNOWN_CHANNEL', 42);
+
+/**
+ * Error code when no files are found in the filelist
+ */
+define('PEAR_PACKAGEFILE_ERROR_NO_FILES', 43);
+
+/**
+ * Error code when a file is not valid php according to _analyzeSourceCode()
+ */
+define('PEAR_PACKAGEFILE_ERROR_INVALID_FILE', 44);
+
+/**
+ * Error code when the channel validator returns an error or warning
+ */
+define('PEAR_PACKAGEFILE_ERROR_CHANNELVAL', 45);
+
+/**
+ * Error code when a php5 package is packaged in php4 (analysis doesn't work)
+ */
+define('PEAR_PACKAGEFILE_ERROR_PHP5', 46);
+
+/**
+ * Error code when a file is listed in package.xml but does not exist
+ */
+define('PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND', 47);
+
+/**
+ * Error code when a
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_PackageFile_v1
+{
+ /**
+ * @access private
+ * @var PEAR_ErrorStack
+ * @access private
+ */
+ var $_stack;
+
+ /**
+ * A registry object, used to access the package name validation regex for non-standard channels
+ * @var PEAR_Registry
+ * @access private
+ */
+ var $_registry;
+
+ /**
+ * An object that contains a log method that matches PEAR_Common::log's signature
+ * @var object
+ * @access private
+ */
+ var $_logger;
+
+ /**
+ * Parsed package information
+ * @var array
+ * @access private
+ */
+ var $_packageInfo;
+
+ /**
+ * path to package.xml
+ * @var string
+ * @access private
+ */
+ var $_packageFile;
+
+ /**
+ * path to package .tgz or false if this is a local/extracted package.xml
+ * @var string
+ * @access private
+ */
+ var $_archiveFile;
+
+ /**
+ * @var int
+ * @access private
+ */
+ var $_isValid = 0;
+
+ /**
+ * Determines whether this packagefile was initialized only with partial package info
+ *
+ * If this package file was constructed via parsing REST, it will only contain
+ *
+ * - package name
+ * - channel name
+ * - dependencies
+ * @var boolean
+ * @access private
+ */
+ var $_incomplete = true;
+
+ /**
+ * @param bool determines whether to return a PEAR_Error object, or use the PEAR_ErrorStack
+ * @param string Name of Error Stack class to use.
+ */
+ function __construct()
+ {
+ $this->_stack = new PEAR_ErrorStack('PEAR_PackageFile_v1');
+ $this->_stack->setErrorMessageTemplate($this->_getErrorMessage());
+ $this->_isValid = 0;
+ }
+
+ function installBinary($installer)
+ {
+ return false;
+ }
+
+ function isExtension($name)
+ {
+ return false;
+ }
+
+ function setConfig(&$config)
+ {
+ $this->_config = &$config;
+ $this->_registry = &$config->getRegistry();
+ }
+
+ function setRequestedGroup()
+ {
+ // placeholder
+ }
+
+ /**
+ * For saving in the registry.
+ *
+ * Set the last version that was installed
+ * @param string
+ */
+ function setLastInstalledVersion($version)
+ {
+ $this->_packageInfo['_lastversion'] = $version;
+ }
+
+ /**
+ * @return string|false
+ */
+ function getLastInstalledVersion()
+ {
+ if (isset($this->_packageInfo['_lastversion'])) {
+ return $this->_packageInfo['_lastversion'];
+ }
+ return false;
+ }
+
+ function getInstalledBinary()
+ {
+ return false;
+ }
+
+ function listPostinstallScripts()
+ {
+ return false;
+ }
+
+ function initPostinstallScripts()
+ {
+ return false;
+ }
+
+ function setLogger(&$logger)
+ {
+ if ($logger && (!is_object($logger) || !method_exists($logger, 'log'))) {
+ return PEAR::raiseError('Logger must be compatible with PEAR_Common::log');
+ }
+ $this->_logger = &$logger;
+ }
+
+ function setPackagefile($file, $archive = false)
+ {
+ $this->_packageFile = $file;
+ $this->_archiveFile = $archive ? $archive : $file;
+ }
+
+ function getPackageFile()
+ {
+ return isset($this->_packageFile) ? $this->_packageFile : false;
+ }
+
+ function getPackageType()
+ {
+ return 'php';
+ }
+
+ function getArchiveFile()
+ {
+ return $this->_archiveFile;
+ }
+
+ function packageInfo($field)
+ {
+ if (!is_string($field) || empty($field) ||
+ !isset($this->_packageInfo[$field])) {
+ return false;
+ }
+ return $this->_packageInfo[$field];
+ }
+
+ function setDirtree($path)
+ {
+ if (!isset($this->_packageInfo['dirtree'])) {
+ $this->_packageInfo['dirtree'] = array();
+ }
+ $this->_packageInfo['dirtree'][$path] = true;
+ }
+
+ function getDirtree()
+ {
+ if (isset($this->_packageInfo['dirtree']) && count($this->_packageInfo['dirtree'])) {
+ return $this->_packageInfo['dirtree'];
+ }
+ return false;
+ }
+
+ function resetDirtree()
+ {
+ unset($this->_packageInfo['dirtree']);
+ }
+
+ function fromArray($pinfo)
+ {
+ $this->_incomplete = false;
+ $this->_packageInfo = $pinfo;
+ }
+
+ function isIncomplete()
+ {
+ return $this->_incomplete;
+ }
+
+ function getChannel()
+ {
+ return 'pear.php.net';
+ }
+
+ function getUri()
+ {
+ return false;
+ }
+
+ function getTime()
+ {
+ return false;
+ }
+
+ function getExtends()
+ {
+ if (isset($this->_packageInfo['extends'])) {
+ return $this->_packageInfo['extends'];
+ }
+ return false;
+ }
+
+ /**
+ * @return array
+ */
+ function toArray()
+ {
+ if (!$this->validate(PEAR_VALIDATE_NORMAL)) {
+ return false;
+ }
+ return $this->getArray();
+ }
+
+ function getArray()
+ {
+ return $this->_packageInfo;
+ }
+
+ function getName()
+ {
+ return $this->getPackage();
+ }
+
+ function getPackage()
+ {
+ if (isset($this->_packageInfo['package'])) {
+ return $this->_packageInfo['package'];
+ }
+ return false;
+ }
+
+ /**
+ * WARNING - don't use this unless you know what you are doing
+ */
+ function setRawPackage($package)
+ {
+ $this->_packageInfo['package'] = $package;
+ }
+
+ function setPackage($package)
+ {
+ $this->_packageInfo['package'] = $package;
+ $this->_isValid = false;
+ }
+
+ function getVersion()
+ {
+ if (isset($this->_packageInfo['version'])) {
+ return $this->_packageInfo['version'];
+ }
+ return false;
+ }
+
+ function setVersion($version)
+ {
+ $this->_packageInfo['version'] = $version;
+ $this->_isValid = false;
+ }
+
+ function clearMaintainers()
+ {
+ unset($this->_packageInfo['maintainers']);
+ }
+
+ function getMaintainers()
+ {
+ if (isset($this->_packageInfo['maintainers'])) {
+ return $this->_packageInfo['maintainers'];
+ }
+ return false;
+ }
+
+ /**
+ * Adds a new maintainer - no checking of duplicates is performed, use
+ * updatemaintainer for that purpose.
+ */
+ function addMaintainer($role, $handle, $name, $email)
+ {
+ $this->_packageInfo['maintainers'][] =
+ array('handle' => $handle, 'role' => $role, 'email' => $email, 'name' => $name);
+ $this->_isValid = false;
+ }
+
+ function updateMaintainer($role, $handle, $name, $email)
+ {
+ $found = false;
+ if (!isset($this->_packageInfo['maintainers']) ||
+ !is_array($this->_packageInfo['maintainers'])) {
+ return $this->addMaintainer($role, $handle, $name, $email);
+ }
+ foreach ($this->_packageInfo['maintainers'] as $i => $maintainer) {
+ if ($maintainer['handle'] == $handle) {
+ $found = $i;
+ break;
+ }
+ }
+ if ($found !== false) {
+ unset($this->_packageInfo['maintainers'][$found]);
+ $this->_packageInfo['maintainers'] =
+ array_values($this->_packageInfo['maintainers']);
+ }
+ $this->addMaintainer($role, $handle, $name, $email);
+ }
+
+ function deleteMaintainer($handle)
+ {
+ $found = false;
+ foreach ($this->_packageInfo['maintainers'] as $i => $maintainer) {
+ if ($maintainer['handle'] == $handle) {
+ $found = $i;
+ break;
+ }
+ }
+ if ($found !== false) {
+ unset($this->_packageInfo['maintainers'][$found]);
+ $this->_packageInfo['maintainers'] =
+ array_values($this->_packageInfo['maintainers']);
+ return true;
+ }
+ return false;
+ }
+
+ function getState()
+ {
+ if (isset($this->_packageInfo['release_state'])) {
+ return $this->_packageInfo['release_state'];
+ }
+ return false;
+ }
+
+ function setRawState($state)
+ {
+ $this->_packageInfo['release_state'] = $state;
+ }
+
+ function setState($state)
+ {
+ $this->_packageInfo['release_state'] = $state;
+ $this->_isValid = false;
+ }
+
+ function getDate()
+ {
+ if (isset($this->_packageInfo['release_date'])) {
+ return $this->_packageInfo['release_date'];
+ }
+ return false;
+ }
+
+ function setDate($date)
+ {
+ $this->_packageInfo['release_date'] = $date;
+ $this->_isValid = false;
+ }
+
+ function getLicense()
+ {
+ if (isset($this->_packageInfo['release_license'])) {
+ return $this->_packageInfo['release_license'];
+ }
+ return false;
+ }
+
+ function setLicense($date)
+ {
+ $this->_packageInfo['release_license'] = $date;
+ $this->_isValid = false;
+ }
+
+ function getSummary()
+ {
+ if (isset($this->_packageInfo['summary'])) {
+ return $this->_packageInfo['summary'];
+ }
+ return false;
+ }
+
+ function setSummary($summary)
+ {
+ $this->_packageInfo['summary'] = $summary;
+ $this->_isValid = false;
+ }
+
+ function getDescription()
+ {
+ if (isset($this->_packageInfo['description'])) {
+ return $this->_packageInfo['description'];
+ }
+ return false;
+ }
+
+ function setDescription($desc)
+ {
+ $this->_packageInfo['description'] = $desc;
+ $this->_isValid = false;
+ }
+
+ function getNotes()
+ {
+ if (isset($this->_packageInfo['release_notes'])) {
+ return $this->_packageInfo['release_notes'];
+ }
+ return false;
+ }
+
+ function setNotes($notes)
+ {
+ $this->_packageInfo['release_notes'] = $notes;
+ $this->_isValid = false;
+ }
+
+ function getDeps()
+ {
+ if (isset($this->_packageInfo['release_deps'])) {
+ return $this->_packageInfo['release_deps'];
+ }
+ return false;
+ }
+
+ /**
+ * Reset dependencies prior to adding new ones
+ */
+ function clearDeps()
+ {
+ unset($this->_packageInfo['release_deps']);
+ }
+
+ function addPhpDep($version, $rel)
+ {
+ $this->_isValid = false;
+ $this->_packageInfo['release_deps'][] =
+ array('type' => 'php',
+ 'rel' => $rel,
+ 'version' => $version);
+ }
+
+ function addPackageDep($name, $version, $rel, $optional = 'no')
+ {
+ $this->_isValid = false;
+ $dep =
+ array('type' => 'pkg',
+ 'name' => $name,
+ 'rel' => $rel,
+ 'optional' => $optional);
+ if ($rel != 'has' && $rel != 'not') {
+ $dep['version'] = $version;
+ }
+ $this->_packageInfo['release_deps'][] = $dep;
+ }
+
+ function addExtensionDep($name, $version, $rel, $optional = 'no')
+ {
+ $this->_isValid = false;
+ $this->_packageInfo['release_deps'][] =
+ array('type' => 'ext',
+ 'name' => $name,
+ 'rel' => $rel,
+ 'version' => $version,
+ 'optional' => $optional);
+ }
+
+ /**
+ * WARNING - do not use this function directly unless you know what you're doing
+ */
+ function setDeps($deps)
+ {
+ $this->_packageInfo['release_deps'] = $deps;
+ }
+
+ function hasDeps()
+ {
+ return isset($this->_packageInfo['release_deps']) &&
+ count($this->_packageInfo['release_deps']);
+ }
+
+ function getDependencyGroup($group)
+ {
+ return false;
+ }
+
+ function isCompatible($pf)
+ {
+ return false;
+ }
+
+ function isSubpackageOf($p)
+ {
+ return $p->isSubpackage($this);
+ }
+
+ function isSubpackage($p)
+ {
+ return false;
+ }
+
+ function dependsOn($package, $channel)
+ {
+ if (strtolower($channel) != 'pear.php.net') {
+ return false;
+ }
+ if (!($deps = $this->getDeps())) {
+ return false;
+ }
+ foreach ($deps as $dep) {
+ if ($dep['type'] != 'pkg') {
+ continue;
+ }
+ if (strtolower($dep['name']) == strtolower($package)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ function getConfigureOptions()
+ {
+ if (isset($this->_packageInfo['configure_options'])) {
+ return $this->_packageInfo['configure_options'];
+ }
+ return false;
+ }
+
+ function hasConfigureOptions()
+ {
+ return isset($this->_packageInfo['configure_options']) &&
+ count($this->_packageInfo['configure_options']);
+ }
+
+ function addConfigureOption($name, $prompt, $default = false)
+ {
+ $o = array('name' => $name, 'prompt' => $prompt);
+ if ($default !== false) {
+ $o['default'] = $default;
+ }
+ if (!isset($this->_packageInfo['configure_options'])) {
+ $this->_packageInfo['configure_options'] = array();
+ }
+ $this->_packageInfo['configure_options'][] = $o;
+ }
+
+ function clearConfigureOptions()
+ {
+ unset($this->_packageInfo['configure_options']);
+ }
+
+ function getProvides()
+ {
+ if (isset($this->_packageInfo['provides'])) {
+ return $this->_packageInfo['provides'];
+ }
+ return false;
+ }
+
+ function getProvidesExtension()
+ {
+ return false;
+ }
+
+ function addFile($dir, $file, $attrs)
+ {
+ $dir = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), $dir);
+ if ($dir == '/' || $dir == '') {
+ $dir = '';
+ } else {
+ $dir .= '/';
+ }
+ $file = $dir . $file;
+ $file = preg_replace('![\\/]+!', '/', $file);
+ $this->_packageInfo['filelist'][$file] = $attrs;
+ }
+
+ function getInstallationFilelist()
+ {
+ return $this->getFilelist();
+ }
+
+ function getFilelist()
+ {
+ if (isset($this->_packageInfo['filelist'])) {
+ return $this->_packageInfo['filelist'];
+ }
+ return false;
+ }
+
+ function setFileAttribute($file, $attr, $value)
+ {
+ $this->_packageInfo['filelist'][$file][$attr] = $value;
+ }
+
+ function resetFilelist()
+ {
+ $this->_packageInfo['filelist'] = array();
+ }
+
+ function setInstalledAs($file, $path)
+ {
+ if ($path) {
+ return $this->_packageInfo['filelist'][$file]['installed_as'] = $path;
+ }
+ unset($this->_packageInfo['filelist'][$file]['installed_as']);
+ }
+
+ function installedFile($file, $atts)
+ {
+ if (isset($this->_packageInfo['filelist'][$file])) {
+ $this->_packageInfo['filelist'][$file] =
+ array_merge($this->_packageInfo['filelist'][$file], $atts);
+ } else {
+ $this->_packageInfo['filelist'][$file] = $atts;
+ }
+ }
+
+ function getChangelog()
+ {
+ if (isset($this->_packageInfo['changelog'])) {
+ return $this->_packageInfo['changelog'];
+ }
+ return false;
+ }
+
+ function getPackagexmlVersion()
+ {
+ return '1.0';
+ }
+
+ /**
+ * Wrapper to {@link PEAR_ErrorStack::getErrors()}
+ * @param boolean determines whether to purge the error stack after retrieving
+ * @return array
+ */
+ function getValidationWarnings($purge = true)
+ {
+ return $this->_stack->getErrors($purge);
+ }
+
+ // }}}
+ /**
+ * Validation error. Also marks the object contents as invalid
+ * @param error code
+ * @param array error information
+ * @access private
+ */
+ function _validateError($code, $params = array())
+ {
+ $this->_stack->push($code, 'error', $params, false, false, debug_backtrace());
+ $this->_isValid = false;
+ }
+
+ /**
+ * Validation warning. Does not mark the object contents invalid.
+ * @param error code
+ * @param array error information
+ * @access private
+ */
+ function _validateWarning($code, $params = array())
+ {
+ $this->_stack->push($code, 'warning', $params, false, false, debug_backtrace());
+ }
+
+ /**
+ * @param integer error code
+ * @access protected
+ */
+ function _getErrorMessage()
+ {
+ return array(
+ PEAR_PACKAGEFILE_ERROR_NO_NAME =>
+ 'Missing Package Name',
+ PEAR_PACKAGEFILE_ERROR_NO_SUMMARY =>
+ 'No summary found',
+ PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY =>
+ 'Summary should be on one line',
+ PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION =>
+ 'Missing description',
+ PEAR_PACKAGEFILE_ERROR_NO_LICENSE =>
+ 'Missing license',
+ PEAR_PACKAGEFILE_ERROR_NO_VERSION =>
+ 'No release version found',
+ PEAR_PACKAGEFILE_ERROR_NO_STATE =>
+ 'No release state found',
+ PEAR_PACKAGEFILE_ERROR_NO_DATE =>
+ 'No release date found',
+ PEAR_PACKAGEFILE_ERROR_NO_NOTES =>
+ 'No release notes found',
+ PEAR_PACKAGEFILE_ERROR_NO_LEAD =>
+ 'Package must have at least one lead maintainer',
+ PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS =>
+ 'No maintainers found, at least one must be defined',
+ PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE =>
+ 'Maintainer %index% has no handle (user ID at channel server)',
+ PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE =>
+ 'Maintainer %index% has no role',
+ PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME =>
+ 'Maintainer %index% has no name',
+ PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL =>
+ 'Maintainer %index% has no email',
+ PEAR_PACKAGEFILE_ERROR_NO_DEPNAME =>
+ 'Dependency %index% is not a php dependency, and has no name',
+ PEAR_PACKAGEFILE_ERROR_NO_DEPREL =>
+ 'Dependency %index% has no relation (rel)',
+ PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE =>
+ 'Dependency %index% has no type',
+ PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED =>
+ 'PHP Dependency %index% has a name attribute of "%name%" which will be' .
+ ' ignored!',
+ PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION =>
+ 'Dependency %index% is not a rel="has" or rel="not" dependency, ' .
+ 'and has no version',
+ PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION =>
+ 'Dependency %index% is a type="php" dependency, ' .
+ 'and has no version',
+ PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED =>
+ 'Dependency %index% is a rel="%rel%" dependency, versioning is ignored',
+ PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL =>
+ 'Dependency %index% has invalid optional value "%opt%", should be yes or no',
+ PEAR_PACKAGEFILE_PHP_NO_NOT =>
+ 'Dependency %index%: php dependencies cannot use "not" rel, use "ne"' .
+ ' to exclude specific versions',
+ PEAR_PACKAGEFILE_ERROR_NO_CONFNAME =>
+ 'Configure Option %index% has no name',
+ PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT =>
+ 'Configure Option %index% has no prompt',
+ PEAR_PACKAGEFILE_ERROR_NO_FILES =>
+ 'No files in section of package.xml',
+ PEAR_PACKAGEFILE_ERROR_NO_FILEROLE =>
+ 'File "%file%" has no role, expecting one of "%roles%"',
+ PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE =>
+ 'File "%file%" has invalid role "%role%", expecting one of "%roles%"',
+ PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME =>
+ 'File "%file%" cannot start with ".", cannot package or install',
+ PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE =>
+ 'Parser error: invalid PHP found in file "%file%"',
+ PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX =>
+ 'in %file%: %type% "%name%" not prefixed with package name "%package%"',
+ PEAR_PACKAGEFILE_ERROR_INVALID_FILE =>
+ 'Parser error: invalid PHP file "%file%"',
+ PEAR_PACKAGEFILE_ERROR_CHANNELVAL =>
+ 'Channel validator error: field "%field%" - %reason%',
+ PEAR_PACKAGEFILE_ERROR_PHP5 =>
+ 'Error, PHP5 token encountered in %file%, analysis should be in PHP5',
+ PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND =>
+ 'File "%file%" in package.xml does not exist',
+ PEAR_PACKAGEFILE_ERROR_NON_ISO_CHARS =>
+ 'Package.xml contains non-ISO-8859-1 characters, and may not validate',
+ );
+ }
+
+ /**
+ * Validate XML package definition file.
+ *
+ * @access public
+ * @return boolean
+ */
+ function validate($state = PEAR_VALIDATE_NORMAL, $nofilechecking = false)
+ {
+ if (($this->_isValid & $state) == $state) {
+ return true;
+ }
+ $this->_isValid = true;
+ $info = $this->_packageInfo;
+ if (empty($info['package'])) {
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_NAME);
+ $this->_packageName = $pn = 'unknown';
+ } else {
+ $this->_packageName = $pn = $info['package'];
+ }
+
+ if (empty($info['summary'])) {
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_SUMMARY);
+ } elseif (strpos(trim($info['summary']), "\n") !== false) {
+ $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_MULTILINE_SUMMARY,
+ array('summary' => $info['summary']));
+ }
+ if (empty($info['description'])) {
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DESCRIPTION);
+ }
+ if (empty($info['release_license'])) {
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_LICENSE);
+ }
+ if (empty($info['version'])) {
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_VERSION);
+ }
+ if (empty($info['release_state'])) {
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_STATE);
+ }
+ if (empty($info['release_date'])) {
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DATE);
+ }
+ if (empty($info['release_notes'])) {
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_NOTES);
+ }
+ if (empty($info['maintainers'])) {
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTAINERS);
+ } else {
+ $haslead = false;
+ $i = 1;
+ foreach ($info['maintainers'] as $m) {
+ if (empty($m['handle'])) {
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTHANDLE,
+ array('index' => $i));
+ }
+ if (empty($m['role'])) {
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTROLE,
+ array('index' => $i, 'roles' => PEAR_Common::getUserRoles()));
+ } elseif ($m['role'] == 'lead') {
+ $haslead = true;
+ }
+ if (empty($m['name'])) {
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTNAME,
+ array('index' => $i));
+ }
+ if (empty($m['email'])) {
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_MAINTEMAIL,
+ array('index' => $i));
+ }
+ $i++;
+ }
+ if (!$haslead) {
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_LEAD);
+ }
+ }
+ if (!empty($info['release_deps'])) {
+ $i = 1;
+ foreach ($info['release_deps'] as $d) {
+ if (!isset($d['type']) || empty($d['type'])) {
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPTYPE,
+ array('index' => $i, 'types' => PEAR_Common::getDependencyTypes()));
+ continue;
+ }
+ if (!isset($d['rel']) || empty($d['rel'])) {
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPREL,
+ array('index' => $i, 'rels' => PEAR_Common::getDependencyRelations()));
+ continue;
+ }
+ if (!empty($d['optional'])) {
+ if (!in_array($d['optional'], array('yes', 'no'))) {
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_DEPOPTIONAL,
+ array('index' => $i, 'opt' => $d['optional']));
+ }
+ }
+ if ($d['rel'] != 'has' && $d['rel'] != 'not' && empty($d['version'])) {
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPVERSION,
+ array('index' => $i));
+ } elseif (($d['rel'] == 'has' || $d['rel'] == 'not') && !empty($d['version'])) {
+ $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_DEPVERSION_IGNORED,
+ array('index' => $i, 'rel' => $d['rel']));
+ }
+ if ($d['type'] == 'php' && !empty($d['name'])) {
+ $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_DEPNAME_IGNORED,
+ array('index' => $i, 'name' => $d['name']));
+ } elseif ($d['type'] != 'php' && empty($d['name'])) {
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPNAME,
+ array('index' => $i));
+ }
+ if ($d['type'] == 'php' && empty($d['version'])) {
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_DEPPHPVERSION,
+ array('index' => $i));
+ }
+ if (($d['rel'] == 'not') && ($d['type'] == 'php')) {
+ $this->_validateError(PEAR_PACKAGEFILE_PHP_NO_NOT,
+ array('index' => $i));
+ }
+ $i++;
+ }
+ }
+ if (!empty($info['configure_options'])) {
+ $i = 1;
+ foreach ($info['configure_options'] as $c) {
+ if (empty($c['name'])) {
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_CONFNAME,
+ array('index' => $i));
+ }
+ if (empty($c['prompt'])) {
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_CONFPROMPT,
+ array('index' => $i));
+ }
+ $i++;
+ }
+ }
+ if (empty($info['filelist'])) {
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_FILES);
+ $errors[] = 'no files';
+ } else {
+ foreach ($info['filelist'] as $file => $fa) {
+ if (empty($fa['role'])) {
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_NO_FILEROLE,
+ array('file' => $file, 'roles' => PEAR_Common::getFileRoles()));
+ continue;
+ } elseif (!in_array($fa['role'], PEAR_Common::getFileRoles())) {
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILEROLE,
+ array('file' => $file, 'role' => $fa['role'], 'roles' => PEAR_Common::getFileRoles()));
+ }
+ if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~', str_replace('\\', '/', $file))) {
+ // file contains .. parent directory or . cur directory references
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME,
+ array('file' => $file));
+ }
+ if (isset($fa['install-as']) &&
+ preg_match('~/\.\.?(/|\\z)|^\.\.?/~',
+ str_replace('\\', '/', $fa['install-as']))) {
+ // install-as contains .. parent directory or . cur directory references
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME,
+ array('file' => $file . ' [installed as ' . $fa['install-as'] . ']'));
+ }
+ if (isset($fa['baseinstalldir']) &&
+ preg_match('~/\.\.?(/|\\z)|^\.\.?/~',
+ str_replace('\\', '/', $fa['baseinstalldir']))) {
+ // install-as contains .. parent directory or . cur directory references
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_FILENAME,
+ array('file' => $file . ' [baseinstalldir ' . $fa['baseinstalldir'] . ']'));
+ }
+ }
+ }
+ if (isset($this->_registry) && $this->_isValid) {
+ $chan = $this->_registry->getChannel('pear.php.net');
+ if (PEAR::isError($chan)) {
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $chan->getMessage());
+ return $this->_isValid = 0;
+ }
+ $validator = $chan->getValidationObject();
+ $validator->setPackageFile($this);
+ $validator->validate($state);
+ $failures = $validator->getFailures();
+ foreach ($failures['errors'] as $error) {
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $error);
+ }
+ foreach ($failures['warnings'] as $warning) {
+ $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_CHANNELVAL, $warning);
+ }
+ }
+ if ($this->_isValid && $state == PEAR_VALIDATE_PACKAGING && !$nofilechecking) {
+ if ($this->_analyzePhpFiles()) {
+ $this->_isValid = true;
+ }
+ }
+ if ($this->_isValid) {
+ return $this->_isValid = $state;
+ }
+ return $this->_isValid = 0;
+ }
+
+ function _analyzePhpFiles()
+ {
+ if (!$this->_isValid) {
+ return false;
+ }
+ if (!isset($this->_packageFile)) {
+ return false;
+ }
+ $dir_prefix = dirname($this->_packageFile);
+ $common = new PEAR_Common;
+ $log = isset($this->_logger) ? array(&$this->_logger, 'log') :
+ array($common, 'log');
+ $info = $this->getFilelist();
+ foreach ($info as $file => $fa) {
+ if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $file)) {
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_FILE_NOTFOUND,
+ array('file' => realpath($dir_prefix) . DIRECTORY_SEPARATOR . $file));
+ continue;
+ }
+ if ($fa['role'] == 'php' && $dir_prefix) {
+ call_user_func_array($log, array(1, "Analyzing $file"));
+ $srcinfo = $this->_analyzeSourceCode($dir_prefix . DIRECTORY_SEPARATOR . $file);
+ if ($srcinfo) {
+ $this->_buildProvidesArray($srcinfo);
+ }
+ }
+ }
+ $this->_packageName = $pn = $this->getPackage();
+ $pnl = strlen($pn);
+ if (isset($this->_packageInfo['provides'])) {
+ foreach ((array) $this->_packageInfo['provides'] as $key => $what) {
+ if (isset($what['explicit'])) {
+ // skip conformance checks if the provides entry is
+ // specified in the package.xml file
+ continue;
+ }
+ extract($what);
+ if ($type == 'class') {
+ if (!strncasecmp($name, $pn, $pnl)) {
+ continue;
+ }
+ $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX,
+ array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn));
+ } elseif ($type == 'function') {
+ if (strstr($name, '::') || !strncasecmp($name, $pn, $pnl)) {
+ continue;
+ }
+ $this->_validateWarning(PEAR_PACKAGEFILE_ERROR_NO_PNAME_PREFIX,
+ array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn));
+ }
+ }
+ }
+ return $this->_isValid;
+ }
+
+ /**
+ * Get the default xml generator object
+ *
+ * @return PEAR_PackageFile_Generator_v1
+ */
+ function &getDefaultGenerator()
+ {
+ if (!class_exists('PEAR_PackageFile_Generator_v1')) {
+ require_once 'PEAR/PackageFile/Generator/v1.php';
+ }
+ $a = new PEAR_PackageFile_Generator_v1($this);
+ return $a;
+ }
+
+ /**
+ * Get the contents of a file listed within the package.xml
+ * @param string
+ * @return string
+ */
+ function getFileContents($file)
+ {
+ if ($this->_archiveFile == $this->_packageFile) { // unpacked
+ $dir = dirname($this->_packageFile);
+ $file = $dir . DIRECTORY_SEPARATOR . $file;
+ $file = str_replace(array('/', '\\'),
+ array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), $file);
+ if (file_exists($file) && is_readable($file)) {
+ return implode('', file($file));
+ }
+ } else { // tgz
+ if (!class_exists('Archive_Tar')) {
+ require_once 'Archive/Tar.php';
+ }
+ $tar = new Archive_Tar($this->_archiveFile);
+ $tar->pushErrorHandling(PEAR_ERROR_RETURN);
+ if ($file != 'package.xml' && $file != 'package2.xml') {
+ $file = $this->getPackage() . '-' . $this->getVersion() . '/' . $file;
+ }
+ $file = $tar->extractInString($file);
+ $tar->popErrorHandling();
+ if (PEAR::isError($file)) {
+ return PEAR::raiseError("Cannot locate file '$file' in archive");
+ }
+ return $file;
+ }
+ }
+
+ // {{{ analyzeSourceCode()
+ /**
+ * Analyze the source code of the given PHP file
+ *
+ * @param string Filename of the PHP file
+ * @return mixed
+ * @access private
+ */
+ function _analyzeSourceCode($file)
+ {
+ if (!function_exists("token_get_all")) {
+ return false;
+ }
+ if (!defined('T_DOC_COMMENT')) {
+ define('T_DOC_COMMENT', T_COMMENT);
+ }
+ if (!defined('T_INTERFACE')) {
+ define('T_INTERFACE', -1);
+ }
+ if (!defined('T_IMPLEMENTS')) {
+ define('T_IMPLEMENTS', -1);
+ }
+ if (!$fp = @fopen($file, "r")) {
+ return false;
+ }
+ fclose($fp);
+ $contents = file_get_contents($file);
+ $tokens = token_get_all($contents);
+/*
+ for ($i = 0; $i < sizeof($tokens); $i++) {
+ @list($token, $data) = $tokens[$i];
+ if (is_string($token)) {
+ var_dump($token);
+ } else {
+ print token_name($token) . ' ';
+ var_dump(rtrim($data));
+ }
+ }
+*/
+ $look_for = 0;
+ $paren_level = 0;
+ $bracket_level = 0;
+ $brace_level = 0;
+ $lastphpdoc = '';
+ $current_class = '';
+ $current_interface = '';
+ $current_class_level = -1;
+ $current_function = '';
+ $current_function_level = -1;
+ $declared_classes = array();
+ $declared_interfaces = array();
+ $declared_functions = array();
+ $declared_methods = array();
+ $used_classes = array();
+ $used_functions = array();
+ $extends = array();
+ $implements = array();
+ $nodeps = array();
+ $inquote = false;
+ $interface = false;
+ for ($i = 0; $i < sizeof($tokens); $i++) {
+ if (is_array($tokens[$i])) {
+ list($token, $data) = $tokens[$i];
+ } else {
+ $token = $tokens[$i];
+ $data = '';
+ }
+ if ($inquote) {
+ if ($token != '"' && $token != T_END_HEREDOC) {
+ continue;
+ } else {
+ $inquote = false;
+ continue;
+ }
+ }
+ switch ($token) {
+ case T_WHITESPACE :
+ continue;
+ case ';':
+ if ($interface) {
+ $current_function = '';
+ $current_function_level = -1;
+ }
+ break;
+ case '"':
+ case T_START_HEREDOC:
+ $inquote = true;
+ break;
+ case T_CURLY_OPEN:
+ case T_DOLLAR_OPEN_CURLY_BRACES:
+ case '{': $brace_level++; continue 2;
+ case '}':
+ $brace_level--;
+ if ($current_class_level == $brace_level) {
+ $current_class = '';
+ $current_class_level = -1;
+ }
+ if ($current_function_level == $brace_level) {
+ $current_function = '';
+ $current_function_level = -1;
+ }
+ continue 2;
+ case '[': $bracket_level++; continue 2;
+ case ']': $bracket_level--; continue 2;
+ case '(': $paren_level++; continue 2;
+ case ')': $paren_level--; continue 2;
+ case T_INTERFACE:
+ $interface = true;
+ case T_CLASS:
+ if (($current_class_level != -1) || ($current_function_level != -1)) {
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE,
+ array('file' => $file));
+ return false;
+ }
+ case T_FUNCTION:
+ case T_NEW:
+ case T_EXTENDS:
+ case T_IMPLEMENTS:
+ $look_for = $token;
+ continue 2;
+ case T_STRING:
+ if ($look_for == T_CLASS) {
+ $current_class = $data;
+ $current_class_level = $brace_level;
+ $declared_classes[] = $current_class;
+ } elseif ($look_for == T_INTERFACE) {
+ $current_interface = $data;
+ $current_class_level = $brace_level;
+ $declared_interfaces[] = $current_interface;
+ } elseif ($look_for == T_IMPLEMENTS) {
+ $implements[$current_class] = $data;
+ } elseif ($look_for == T_EXTENDS) {
+ $extends[$current_class] = $data;
+ } elseif ($look_for == T_FUNCTION) {
+ if ($current_class) {
+ $current_function = "$current_class::$data";
+ $declared_methods[$current_class][] = $data;
+ } elseif ($current_interface) {
+ $current_function = "$current_interface::$data";
+ $declared_methods[$current_interface][] = $data;
+ } else {
+ $current_function = $data;
+ $declared_functions[] = $current_function;
+ }
+ $current_function_level = $brace_level;
+ $m = array();
+ } elseif ($look_for == T_NEW) {
+ $used_classes[$data] = true;
+ }
+ $look_for = 0;
+ continue 2;
+ case T_VARIABLE:
+ $look_for = 0;
+ continue 2;
+ case T_DOC_COMMENT:
+ case T_COMMENT:
+ if (preg_match('!^/\*\*\s!', $data)) {
+ $lastphpdoc = $data;
+ if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m)) {
+ $nodeps = array_merge($nodeps, $m[1]);
+ }
+ }
+ continue 2;
+ case T_DOUBLE_COLON:
+ if (!($tokens[$i - 1][0] == T_WHITESPACE || $tokens[$i - 1][0] == T_STRING)) {
+ $this->_validateError(PEAR_PACKAGEFILE_ERROR_INVALID_PHPFILE,
+ array('file' => $file));
+ return false;
+ }
+ $class = $tokens[$i - 1][1];
+ if (strtolower($class) != 'parent') {
+ $used_classes[$class] = true;
+ }
+ continue 2;
+ }
+ }
+ return array(
+ "source_file" => $file,
+ "declared_classes" => $declared_classes,
+ "declared_interfaces" => $declared_interfaces,
+ "declared_methods" => $declared_methods,
+ "declared_functions" => $declared_functions,
+ "used_classes" => array_diff(array_keys($used_classes), $nodeps),
+ "inheritance" => $extends,
+ "implements" => $implements,
+ );
+ }
+
+ /**
+ * Build a "provides" array from data returned by
+ * analyzeSourceCode(). The format of the built array is like
+ * this:
+ *
+ * array(
+ * 'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'),
+ * ...
+ * )
+ *
+ *
+ * @param array $srcinfo array with information about a source file
+ * as returned by the analyzeSourceCode() method.
+ *
+ * @return void
+ *
+ * @access private
+ *
+ */
+ function _buildProvidesArray($srcinfo)
+ {
+ if (!$this->_isValid) {
+ return false;
+ }
+ $file = basename($srcinfo['source_file']);
+ $pn = $this->getPackage();
+ $pnl = strlen($pn);
+ foreach ($srcinfo['declared_classes'] as $class) {
+ $key = "class;$class";
+ if (isset($this->_packageInfo['provides'][$key])) {
+ continue;
+ }
+ $this->_packageInfo['provides'][$key] =
+ array('file'=> $file, 'type' => 'class', 'name' => $class);
+ if (isset($srcinfo['inheritance'][$class])) {
+ $this->_packageInfo['provides'][$key]['extends'] =
+ $srcinfo['inheritance'][$class];
+ }
+ }
+ foreach ($srcinfo['declared_methods'] as $class => $methods) {
+ foreach ($methods as $method) {
+ $function = "$class::$method";
+ $key = "function;$function";
+ if ($method{0} == '_' || !strcasecmp($method, $class) ||
+ isset($this->_packageInfo['provides'][$key])) {
+ continue;
+ }
+ $this->_packageInfo['provides'][$key] =
+ array('file'=> $file, 'type' => 'function', 'name' => $function);
+ }
+ }
+
+ foreach ($srcinfo['declared_functions'] as $function) {
+ $key = "function;$function";
+ if ($function{0} == '_' || isset($this->_packageInfo['provides'][$key])) {
+ continue;
+ }
+ if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) {
+ $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\"";
+ }
+ $this->_packageInfo['provides'][$key] =
+ array('file'=> $file, 'type' => 'function', 'name' => $function);
+ }
+ }
+
+ // }}}
+}
+?>
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/PackageFile/v2.php b/vendor/pear-pear.php.net/PEAR/PEAR/PackageFile/v2.php
new file mode 100644
index 000000000..248997a6a
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/PackageFile/v2.php
@@ -0,0 +1,2059 @@
+
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+/**
+ * For error handling
+ */
+require_once 'PEAR/ErrorStack.php';
+/**
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_PackageFile_v2
+{
+
+ /**
+ * Parsed package information
+ * @var array
+ * @access private
+ */
+ var $_packageInfo = array();
+
+ /**
+ * path to package .tgz or false if this is a local/extracted package.xml
+ * @var string|false
+ * @access private
+ */
+ var $_archiveFile;
+
+ /**
+ * path to package .xml or false if this is an abstract parsed-from-string xml
+ * @var string|false
+ * @access private
+ */
+ var $_packageFile;
+
+ /**
+ * This is used by file analysis routines to log progress information
+ * @var PEAR_Common
+ * @access protected
+ */
+ var $_logger;
+
+ /**
+ * This is set to the highest validation level that has been validated
+ *
+ * If the package.xml is invalid or unknown, this is set to 0. If
+ * normal validation has occurred, this is set to PEAR_VALIDATE_NORMAL. If
+ * downloading/installation validation has occurred it is set to PEAR_VALIDATE_DOWNLOADING
+ * or INSTALLING, and so on up to PEAR_VALIDATE_PACKAGING. This allows validation
+ * "caching" to occur, which is particularly important for package validation, so
+ * that PHP files are not validated twice
+ * @var int
+ * @access private
+ */
+ var $_isValid = 0;
+
+ /**
+ * True if the filelist has been validated
+ * @param bool
+ */
+ var $_filesValid = false;
+
+ /**
+ * @var PEAR_Registry
+ * @access protected
+ */
+ var $_registry;
+
+ /**
+ * @var PEAR_Config
+ * @access protected
+ */
+ var $_config;
+
+ /**
+ * Optional Dependency group requested for installation
+ * @var string
+ * @access private
+ */
+ var $_requestedGroup = false;
+
+ /**
+ * @var PEAR_ErrorStack
+ * @access protected
+ */
+ var $_stack;
+
+ /**
+ * Namespace prefix used for tasks in this package.xml - use tasks: whenever possible
+ */
+ var $_tasksNs;
+
+ /**
+ * Determines whether this packagefile was initialized only with partial package info
+ *
+ * If this package file was constructed via parsing REST, it will only contain
+ *
+ * - package name
+ * - channel name
+ * - dependencies
+ * @var boolean
+ * @access private
+ */
+ var $_incomplete = true;
+
+ /**
+ * @var PEAR_PackageFile_v2_Validator
+ */
+ var $_v2Validator;
+
+ /**
+ * The constructor merely sets up the private error stack
+ */
+ function __construct()
+ {
+ $this->_stack = new PEAR_ErrorStack('PEAR_PackageFile_v2', false, null);
+ $this->_isValid = false;
+ }
+
+ /**
+ * PHP 4 style constructor for backwards compatibility.
+ * Used by PEAR_PackageFileManager2
+ */
+ public function PEAR_PackageFile_v2()
+ {
+ $this->__construct();
+ }
+
+ /**
+ * To make unit-testing easier
+ * @param PEAR_Frontend_*
+ * @param array options
+ * @param PEAR_Config
+ * @return PEAR_Downloader
+ * @access protected
+ */
+ function &getPEARDownloader(&$i, $o, &$c)
+ {
+ $z = new PEAR_Downloader($i, $o, $c);
+ return $z;
+ }
+
+ /**
+ * To make unit-testing easier
+ * @param PEAR_Config
+ * @param array options
+ * @param array package name as returned from {@link PEAR_Registry::parsePackageName()}
+ * @param int PEAR_VALIDATE_* constant
+ * @return PEAR_Dependency2
+ * @access protected
+ */
+ function &getPEARDependency2(&$c, $o, $p, $s = PEAR_VALIDATE_INSTALLING)
+ {
+ if (!class_exists('PEAR_Dependency2')) {
+ require_once 'PEAR/Dependency2.php';
+ }
+ $z = new PEAR_Dependency2($c, $o, $p, $s);
+ return $z;
+ }
+
+ function getInstalledBinary()
+ {
+ return isset($this->_packageInfo['#binarypackage']) ? $this->_packageInfo['#binarypackage'] :
+ false;
+ }
+
+ /**
+ * Installation of source package has failed, attempt to download and install the
+ * binary version of this package.
+ * @param PEAR_Installer
+ * @return array|false
+ */
+ function installBinary(&$installer)
+ {
+ if (!OS_WINDOWS) {
+ $a = false;
+ return $a;
+ }
+ if ($this->getPackageType() == 'extsrc' || $this->getPackageType() == 'zendextsrc') {
+ $releasetype = $this->getPackageType() . 'release';
+ if (!is_array($installer->getInstallPackages())) {
+ $a = false;
+ return $a;
+ }
+ foreach ($installer->getInstallPackages() as $p) {
+ if ($p->isExtension($this->_packageInfo['providesextension'])) {
+ if ($p->getPackageType() != 'extsrc' && $p->getPackageType() != 'zendextsrc') {
+ $a = false;
+ return $a; // the user probably downloaded it separately
+ }
+ }
+ }
+ if (isset($this->_packageInfo[$releasetype]['binarypackage'])) {
+ $installer->log(0, 'Attempting to download binary version of extension "' .
+ $this->_packageInfo['providesextension'] . '"');
+ $params = $this->_packageInfo[$releasetype]['binarypackage'];
+ if (!is_array($params) || !isset($params[0])) {
+ $params = array($params);
+ }
+ if (isset($this->_packageInfo['channel'])) {
+ foreach ($params as $i => $param) {
+ $params[$i] = array('channel' => $this->_packageInfo['channel'],
+ 'package' => $param, 'version' => $this->getVersion());
+ }
+ }
+ $dl = &$this->getPEARDownloader($installer->ui, $installer->getOptions(),
+ $installer->config);
+ $verbose = $dl->config->get('verbose');
+ $dl->config->set('verbose', -1);
+ foreach ($params as $param) {
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ $ret = $dl->download(array($param));
+ PEAR::popErrorHandling();
+ if (is_array($ret) && count($ret)) {
+ break;
+ }
+ }
+ $dl->config->set('verbose', $verbose);
+ if (is_array($ret)) {
+ if (count($ret) == 1) {
+ $pf = $ret[0]->getPackageFile();
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ $err = $installer->install($ret[0]);
+ PEAR::popErrorHandling();
+ if (is_array($err)) {
+ $this->_packageInfo['#binarypackage'] = $ret[0]->getPackage();
+ // "install" self, so all dependencies will work transparently
+ $this->_registry->addPackage2($this);
+ $installer->log(0, 'Download and install of binary extension "' .
+ $this->_registry->parsedPackageNameToString(
+ array('channel' => $pf->getChannel(),
+ 'package' => $pf->getPackage()), true) . '" successful');
+ $a = array($ret[0], $err);
+ return $a;
+ }
+ $installer->log(0, 'Download and install of binary extension "' .
+ $this->_registry->parsedPackageNameToString(
+ array('channel' => $pf->getChannel(),
+ 'package' => $pf->getPackage()), true) . '" failed');
+ }
+ }
+ }
+ }
+ $a = false;
+ return $a;
+ }
+
+ /**
+ * @return string|false Extension name
+ */
+ function getProvidesExtension()
+ {
+ if (in_array($this->getPackageType(),
+ array('extsrc', 'extbin', 'zendextsrc', 'zendextbin'))) {
+ if (isset($this->_packageInfo['providesextension'])) {
+ return $this->_packageInfo['providesextension'];
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @param string Extension name
+ * @return bool
+ */
+ function isExtension($extension)
+ {
+ if (in_array($this->getPackageType(),
+ array('extsrc', 'extbin', 'zendextsrc', 'zendextbin'))) {
+ return $this->_packageInfo['providesextension'] == $extension;
+ }
+ return false;
+ }
+
+ /**
+ * Tests whether every part of the package.xml 1.0 is represented in
+ * this package.xml 2.0
+ * @param PEAR_PackageFile_v1
+ * @return bool
+ */
+ function isEquivalent($pf1)
+ {
+ if (!$pf1) {
+ return true;
+ }
+ if ($this->getPackageType() == 'bundle') {
+ return false;
+ }
+ $this->_stack->getErrors(true);
+ if (!$pf1->validate(PEAR_VALIDATE_NORMAL)) {
+ return false;
+ }
+ $pass = true;
+ if ($pf1->getPackage() != $this->getPackage()) {
+ $this->_differentPackage($pf1->getPackage());
+ $pass = false;
+ }
+ if ($pf1->getVersion() != $this->getVersion()) {
+ $this->_differentVersion($pf1->getVersion());
+ $pass = false;
+ }
+ if (trim($pf1->getSummary()) != $this->getSummary()) {
+ $this->_differentSummary($pf1->getSummary());
+ $pass = false;
+ }
+ if (preg_replace('/\s+/', '', $pf1->getDescription()) !=
+ preg_replace('/\s+/', '', $this->getDescription())) {
+ $this->_differentDescription($pf1->getDescription());
+ $pass = false;
+ }
+ if ($pf1->getState() != $this->getState()) {
+ $this->_differentState($pf1->getState());
+ $pass = false;
+ }
+ if (!strstr(preg_replace('/\s+/', '', $this->getNotes()),
+ preg_replace('/\s+/', '', $pf1->getNotes()))) {
+ $this->_differentNotes($pf1->getNotes());
+ $pass = false;
+ }
+ $mymaintainers = $this->getMaintainers();
+ $yourmaintainers = $pf1->getMaintainers();
+ for ($i1 = 0; $i1 < count($yourmaintainers); $i1++) {
+ $reset = false;
+ for ($i2 = 0; $i2 < count($mymaintainers); $i2++) {
+ if ($mymaintainers[$i2]['handle'] == $yourmaintainers[$i1]['handle']) {
+ if ($mymaintainers[$i2]['role'] != $yourmaintainers[$i1]['role']) {
+ $this->_differentRole($mymaintainers[$i2]['handle'],
+ $yourmaintainers[$i1]['role'], $mymaintainers[$i2]['role']);
+ $pass = false;
+ }
+ if ($mymaintainers[$i2]['email'] != $yourmaintainers[$i1]['email']) {
+ $this->_differentEmail($mymaintainers[$i2]['handle'],
+ $yourmaintainers[$i1]['email'], $mymaintainers[$i2]['email']);
+ $pass = false;
+ }
+ if ($mymaintainers[$i2]['name'] != $yourmaintainers[$i1]['name']) {
+ $this->_differentName($mymaintainers[$i2]['handle'],
+ $yourmaintainers[$i1]['name'], $mymaintainers[$i2]['name']);
+ $pass = false;
+ }
+ unset($mymaintainers[$i2]);
+ $mymaintainers = array_values($mymaintainers);
+ unset($yourmaintainers[$i1]);
+ $yourmaintainers = array_values($yourmaintainers);
+ $reset = true;
+ break;
+ }
+ }
+ if ($reset) {
+ $i1 = -1;
+ }
+ }
+ $this->_unmatchedMaintainers($mymaintainers, $yourmaintainers);
+ $filelist = $this->getFilelist();
+ foreach ($pf1->getFilelist() as $file => $atts) {
+ if (!isset($filelist[$file])) {
+ $this->_missingFile($file);
+ $pass = false;
+ }
+ }
+ return $pass;
+ }
+
+ function _differentPackage($package)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('package' => $package,
+ 'self' => $this->getPackage()),
+ 'package.xml 1.0 package "%package%" does not match "%self%"');
+ }
+
+ function _differentVersion($version)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('version' => $version,
+ 'self' => $this->getVersion()),
+ 'package.xml 1.0 version "%version%" does not match "%self%"');
+ }
+
+ function _differentState($state)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('state' => $state,
+ 'self' => $this->getState()),
+ 'package.xml 1.0 state "%state%" does not match "%self%"');
+ }
+
+ function _differentRole($handle, $role, $selfrole)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle,
+ 'role' => $role, 'self' => $selfrole),
+ 'package.xml 1.0 maintainer "%handle%" role "%role%" does not match "%self%"');
+ }
+
+ function _differentEmail($handle, $email, $selfemail)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle,
+ 'email' => $email, 'self' => $selfemail),
+ 'package.xml 1.0 maintainer "%handle%" email "%email%" does not match "%self%"');
+ }
+
+ function _differentName($handle, $name, $selfname)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('handle' => $handle,
+ 'name' => $name, 'self' => $selfname),
+ 'package.xml 1.0 maintainer "%handle%" name "%name%" does not match "%self%"');
+ }
+
+ function _unmatchedMaintainers($my, $yours)
+ {
+ if ($my) {
+ array_walk($my, create_function('&$i, $k', '$i = $i["handle"];'));
+ $this->_stack->push(__FUNCTION__, 'error', array('handles' => $my),
+ 'package.xml 2.0 has unmatched extra maintainers "%handles%"');
+ }
+ if ($yours) {
+ array_walk($yours, create_function('&$i, $k', '$i = $i["handle"];'));
+ $this->_stack->push(__FUNCTION__, 'error', array('handles' => $yours),
+ 'package.xml 1.0 has unmatched extra maintainers "%handles%"');
+ }
+ }
+
+ function _differentNotes($notes)
+ {
+ $truncnotes = strlen($notes) < 25 ? $notes : substr($notes, 0, 24) . '...';
+ $truncmynotes = strlen($this->getNotes()) < 25 ? $this->getNotes() :
+ substr($this->getNotes(), 0, 24) . '...';
+ $this->_stack->push(__FUNCTION__, 'error', array('notes' => $truncnotes,
+ 'self' => $truncmynotes),
+ 'package.xml 1.0 release notes "%notes%" do not match "%self%"');
+ }
+
+ function _differentSummary($summary)
+ {
+ $truncsummary = strlen($summary) < 25 ? $summary : substr($summary, 0, 24) . '...';
+ $truncmysummary = strlen($this->getsummary()) < 25 ? $this->getSummary() :
+ substr($this->getsummary(), 0, 24) . '...';
+ $this->_stack->push(__FUNCTION__, 'error', array('summary' => $truncsummary,
+ 'self' => $truncmysummary),
+ 'package.xml 1.0 summary "%summary%" does not match "%self%"');
+ }
+
+ function _differentDescription($description)
+ {
+ $truncdescription = trim(strlen($description) < 25 ? $description : substr($description, 0, 24) . '...');
+ $truncmydescription = trim(strlen($this->getDescription()) < 25 ? $this->getDescription() :
+ substr($this->getdescription(), 0, 24) . '...');
+ $this->_stack->push(__FUNCTION__, 'error', array('description' => $truncdescription,
+ 'self' => $truncmydescription),
+ 'package.xml 1.0 description "%description%" does not match "%self%"');
+ }
+
+ function _missingFile($file)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('file' => $file),
+ 'package.xml 1.0 file "%file%" is not present in ');
+ }
+
+ /**
+ * WARNING - do not use this function unless you know what you're doing
+ */
+ function setRawState($state)
+ {
+ if (!isset($this->_packageInfo['stability'])) {
+ $this->_packageInfo['stability'] = array();
+ }
+ $this->_packageInfo['stability']['release'] = $state;
+ }
+
+ /**
+ * WARNING - do not use this function unless you know what you're doing
+ */
+ function setRawCompatible($compatible)
+ {
+ $this->_packageInfo['compatible'] = $compatible;
+ }
+
+ /**
+ * WARNING - do not use this function unless you know what you're doing
+ */
+ function setRawPackage($package)
+ {
+ $this->_packageInfo['name'] = $package;
+ }
+
+ /**
+ * WARNING - do not use this function unless you know what you're doing
+ */
+ function setRawChannel($channel)
+ {
+ $this->_packageInfo['channel'] = $channel;
+ }
+
+ function setRequestedGroup($group)
+ {
+ $this->_requestedGroup = $group;
+ }
+
+ function getRequestedGroup()
+ {
+ if (isset($this->_requestedGroup)) {
+ return $this->_requestedGroup;
+ }
+ return false;
+ }
+
+ /**
+ * For saving in the registry.
+ *
+ * Set the last version that was installed
+ * @param string
+ */
+ function setLastInstalledVersion($version)
+ {
+ $this->_packageInfo['_lastversion'] = $version;
+ }
+
+ /**
+ * @return string|false
+ */
+ function getLastInstalledVersion()
+ {
+ if (isset($this->_packageInfo['_lastversion'])) {
+ return $this->_packageInfo['_lastversion'];
+ }
+ return false;
+ }
+
+ /**
+ * Determines whether this package.xml has post-install scripts or not
+ * @return array|false
+ */
+ function listPostinstallScripts()
+ {
+ $filelist = $this->getFilelist();
+ $contents = $this->getContents();
+ $contents = $contents['dir']['file'];
+ if (!is_array($contents) || !isset($contents[0])) {
+ $contents = array($contents);
+ }
+ $taskfiles = array();
+ foreach ($contents as $file) {
+ $atts = $file['attribs'];
+ unset($file['attribs']);
+ if (count($file)) {
+ $taskfiles[$atts['name']] = $file;
+ }
+ }
+ $common = new PEAR_Common;
+ $common->debug = $this->_config->get('verbose');
+ $this->_scripts = array();
+ $ret = array();
+ foreach ($taskfiles as $name => $tasks) {
+ if (!isset($filelist[$name])) {
+ // ignored files will not be in the filelist
+ continue;
+ }
+ $atts = $filelist[$name];
+ foreach ($tasks as $tag => $raw) {
+ $task = $this->getTask($tag);
+ $task = new $task($this->_config, $common, PEAR_TASK_INSTALL);
+ if ($task->isScript()) {
+ $ret[] = $filelist[$name]['installed_as'];
+ }
+ }
+ }
+ if (count($ret)) {
+ return $ret;
+ }
+ return false;
+ }
+
+ /**
+ * Initialize post-install scripts for running
+ *
+ * This method can be used to detect post-install scripts, as the return value
+ * indicates whether any exist
+ * @return bool
+ */
+ function initPostinstallScripts()
+ {
+ $filelist = $this->getFilelist();
+ $contents = $this->getContents();
+ $contents = $contents['dir']['file'];
+ if (!is_array($contents) || !isset($contents[0])) {
+ $contents = array($contents);
+ }
+ $taskfiles = array();
+ foreach ($contents as $file) {
+ $atts = $file['attribs'];
+ unset($file['attribs']);
+ if (count($file)) {
+ $taskfiles[$atts['name']] = $file;
+ }
+ }
+ $common = new PEAR_Common;
+ $common->debug = $this->_config->get('verbose');
+ $this->_scripts = array();
+ foreach ($taskfiles as $name => $tasks) {
+ if (!isset($filelist[$name])) {
+ // file was not installed due to installconditions
+ continue;
+ }
+ $atts = $filelist[$name];
+ foreach ($tasks as $tag => $raw) {
+ $taskname = $this->getTask($tag);
+ $task = new $taskname($this->_config, $common, PEAR_TASK_INSTALL);
+ if (!$task->isScript()) {
+ continue; // scripts are only handled after installation
+ }
+ $lastversion = isset($this->_packageInfo['_lastversion']) ?
+ $this->_packageInfo['_lastversion'] : null;
+ $task->init($raw, $atts, $lastversion);
+ $res = $task->startSession($this, $atts['installed_as'], null);
+ if (!$res) {
+ continue; // skip this file
+ }
+ if (PEAR::isError($res)) {
+ return $res;
+ }
+ $this->_scripts[] = $task;
+ }
+ }
+ if (count($this->_scripts)) {
+ return true;
+ }
+ return false;
+ }
+
+ function runPostinstallScripts()
+ {
+ if ($this->initPostinstallScripts()) {
+ $ui = &PEAR_Frontend::singleton();
+ if ($ui) {
+ $ui->runPostinstallScripts($this->_scripts, $this);
+ }
+ }
+ }
+
+
+ /**
+ * Convert a recursive set of