diff --git a/boot.php b/boot.php
index 438c6bb1f..1d8a9e7f7 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']) ||
@@ -2472,7 +2472,7 @@ function get_temppath() {
// Check if it is usable
if (($temppath != "") AND App::directory_usable($temppath)) {
// To avoid any interferences with other systems we create our own directory
- $new_temppath .= "/".$a->get_hostname();
+ $new_temppath = $temppath."/".$a->get_hostname();
if (!is_dir($new_temppath)) {
/// @TODO There is a mkdir()+chmod() upwards, maybe generalize this (+ configurable) into a function/method?
mkdir($new_temppath);
diff --git a/composer.json b/composer.json
index a7800ffff..8b4a630d3 100644
--- a/composer.json
+++ b/composer.json
@@ -14,8 +14,16 @@
},
"require": {
"ezyang/htmlpurifier": "~4.7.0",
- "mobiledetect/mobiledetectlib": "2.8.*"
+ "mobiledetect/mobiledetectlib": "2.8.*",
+ "league/html-to-markdown": "~4.4.1",
+ "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..b46614f6e 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": "802372ddf124ef949e80dd8dc1d38797",
"packages": [
{
"name": "ezyang/htmlpurifier",
@@ -50,6 +50,70 @@
],
"time": "2015-08-05T01:03:42+00:00"
},
+ {
+ "name": "league/html-to-markdown",
+ "version": "4.4.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/thephpleague/html-to-markdown.git",
+ "reference": "82ea375b5b2b1da1da222644c0565c695bf88186"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/82ea375b5b2b1da1da222644c0565c695bf88186",
+ "reference": "82ea375b5b2b1da1da222644c0565c695bf88186",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-xml": "*",
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "mikehaertl/php-shellcommand": "~1.1.0",
+ "phpunit/phpunit": "4.*",
+ "scrutinizer/ocular": "~1.1"
+ },
+ "bin": [
+ "bin/html-to-markdown"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.5-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "League\\HTMLToMarkdown\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Colin O'Dell",
+ "email": "colinodell@gmail.com",
+ "homepage": "http://www.colinodell.com",
+ "role": "Lead Developer"
+ },
+ {
+ "name": "Nick Cernis",
+ "email": "nick@cern.is",
+ "homepage": "http://modernnerd.net",
+ "role": "Original Author"
+ }
+ ],
+ "description": "An HTML-to-markdown conversion helper for PHP",
+ "homepage": "https://github.com/thephpleague/html-to-markdown",
+ "keywords": [
+ "html",
+ "markdown"
+ ],
+ "time": "2017-03-16T00:45:59+00:00"
+ },
{
"name": "mobiledetect/mobiledetectlib",
"version": "2.8.25",
@@ -101,6 +165,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/doc/Composer.md b/doc/Composer.md
index d0e930e34..8310baf3f 100644
--- a/doc/Composer.md
+++ b/doc/Composer.md
@@ -95,4 +95,21 @@ If a package needs to be updated, whether to the next minor version or to the ne
Then you should run `util/composer.phar update` to update it in your local `vendor` folder and update the `composer.lock` file that specifies the current versions of the dependencies.
-Please note that you should commit both `composer.json` and `composer.lock` with your work every time you make a change to the former.
\ No newline at end of file
+Please note that you should commit both `composer.json` and `composer.lock` with your work every time you make a change to the former.
+
+## Composer FAQ
+
+### I used the `composer` command and got a warning about not to run it as root.
+
+See [https://getcomposer.org/root]().
+Composer should be run as the web server user, usually `www-data` with Apache or `http` with nginx.
+If you can't switch to the web server user using `su - [web user]`, you can directly run the Composer command with `sudo -u [web user]`.
+
+### Running Composer with `sudo` complains about not being able to create the composer cache directory in `/root/.composer`
+
+This is because `sudo` doesn't always change the `HOME` environment variable, which means that the command is run as the web server user but the system still uses `root` home directory.
+However, you can temporarily change environment variable for the execution of a single command.
+For Composer, this would be:
+````
+$> COMPOSER_HOME=/var/tmp/composer sudo -u [web user] util/composer.phar [mode]
+````
diff --git a/include/bb2diaspora.php b/include/bb2diaspora.php
index 95e236524..a07a58353 100644
--- a/include/bb2diaspora.php
+++ b/include/bb2diaspora.php
@@ -1,11 +1,12 @@
convert($Text);
// unmask the special chars back to HTML
- $Text = str_replace(array('&_lt_;','&_gt_;','&_amp_;'),array('<','>','&'),$Text);
+ $Text = str_replace(array('&_lt_;', '&_gt_;', '&_amp_;'), array('<', '>', '&'), $Text);
$a->save_timestamp($stamp1, "parser");
@@ -176,14 +201,25 @@ function bb2diaspora($Text, $preserve_nl = false, $fordiaspora = true) {
$Text = preg_replace_callback("/([@]\[(.*?)\])\(([$URLSearchString]*?)\)/ism", 'diaspora_mentions', $Text);
}
+ // Restore code blocks
+ $Text = preg_replace_callback('/#codeblock-([0-9]+)#/iU',
+ function ($matches) use ($codeblocks) {
+ $return = '';
+ if (isset($codeblocks[intval($matches[1])])) {
+ $return = $codeblocks[$matches[1]];
+ }
+ return $return;
+ }
+ , $Text);
+
call_hooks('bb2diaspora',$Text);
return $Text;
}
function unescape_underscores_in_links($m) {
- $y = str_replace('\\_','_', $m[2]);
- return '[' . $m[1] . '](' . $y . ')';
+ $y = str_replace('\\_', '_', $m[2]);
+ return('[' . $m[1] . '](' . $y . ')');
}
function format_event_diaspora($ev) {
diff --git a/include/bbcode.php b/include/bbcode.php
index eccf32d5b..97b1b6c0c 100644
--- a/include/bbcode.php
+++ b/include/bbcode.php
@@ -1,12 +1,12 @@
', '', $s[1]) . '[/code]';
}
-function bb_onelinecode_cb($match) {
- if (strpos($match[1], "
") === false) {
- return "" . $match[1] . "
";
-}
-
-function tryoembed($match){
+function tryoembed($match) {
$url = $match[1];
// Always embed the SSL version
@@ -203,7 +196,6 @@ function tryoembed($match){
$html = oembed_format_object($o);
return $html;
-
}
// [noparse][i]italic[/i][/noparse] turns into
@@ -230,14 +222,13 @@ function bb_unspacefy_and_trim($st) {
}
function bb_find_open_close($s, $open, $close, $occurence = 1) {
-
- if ($occurence < 1) {
- $occurence = 1;
- }
+ if ($occurence < 1) {
+ $occurence = 1;
+ }
$start_pos = -1;
for ($i = 1; $i <= $occurence; $i++) {
- if ($start_pos !== false) {
+ if ( $start_pos !== false) {
$start_pos = strpos($s, $open, $start_pos + 1);
}
}
@@ -258,14 +249,13 @@ function bb_find_open_close($s, $open, $close, $occurence = 1) {
}
function get_bb_tag_pos($s, $name, $occurence = 1) {
-
if ($occurence < 1) {
$occurence = 1;
- }
+ }
$start_open = -1;
for ($i = 1; $i <= $occurence; $i++) {
- if ($start_open !== false) {
+ if ( $start_open !== false) {
$start_open = strpos($s, '[' . $name, $start_open + 1); // allow [name= type tags
}
}
@@ -314,7 +304,6 @@ function bb_tag_preg_replace($pattern, $replace, $name, $s) {
$occurence = 1;
$pos = get_bb_tag_pos($string, $name, $occurence);
while ($pos !== false && $occurence < 1000) {
-
$start = substr($string, 0, $pos['start']['open']);
$subject = substr($string, $pos['start']['open'], $pos['end']['close'] - $pos['start']['open']);
$end = substr($string, $pos['end']['close']);
@@ -766,19 +755,41 @@ function bb_highlight($match) {
return $match[0];
}
- // BBcode 2 HTML was written by WAY2WEB.net
- // extended to work with Mistpark/Friendica - Mike Macgirvin
-
-function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = false, $forplaintext = false) {
+/**
+ * @brief Converts a BBCode message to HTML message
+ *
+ * BBcode 2 HTML was written by WAY2WEB.net
+ * extended to work with Mistpark/Friendica - Mike Macgirvin
+ *
+ * Simple HTML values meaning:
+ * - 0: Friendica display
+ * - 1: Unused
+ * - 2: Used for Facebook, Google+, Windows Phone push, Friendica API
+ * - 3: Used before converting to Markdown in bb2diaspora.php
+ * - 4: Used for WordPress, Libertree (before Markdown), pump.io and tumblr
+ * - 5: Unused
+ * - 6: Used for Appnet
+ * - 7: Used for dfrn, OStatus
+ * - 8: Used for WP backlink text setting
+ *
+ * @staticvar array $allowed_src_protocols
+ * @param string $Text
+ * @param bool $preserve_nl
+ * @param bool $tryoembed
+ * @param int $simplehtml
+ * @param bool $forplaintext
+ * @return string
+ */
+function bbcode($Text, $preserve_nl = false, $tryoembed = true, $simplehtml = false, $forplaintext = false) {
$a = get_app();
// Hide all [noparse] contained bbtags by spacefying them
// POSSIBLE BUG --> Will the 'preg' functions crash if there's an embedded image?
- $Text = preg_replace_callback("/\[noparse\](.*?)\[\/noparse\]/ism", 'bb_spacefy',$Text);
- $Text = preg_replace_callback("/\[nobb\](.*?)\[\/nobb\]/ism", 'bb_spacefy',$Text);
- $Text = preg_replace_callback("/\[pre\](.*?)\[\/pre\]/ism", 'bb_spacefy',$Text);
+ $Text = preg_replace_callback("/\[noparse\](.*?)\[\/noparse\]/ism", 'bb_spacefy', $Text);
+ $Text = preg_replace_callback("/\[nobb\](.*?)\[\/nobb\]/ism", 'bb_spacefy', $Text);
+ $Text = preg_replace_callback("/\[pre\](.*?)\[\/pre\]/ism", 'bb_spacefy', $Text);
// Remove the abstract element. It is a non visible element.
$Text = remove_abstract($Text);
@@ -808,19 +819,20 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
$Text = str_replace(">", ">", $Text);
// remove some newlines before the general conversion
- $Text = preg_replace("/\s?\[share(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism","[share$1]$2[/share]",$Text);
- $Text = preg_replace("/\s?\[quote(.*?)\]\s?(.*?)\s?\[\/quote\]\s?/ism","[quote$1]$2[/quote]",$Text);
+ $Text = preg_replace("/\s?\[share(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism", "[share$1]$2[/share]", $Text);
+ $Text = preg_replace("/\s?\[quote(.*?)\]\s?(.*?)\s?\[\/quote\]\s?/ism", "[quote$1]$2[/quote]", $Text);
$Text = preg_replace("/\n\[code\]/ism", "[code]", $Text);
$Text = preg_replace("/\[\/code\]\n/ism", "[/code]", $Text);
// when the content is meant exporting to other systems then remove the avatar picture since this doesn't really look good on these systems
- if (!$tryoembed)
- $Text = preg_replace("/\[share(.*?)avatar\s?=\s?'.*?'\s?(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism","\n[share$1$2]$3[/share]",$Text);
+ if (!$tryoembed) {
+ $Text = preg_replace("/\[share(.*?)avatar\s?=\s?'.*?'\s?(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism", "\n[share$1$2]$3[/share]", $Text);
+ }
// Check for [code] text here, before the linefeeds are messed with.
// The highlighter will unescape and re-escape the content.
- if (strpos($Text,'[code=') !== false) {
+ if (strpos($Text, '[code=') !== false) {
$Text = preg_replace_callback("/\[code=(.*?)\](.*?)\[\/code\]/ism", 'bb_highlight', $Text);
}
// Convert new line chars to html
tags
@@ -831,7 +843,7 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
// We'll emulate it.
$Text = trim($Text);
- $Text = str_replace("\r\n","\n", $Text);
+ $Text = str_replace("\r\n", "\n", $Text);
// removing multiplicated newlines
if (get_config("system", "remove_multiplicated_lines")) {
@@ -850,8 +862,9 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
$Text = str_replace(array("\r","\n"), array('
','
'), $Text);
- if ($preserve_nl)
- $Text = str_replace(array("\n","\r"), array('',''),$Text);
+ if ($preserve_nl) {
+ $Text = str_replace(array("\n", "\r"), array('', ''), $Text);
+ }
// Set up the parameters for a URL search string
$URLSearchString = "^\[\]";
@@ -859,20 +872,21 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
$MAILSearchString = $URLSearchString;
// Remove all hashtag addresses
- if ((!$tryoembed OR $simplehtml) AND !in_array($simplehtml, array(3, 7)))
+ if ((!$tryoembed OR $simplehtml) AND !in_array($simplehtml, array(3, 7))) {
$Text = preg_replace("/([#@])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '$1$3', $Text);
- elseif ($simplehtml == 3)
+ } elseif ($simplehtml == 3) {
$Text = preg_replace("/([@])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",
'$1$3',
$Text);
- elseif ($simplehtml == 7)
+ } elseif ($simplehtml == 7) {
$Text = preg_replace("/([@])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",
'$1$3',
$Text);
- elseif (!$simplehtml)
+ } elseif (!$simplehtml) {
$Text = preg_replace("/([@])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",
'$1$3',
$Text);
+ }
// Bookmarks in red - will be converted to bookmarks in friendica
$Text = preg_replace("/#\^\[url\]([$URLSearchString]*)\[\/url\]/ism", '[bookmark=$1]$1[/bookmark]', $Text);
@@ -881,38 +895,42 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
"[bookmark=$1]$2[/bookmark]", $Text);
if (in_array($simplehtml, array(2, 6, 7, 8, 9))) {
- $Text = preg_replace_callback("/([^#@])\[url\=([^\]]*)\](.*?)\[\/url\]/ism","bb_expand_links",$Text);
- //$Text = preg_replace("/[^#@]\[url\=([^\]]*)\](.*?)\[\/url\]/ism",' $2 [url]$1[/url]',$Text);
- $Text = preg_replace("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism",' $2 [url]$1[/url]',$Text);
+ $Text = preg_replace_callback("/([^#@])\[url\=([^\]]*)\](.*?)\[\/url\]/ism", "bb_expand_links", $Text);
+ //$Text = preg_replace("/[^#@]\[url\=([^\]]*)\](.*?)\[\/url\]/ism", ' $2 [url]$1[/url]', $Text);
+ $Text = preg_replace("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism", ' $2 [url]$1[/url]',$Text);
}
- if ($simplehtml == 5)
+ if ($simplehtml == 5) {
$Text = preg_replace("/[^#@]\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '[url]$1[/url]', $Text);
+ }
// Perform URL Search
- if ($tryoembed)
- $Text = preg_replace_callback("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism",'tryoembed',$Text);
+ if ($tryoembed) {
+ $Text = preg_replace_callback("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism", 'tryoembed', $Text);
+ }
- if ($simplehtml == 5)
- $Text = preg_replace("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism",'[url]$1[/url]',$Text);
- else
- $Text = preg_replace("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism",'[url=$1]$2[/url]',$Text);
+ if ($simplehtml == 5) {
+ $Text = preg_replace("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism", '[url]$1[/url]', $Text);
+ } else {
+ $Text = preg_replace("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism", '[url=$1]$2[/url]', $Text);
+ }
// Handle Diaspora posts
$Text = preg_replace_callback("&\[url=/posts/([^\[\]]*)\](.*)\[\/url\]&Usi", 'bb_DiasporaLinks', $Text);
// if the HTML is used to generate plain text, then don't do this search, but replace all URL of that kind to text
// if ($simplehtml != 7) {
- if (!$forplaintext)
+ if (!$forplaintext) {
$Text = preg_replace("/([^\]\='".'"'."]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1$2', $Text);
- else {
- $Text = preg_replace("(\[url\]([$URLSearchString]*)\[\/url\])ism"," $1 ",$Text);
+ } else {
+ $Text = preg_replace("(\[url\]([$URLSearchString]*)\[\/url\])ism", " $1 ", $Text);
$Text = preg_replace_callback("&\[url=([^\[\]]*)\]\[img\](.*)\[\/img\]\[\/url\]&Usi", 'bb_RemovePictureLinks', $Text);
}
// }
- if ($tryoembed)
- $Text = preg_replace_callback("/\[url\]([$URLSearchString]*)\[\/url\]/ism",'tryoembed',$Text);
+ if ($tryoembed) {
+ $Text = preg_replace_callback("/\[url\]([$URLSearchString]*)\[\/url\]/ism", 'tryoembed', $Text);
+ }
$Text = preg_replace("/([#])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism",
'$1$3', $Text);
@@ -928,7 +946,7 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
// we may need to restrict this further if it picks up too many strays
// link acct:user@host to a webfinger profile redirector
- $Text = preg_replace('/acct:([^@]+)@((?!\-)(?:[a-zA-Z\d\-]{0,62}[a-zA-Z\d]\.){1,126}(?!\d+)[a-zA-Z\d]{1,63})/', 'acct:$1@$2',$Text);
+ $Text = preg_replace('/acct:([^@]+)@((?!\-)(?:[a-zA-Z\d\-]{0,62}[a-zA-Z\d]\.){1,126}(?!\d+)[a-zA-Z\d]{1,63})/', 'acct:$1@$2', $Text);
// Perform MAIL Search
$Text = preg_replace("/\[mail\]([$MAILSearchString]*)\[\/mail\]/", '$1', $Text);
@@ -937,61 +955,61 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
// leave open the posibility of [map=something]
// this is replaced in prepare_body() which has knowledge of the item location
- if (strpos($Text,'[/map]') !== false) {
+ if (strpos($Text, '[/map]') !== false) {
$Text = preg_replace_callback("/\[map\](.*?)\[\/map\]/ism", 'bb_map_location', $Text);
}
- if (strpos($Text,'[map=') !== false) {
+ if (strpos($Text, '[map=') !== false) {
$Text = preg_replace_callback("/\[map=(.*?)\]/ism", 'bb_map_coords', $Text);
}
- if (strpos($Text,'[map]') !== false) {
+ if (strpos($Text, '[map]') !== false) {
$Text = preg_replace("/\[map\]/", '
$1
',$Text); + $Text = preg_replace("(\[p\](.*?)\[\/p\])ism", '$1
', $Text); // Check for bold text - $Text = preg_replace("(\[b\](.*?)\[\/b\])ism",'$1',$Text); + $Text = preg_replace("(\[b\](.*?)\[\/b\])ism", '$1', $Text); // Check for Italics text - $Text = preg_replace("(\[i\](.*?)\[\/i\])ism",'$1',$Text); + $Text = preg_replace("(\[i\](.*?)\[\/i\])ism", '$1', $Text); // Check for Underline text - $Text = preg_replace("(\[u\](.*?)\[\/u\])ism",'$1',$Text); + $Text = preg_replace("(\[u\](.*?)\[\/u\])ism", '$1', $Text); // Check for strike-through text - $Text = preg_replace("(\[s\](.*?)\[\/s\])ism",'$1
';
// Check for [code] text
- $Text = preg_replace("/\[code\](.*?)\[\/code\]/ism","$CodeLayout", $Text);
+ $Text = preg_replace("/\[code\](.*?)\[\/code\]/ism", "$CodeLayout", $Text);
// Declare the format for [spoiler] layout
$SpoilerLayout = '$1'; @@ -1043,8 +1061,9 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal // Check for [spoiler] text // handle nested quotes $endlessloop = 0; - while ((strpos($Text, "[/spoiler]") !== false) and (strpos($Text, "[spoiler]") !== false) and (++$endlessloop < 20)) - $Text = preg_replace("/\[spoiler\](.*?)\[\/spoiler\]/ism","$SpoilerLayout", $Text); + while ((strpos($Text, "[/spoiler]") !== false) and (strpos($Text, "[spoiler]") !== false) and (++$endlessloop < 20)) { + $Text = preg_replace("/\[spoiler\](.*?)\[\/spoiler\]/ism", "$SpoilerLayout", $Text); + } // Check for [spoiler=Author] text @@ -1052,10 +1071,11 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal // handle nested quotes $endlessloop = 0; - while ((strpos($Text, "[/spoiler]")!== false) and (strpos($Text, "[spoiler=") !== false) and (++$endlessloop < 20)) + while ((strpos($Text, "[/spoiler]")!== false) and (strpos($Text, "[spoiler=") !== false) and (++$endlessloop < 20)) { $Text = preg_replace("/\[spoiler=[\"\']*(.*?)[\"\']*\](.*?)\[\/spoiler\]/ism", "
$2", $Text); + } // Declare the format for [quote] layout $QuoteLayout = '
$1'; @@ -1063,8 +1083,9 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal // Check for [quote] text // handle nested quotes $endlessloop = 0; - while ((strpos($Text, "[/quote]") !== false) and (strpos($Text, "[quote]") !== false) and (++$endlessloop < 20)) - $Text = preg_replace("/\[quote\](.*?)\[\/quote\]/ism","$QuoteLayout", $Text); + while ((strpos($Text, "[/quote]") !== false) and (strpos($Text, "[quote]") !== false) and (++$endlessloop < 20)) { + $Text = preg_replace("/\[quote\](.*?)\[\/quote\]/ism", "$QuoteLayout", $Text); + } // Check for [quote=Author] text @@ -1072,10 +1093,11 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal // handle nested quotes $endlessloop = 0; - while ((strpos($Text, "[/quote]")!== false) and (strpos($Text, "[quote=") !== false) and (++$endlessloop < 20)) + while ((strpos($Text, "[/quote]")!== false) and (strpos($Text, "[quote=") !== false) and (++$endlessloop < 20)) { $Text = preg_replace("/\[quote=[\"\']*(.*?)[\"\']*\](.*?)\[\/quote\]/ism", "
$2", $Text); + } // [img=widthxheight]image source[/img] @@ -1095,11 +1117,11 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal $Text = preg_replace_callback("/(.*?)\[share(.*?)\](.*?)\[\/share\]/ism", function ($match) use ($simplehtml){ return(bb_ShareAttributes($match, $simplehtml)); - },$Text); + }, $Text); - $Text = preg_replace("/\[crypt\](.*?)\[\/crypt\]/ism",'
with
- $Text = preg_replace_callback("|(?!
]*>)([^<]*)
(?!
]*>)|ism", 'bb_onelinecode_cb', $Text);
+ // Replace inline code blocks
+ $Text = preg_replace_callback("|(?!
]*>)([^<]*)
(?!
]*>)|ism",
+ function ($match) use ($simplehtml) {
+ $return = '' . $match[1] . ' ';
+ // Use for Diaspora inline code blocks
+ if ($simplehtml === 3) {
+ $return = '' . $match[1] . '
';
+ }
+ return $return;
+ }
+ , $Text);
// Unhide all [noparse] contained bbtags unspacefying them
// and triming the [noparse] tag.
- $Text = preg_replace_callback("/\[noparse\](.*?)\[\/noparse\]/ism", 'bb_unspacefy_and_trim',$Text);
- $Text = preg_replace_callback("/\[nobb\](.*?)\[\/nobb\]/ism", 'bb_unspacefy_and_trim',$Text);
- $Text = preg_replace_callback("/\[pre\](.*?)\[\/pre\]/ism", 'bb_unspacefy_and_trim',$Text);
+ $Text = preg_replace_callback("/\[noparse\](.*?)\[\/noparse\]/ism", 'bb_unspacefy_and_trim', $Text);
+ $Text = preg_replace_callback("/\[nobb\](.*?)\[\/nobb\]/ism", 'bb_unspacefy_and_trim', $Text);
+ $Text = preg_replace_callback("/\[pre\](.*?)\[\/pre\]/ism", 'bb_unspacefy_and_trim', $Text);
- $Text = preg_replace('/\[\&\;([#a-z0-9]+)\;\]/','&$1;',$Text);
- $Text = preg_replace('/\&\#039\;/','\'',$Text);
- $Text = preg_replace('/\"\;/','"',$Text);
+ $Text = preg_replace('/\[\&\;([#a-z0-9]+)\;\]/', '&$1;', $Text);
+ $Text = preg_replace('/\&\#039\;/', '\'', $Text);
+ $Text = preg_replace('/\"\;/', '"', $Text);
// fix any escaped ampersands that may have been converted into links
$Text = preg_replace('/\<([^>]*?)(src|href)=(.*?)\&\;(.*?)\>/ism', '<$1$2=$3&$4>', $Text);
@@ -1234,19 +1268,19 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true, $simplehtml = fal
$Text = $doc->saveHTML();
$Text = str_replace(array("", "", $doctype, $encoding), array("", "", "", ""), $Text);
- $Text = str_replace('
','', $Text);
+ $Text = str_replace('
', '', $Text);
//$Text = mb_convert_encoding($Text, "UTF-8", 'HTML-ENTITIES');
}
// Clean up some useless linebreaks in lists
- //$Text = str_replace('
','
', $Text);
- //$Text = str_replace('
','', $Text);
- //$Text = str_replace('
',' ', $Text);
- // $Text = str_replace('
', '
', $Text);
+ //$Text = str_replace('
', '', $Text);
+ //$Text = str_replace('
', ' ', $Text);
+ //$Text = str_replace('
diff --git a/include/feed.php b/include/feed.php
index 295993370..2117676db 100644
--- a/include/feed.php
+++ b/include/feed.php
@@ -200,7 +200,6 @@ function feed_import($xml,$importer,&$contact, &$hub, $simulate = false) {
if ($item["plink"] == "") {
$item["plink"] = $xpath->evaluate('rss:link/text()', $entry)->item(0)->nodeValue;
}
- $item["plink"] = original_url($item["plink"]);
$item["uri"] = $xpath->evaluate('atom:id/text()', $entry)->item(0)->nodeValue;
@@ -210,12 +209,17 @@ function feed_import($xml,$importer,&$contact, &$hub, $simulate = false) {
if ($item["uri"] == "") {
$item["uri"] = $item["plink"];
}
+
+ $orig_plink = $item["plink"];
+
+ $item["plink"] = original_url($item["plink"]);
+
$item["parent-uri"] = $item["uri"];
if (!$simulate) {
$r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s' AND `network` IN ('%s', '%s')",
intval($importer["uid"]), dbesc($item["uri"]), dbesc(NETWORK_FEED), dbesc(NETWORK_DFRN));
- if ($r) {
+ if (dbm::is_result($r)) {
logger("Item with uri ".$item["uri"]." for user ".$importer["uid"]." already existed under id ".$r[0]["id"], LOGGER_DEBUG);
continue;
}
@@ -340,6 +344,7 @@ function feed_import($xml,$importer,&$contact, &$hub, $simulate = false) {
// Distributed items should have a well formatted URI.
// Additionally we have to avoid conflicts with identical URI between imported feeds and these items.
if ($notify) {
+ $item['guid'] = uri_to_guid($orig_plink, $a->get_hostname());
unset($item['uri']);
unset($item['parent-uri']);
}
diff --git a/include/items.php b/include/items.php
index c2b3d7d1f..f3885d21f 100644
--- a/include/items.php
+++ b/include/items.php
@@ -407,10 +407,12 @@ function item_store($arr,$force_parent = false, $notify = false, $dontcache = fa
// We have to avoid duplicates. So we create the GUID in form of a hash of the plink or uri.
// In difference to the call to "uri_to_guid" several lines below we add the hash of our own host.
// This is done because our host is the original creator of the post.
- if (isset($arr['plink'])) {
- $arr['guid'] = uri_to_guid($arr['plink'], $a->get_hostname());
- } elseif (isset($arr['uri'])) {
- $arr['guid'] = uri_to_guid($arr['uri'], $a->get_hostname());
+ if (!isset($arr['guid'])) {
+ if (isset($arr['plink'])) {
+ $arr['guid'] = uri_to_guid($arr['plink'], $a->get_hostname());
+ } elseif (isset($arr['uri'])) {
+ $arr['guid'] = uri_to_guid($arr['uri'], $a->get_hostname());
+ }
}
}
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/include/update_gcontact.php b/include/update_gcontact.php
index 221c0829f..883a22989 100644
--- a/include/update_gcontact.php
+++ b/include/update_gcontact.php
@@ -21,7 +21,7 @@ function update_gcontact_run(&$argv, &$argc) {
$r = q("SELECT * FROM `gcontact` WHERE `id` = %d", intval($contact_id));
- if (!dbm::_is_result($r)) {
+ if (!dbm::is_result($r)) {
return;
}
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/library/html-to-markdown/.gitignore b/library/html-to-markdown/.gitignore
deleted file mode 100644
index aa429a9a1..000000000
--- a/library/html-to-markdown/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-~*
-vendor
-composer.lock
\ No newline at end of file
diff --git a/library/html-to-markdown/.travis.yml b/library/html-to-markdown/.travis.yml
deleted file mode 100644
index 48b3e64a4..000000000
--- a/library/html-to-markdown/.travis.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-language: php
-php:
- - "5.5"
- - "5.4"
- - "5.3"
-script: phpunit --no-configuration HTML_To_MarkdownTest ./tests/HTML_To_MarkdownTest.php
\ No newline at end of file
diff --git a/library/html-to-markdown/HTML_To_Markdown.php b/library/html-to-markdown/HTML_To_Markdown.php
deleted file mode 100644
index 109780edd..000000000
--- a/library/html-to-markdown/HTML_To_Markdown.php
+++ /dev/null
@@ -1,598 +0,0 @@
-
- * @link https://github.com/nickcernis/html2markdown/ Latest version on GitHub.
- * @link http://twitter.com/nickcernis Nick on twitter.
- * @license http://www.opensource.org/licenses/mit-license.php MIT
- */
-class HTML_To_Markdown
-{
- /**
- * @var DOMDocument The root of the document tree that holds our HTML.
- */
- private $document;
-
- /**
- * @var string|boolean The Markdown version of the original HTML, or false if conversion failed
- */
- private $output;
-
- /**
- * @var array Class-wide options users can override.
- */
- private $options = array(
- 'header_style' => 'setext', // Set to "atx" to output H1 and H2 headers as # Header1 and ## Header2
- 'suppress_errors' => true, // Set to false to show warnings when loading malformed HTML
- 'strip_tags' => false, // Set to true to strip tags that don't have markdown equivalents. N.B. Strips tags, not their content. Useful to clean MS Word HTML output.
- 'bold_style' => '**', // Set to '__' if you prefer the underlined style
- 'italic_style' => '*', // Set to '_' if you prefer the underlined style
- 'remove_nodes' => '', // space-separated list of dom nodes that should be removed. example: "meta style script"
- );
-
-
- /**
- * Constructor
- *
- * Set up a new DOMDocument from the supplied HTML, convert it to Markdown, and store it in $this->$output.
- *
- * @param string $html The HTML to convert to Markdown.
- * @param array $overrides [optional] List of style and error display overrides.
- */
- public function __construct($html = null, $overrides = null)
- {
- if ($overrides)
- $this->options = array_merge($this->options, $overrides);
-
- if ($html)
- $this->convert($html);
- }
-
-
- /**
- * Setter for conversion options
- *
- * @param $name
- * @param $value
- */
- public function set_option($name, $value)
- {
- $this->options[$name] = $value;
- }
-
-
- /**
- * Convert
- *
- * Loads HTML and passes to get_markdown()
- *
- * @param $html
- * @return string The Markdown version of the html
- */
- public function convert($html)
- {
- $html = preg_replace('~>\s+<~', '><', $html); // Strip white space between tags to prevent creation of empty #text nodes
-
- $this->document = new DOMDocument();
-
- if ($this->options['suppress_errors'])
- libxml_use_internal_errors(true); // Suppress conversion errors (from http://bit.ly/pCCRSX )
-
- $this->document->loadHTML('' . $html); // Hack to load utf-8 HTML (from http://bit.ly/pVDyCt )
- $this->document->encoding = 'UTF-8';
-
- if ($this->options['suppress_errors'])
- libxml_clear_errors();
-
- return $this->get_markdown($html);
- }
-
-
- /**
- * Is Child Of?
- *
- * Is the node a child of the given parent tag?
- *
- * @param $parent_name string|array The name of the parent node(s) to search for e.g. 'code' or array('pre', 'code')
- * @param $node
- * @return bool
- */
- private static function is_child_of($parent_name, $node)
- {
- for ($p = $node->parentNode; $p != false; $p = $p->parentNode) {
- if (is_null($p))
- return false;
-
- if ( is_array($parent_name) && in_array($p->nodeName, $parent_name) )
- return true;
-
- if ($p->nodeName == $parent_name)
- return true;
- }
- return false;
- }
-
-
- /**
- * Convert Children
- *
- * Recursive function to drill into the DOM and convert each node into Markdown from the inside out.
- *
- * Finds children of each node and convert those to #text nodes containing their Markdown equivalent,
- * starting with the innermost element and working up to the outermost element.
- *
- * @param $node
- */
- private function convert_children($node)
- {
- // Don't convert HTML code inside and blocks to Markdown - that should stay as HTML
- if (self::is_child_of(array('pre', 'code'), $node))
- return;
-
- // If the node has children, convert those to Markdown first
- if ($node->hasChildNodes()) {
- $length = $node->childNodes->length;
-
- for ($i = 0; $i < $length; $i++) {
- $child = $node->childNodes->item($i);
- $this->convert_children($child);
- }
- }
-
- // Now that child nodes have been converted, convert the original node
- $markdown = $this->convert_to_markdown($node);
-
- // Create a DOM text node containing the Markdown equivalent of the original node
- $markdown_node = $this->document->createTextNode($markdown);
-
- // Replace the old $node e.g. "Title
" with the new $markdown_node e.g. "### Title"
- $node->parentNode->replaceChild($markdown_node, $node);
- }
-
-
- /**
- * Get Markdown
- *
- * Sends the body node to convert_children() to change inner nodes to Markdown #text nodes, then saves and
- * returns the resulting converted document as a string in Markdown format.
- *
- * @return string|boolean The converted HTML as Markdown, or false if conversion failed
- */
- private function get_markdown()
- {
- // Work on the entire DOM tree (including head and body)
- $input = $this->document->getElementsByTagName("html")->item(0);
-
- if (!$input)
- return false;
-
- // Convert all children of this root element. The DOMDocument stored in $this->doc will
- // then consist of #text nodes, each containing a Markdown version of the original node
- // that it replaced.
- $this->convert_children($input);
-
- // Sanitize and return the body contents as a string.
- $markdown = $this->document->saveHTML(); // stores the DOMDocument as a string
- $markdown = html_entity_decode($markdown, ENT_QUOTES, 'UTF-8');
- $markdown = html_entity_decode($markdown, ENT_QUOTES, 'UTF-8'); // Double decode to cover cases like http://www.php.net/manual/en/function.htmlentities.php#99984
- $markdown = preg_replace("/]+>/", "", $markdown); // Strip doctype declaration
- $unwanted = array('', '', '', '', '', '', '', '
');
- $markdown = str_replace($unwanted, '', $markdown); // Strip unwanted tags
- $markdown = trim($markdown, "\n\r\0\x0B");
-
- $this->output = $markdown;
-
- return $markdown;
- }
-
-
- /**
- * Convert to Markdown
- *
- * Converts an individual node into a #text node containing a string of its Markdown equivalent.
- *
- * Example: An node with text content of "Title" becomes a text node with content of "### Title"
- *
- * @param $node
- * @return string The converted HTML as Markdown
- */
- private function convert_to_markdown($node)
- {
- $tag = $node->nodeName; // the type of element, e.g. h1
- $value = $node->nodeValue; // the value of that element, e.g. The Title
-
- // Strip nodes named in remove_nodes
- $tags_to_remove = explode(' ', $this->options['remove_nodes']);
- if ( in_array($tag, $tags_to_remove) )
- return false;
-
- switch ($tag) {
- case "p":
- $markdown = (trim($value)) ? rtrim($value) . PHP_EOL . PHP_EOL : '';
- break;
- case "pre":
- $markdown = PHP_EOL . $this->convert_code($node) . PHP_EOL;
- break;
- case "h1":
- case "h2":
- $markdown = $this->convert_header($tag, $node);
- break;
- case "h3":
- $markdown = "### " . $value . PHP_EOL . PHP_EOL;
- break;
- case "h4":
- $markdown = "#### " . $value . PHP_EOL . PHP_EOL;
- break;
- case "h5":
- $markdown = "##### " . $value . PHP_EOL . PHP_EOL;
- break;
- case "h6":
- $markdown = "###### " . $value . PHP_EOL . PHP_EOL;
- break;
- case "em":
- case "i":
- case "strong":
- case "b":
- $markdown = $this->convert_emphasis($tag, $value);
- break;
- case "hr":
- $markdown = "- - - - - -" . PHP_EOL . PHP_EOL;
- break;
- case "br":
- $markdown = " " . PHP_EOL;
- break;
- case "blockquote":
- $markdown = $this->convert_blockquote($node);
- break;
- case "code":
- $markdown = $this->convert_code($node);
- break;
- case "ol":
- case "ul":
- $markdown = $value . PHP_EOL;
- break;
- case "li":
- $markdown = $this->convert_list($node);
- break;
- case "img":
- $markdown = $this->convert_image($node);
- break;
- case "a":
- $markdown = $this->convert_anchor($node);
- break;
- case "#text":
- $markdown = preg_replace('~\s+~', ' ', $value);
- $markdown = preg_replace('~^#~', '\\\\#', $markdown);
- break;
- case "#comment":
- $markdown = '';
- break;
- case "div":
- $markdown = ($this->options['strip_tags']) ? $value . PHP_EOL . PHP_EOL : html_entity_decode($node->C14N());
- break;
- default:
- // If strip_tags is false (the default), preserve tags that don't have Markdown equivalents,
- // such as nodes on their own. C14N() canonicalizes the node to a string.
- // See: http://www.php.net/manual/en/domnode.c14n.php
- $markdown = ($this->options['strip_tags']) ? $value : html_entity_decode($node->C14N());
- }
-
- return $markdown;
- }
-
-
- /**
- * Convert Header
- *
- * Converts h1 and h2 headers to Markdown-style headers in setext style,
- * matching the number of underscores with the length of the title.
- *
- * e.g. Header 1 Header Two
- * ======== ----------
- *
- * Returns atx headers instead if $this->options['header_style'] is "atx"
- *
- * e.g. # Header 1 ## Header Two
- *
- * @param string $level The header level, including the "h". e.g. h1
- * @param string $node The node to convert.
- * @return string The Markdown version of the header.
- */
- private function convert_header($level, $node)
- {
- $content = $node->nodeValue;
-
- if (!$this->is_child_of('blockquote', $node) && $this->options['header_style'] == "setext") {
- $length = (function_exists('mb_strlen')) ? mb_strlen($content, 'utf-8') : strlen($content);
- $underline = ($level == "h1") ? "=" : "-";
- $markdown = $content . PHP_EOL . str_repeat($underline, $length) . PHP_EOL . PHP_EOL; // setext style
- } else {
- $prefix = ($level == "h1") ? "# " : "## ";
- $markdown = $prefix . $content . PHP_EOL . PHP_EOL; // atx style
- }
-
- return $markdown;
- }
-
-
- /**
- * Converts inline styles
- * This function is used to render strong and em tags
- *
- * eg bold text becomes **bold text** or __bold text__
- *
- * @param string $tag
- * @param string $value
- * @return string
- */
- private function convert_emphasis($tag, $value)
- {
- if ($tag == 'i' || $tag == 'em') {
- $markdown = $this->options['italic_style'] . $value . $this->options['italic_style'];
- } else {
- $markdown = $this->options['bold_style'] . $value . $this->options['bold_style'];
- }
-
- return $markdown;
- }
-
-
- /**
- * Convert Image
- *
- * Converts tags to Markdown.
- *
- * e.g.
- * becomes ![alt text](/path/img.jpg "Title")
- *
- * @param $node
- * @return string
- */
- private function convert_image($node)
- {
- $src = $node->getAttribute('src');
- $alt = $node->getAttribute('alt');
- $title = $node->getAttribute('title');
-
- if ($title != "") {
- $markdown = '![' . $alt . '](' . $src . ' "' . $title . '")'; // No newlines added. should be in a block-level element.
- } else {
- $markdown = '![' . $alt . '](' . $src . ')';
- }
-
- return $markdown;
- }
-
-
- /**
- * Convert Anchor
- *
- * Converts tags to Markdown.
- *
- * e.g. Modern Nerd
- * becomes [Modern Nerd](http://modernnerd.net "Title")
- *
- * @param $node
- * @return string
- */
- private function convert_anchor($node)
- {
- $href = $node->getAttribute('href');
- $title = $node->getAttribute('title');
- $text = $node->nodeValue;
-
- if ($title != "") {
- $markdown = '[' . $text . '](' . $href . ' "' . $title . '")';
- } else {
- $markdown = '[' . $text . '](' . $href . ')';
- }
-
- if (! $href)
- $markdown = html_entity_decode($node->C14N());
-
- // Append a space if the node after this one is also an anchor
- $next_node_name = $this->get_next_node_name($node);
-
- if ($next_node_name == 'a')
- $markdown = $markdown . ' ';
-
- return $markdown;
- }
-
-
- /**
- * Convert List
- *
- * Converts and lists to Markdown.
- *
- * @param $node
- * @return string
- */
- private function convert_list($node)
- {
- // If parent is an ol, use numbers, otherwise, use dashes
- $list_type = $node->parentNode->nodeName;
- $value = $node->nodeValue;
-
- if ($list_type == "ul") {
- $markdown = "- " . trim($value) . PHP_EOL;
- } else {
- $number = $this->get_position($node);
- $markdown = $number . ". " . trim($value) . PHP_EOL;
- }
-
- return $markdown;
- }
-
-
- /**
- * Convert Code
- *
- * Convert code tags by indenting blocks of code and wrapping single lines in backticks.
- *
- * @param DOMNode $node
- * @return string
- */
- private function convert_code($node)
- {
- // Store the content of the code block in an array, one entry for each line
-
- $markdown = '';
-
- $code_content = html_entity_decode($node->C14N());
- $code_content = str_replace(array("", "
"), "", $code_content);
- $code_content = str_replace(array("", "
"), "", $code_content);
-
- $lines = preg_split('/\r\n|\r|\n/', $code_content);
- $total = count($lines);
-
- // If there's more than one line of code, prepend each line with four spaces and no backticks.
- if ($total > 1 || $node->nodeName === 'pre') {
-
- // Remove the first and last line if they're empty
- $first_line = trim($lines[0]);
- $last_line = trim($lines[$total - 1]);
- $first_line = trim($first_line, "
"); //trim XML style carriage returns too
- $last_line = trim($last_line, "
");
-
- if (empty($first_line))
- array_shift($lines);
-
- if (empty($last_line))
- array_pop($lines);
-
- $count = 1;
- foreach ($lines as $line) {
- $line = str_replace('
', '', $line);
- $markdown .= " " . $line;
- // Add newlines, except final line of the code
- if ($count != $total)
- $markdown .= PHP_EOL;
- $count++;
- }
- $markdown .= PHP_EOL;
-
- } else { // There's only one line of code. It's a code span, not a block. Just wrap it with backticks.
-
- $markdown .= "`" . $lines[0] . "`";
-
- }
-
- return $markdown;
- }
-
-
- /**
- * Convert blockquote
- *
- * Prepend blockquotes with > chars.
- *
- * @param $node
- * @return string
- */
- private function convert_blockquote($node)
- {
- // Contents should have already been converted to Markdown by this point,
- // so we just need to add ">" symbols to each line.
-
- $markdown = '';
-
- $quote_content = trim($node->nodeValue);
-
- $lines = preg_split('/\r\n|\r|\n/', $quote_content);
-
- $total_lines = count($lines);
-
- foreach ($lines as $i => $line) {
- $markdown .= "> " . $line . PHP_EOL;
- if ($i + 1 == $total_lines)
- $markdown .= PHP_EOL;
- }
-
- return $markdown;
- }
-
-
- /**
- * Get Position
- *
- * Returns the numbered position of a node inside its parent
- *
- * @param $node
- * @return int The numbered position of the node, starting at 1.
- */
- private function get_position($node)
- {
- // Get all of the nodes inside the parent
- $list_nodes = $node->parentNode->childNodes;
- $total_nodes = $list_nodes->length;
-
- $position = 1;
-
- // Loop through all nodes and find the given $node
- for ($a = 0; $a < $total_nodes; $a++) {
- $current_node = $list_nodes->item($a);
-
- if ($current_node->isSameNode($node))
- $position = $a + 1;
- }
-
- return $position;
- }
-
-
- /**
- * Get Next Node Name
- *
- * Return the name of the node immediately after the passed one.
- *
- * @param $node
- * @return string|null The node name (e.g. 'h1') or null.
- */
- private function get_next_node_name($node)
- {
- $next_node_name = null;
-
- $current_position = $this->get_position($node);
- $next_node = $node->parentNode->childNodes->item($current_position);
-
- if ($next_node)
- $next_node_name = $next_node->nodeName;
-
- return $next_node_name;
- }
-
-
- /**
- * To String
- *
- * Magic method to return Markdown output when HTML_To_Markdown instance is treated as a string.
- *
- * @return string
- */
- public function __toString()
- {
- return $this->output();
- }
-
-
- /**
- * Output
- *
- * Getter for the converted Markdown contents stored in $this->output
- *
- * @return string
- */
- public function output()
- {
- if (!$this->output) {
- return '';
- } else {
- return $this->output;
- }
- }
-}
diff --git a/library/html-to-markdown/README.md b/library/html-to-markdown/README.md
deleted file mode 100644
index de91c9d08..000000000
--- a/library/html-to-markdown/README.md
+++ /dev/null
@@ -1,138 +0,0 @@
-HTML To Markdown for PHP
-========================
-
-A helper class that converts HTML to [Markdown](http://daringfireball.net/projects/markdown/) for your sanity and convenience.
-
-[![Build Status](https://travis-ci.org/nickcernis/html-to-markdown.png?branch=master)](https://travis-ci.org/nickcernis/html-to-markdown)
-
-**Version**: 2.2.1
-**Requires**: PHP 5.3+
-**Author**: [@nickcernis](http://twitter.com/nickcernis)
-**License**: [MIT](http://www.opensource.org/licenses/mit-license.php)
-
-### Why convert HTML to Markdown?
-
-*"What alchemy is this?"* you mutter. *"I can see why you'd convert [Markdown to HTML](http://michelf.com/projects/php-markdown/),"* you continue, already labouring the question somewhat, *"but why go the other way?"*
-
-Typically you would convert HTML to Markdown if:
-
-1. You have an existing HTML document that needs to be edited by people with good taste.
-2. You want to store new content in HTML format but edit it as Markdown.
-3. You want to convert HTML email to plain text email.
-4. You know a guy who's been converting HTML to Markdown for years, and now he can speak Elvish. You'd quite like to be able to speak Elvish.
-5. You just really like Markdown.
-
-### How to use it
-
-Either include HTML_To_Markdown.php directly:
-
- require_once( dirname( __FILE__) . '/HTML_To_Markdown.php' );
-
-Or, require the library in your composer.json:
-
- {
- "require": {
- "nickcernis/html-to-markdown": "dev-master"
- }
- }
-
-Then `composer install` and add `require 'vendor/autoload.php';` to the top of your script.
-
-Next, create a new HTML_To_Markdown instance, passing in your valid HTML code:
-
- $html = "Quick, to the Batpoles!
";
- $markdown = new HTML_To_Markdown($html);
-
-The `$markdown` object now contains the Markdown version of your HTML. Use it like a string:
-
- echo $markdown; // ==> ### Quick, to the Batpoles!
-
-Or access the Markdown output directly:
-
- $string = $markdown->output();
-
-The included `demo` directory contains an HTML->Markdown conversion form to try out.
-
-### Conversion options
-
-By default, HTML To Markdown preserves HTML tags without Markdown equivalents, like `` and ``.
-
-To strip HTML tags that don't have a Markdown equivalent while preserving the content inside them, set `strip_tags` to true, like this:
-
- $html = 'Turnips!';
- $markdown = new HTML_To_Markdown($html, array('strip_tags' => true)); // $markdown now contains "Turnips!"
-
-Or more explicitly, like this:
-
- $html = 'Turnips!';
- $markdown = new HTML_To_Markdown();
- $markdown->set_option('strip_tags', true);
- $markdown->convert($html); // $markdown now contains "Turnips!"
-
-Note that only the tags themselves are stripped, not the content they hold.
-
-To strip tags and their content, pass a space-separated list of tags in `remove_nodes`, like this:
-
- $html = 'Turnips!Monkeys!';
- $markdown = new HTML_To_Markdown($html, array('remove_nodes' => 'span div')); // $markdown now contains ""
-
-### Style options
-
-Bold and italic tags are converted using the asterisk syntax by default. Change this to the underlined syntax using the `bold_style` and `italic_style` options.
-
- $html = 'Italic and a bold';
- $markdown = new HTML_To_Markdown();
- $markdown->set_option('italic_style', '_');
- $markdown->set_option('bold_style', '__');
- $markdown->convert($html); // $markdown now contains "_Italic_ and a __bold__"
-
-### Limitations
-
-- Markdown Extra, MultiMarkdown and other variants aren't supported – just Markdown.
-
-### Known issues
-
-- Nested lists and lists containing multiple paragraphs aren't converted correctly.
-- Lists inside blockquotes aren't converted correctly.
-- Any reported [open issues here](https://github.com/nickcernis/html-to-markdown/issues?state=open).
-
-[Report your issue or request a feature here.](https://github.com/nickcernis/html2markdown/issues/new) Issues with patches or failing tests are especially welcome.
-
-### Style notes
-
-- Setext (underlined) headers are the default for H1 and H2. If you prefer the ATX style for H1 and H2 (# Header 1 and ## Header 2), set `header_style` to 'atx' in the options array when you instantiate the object:
-
- `$markdown = new HTML_To_Markdown( $html, array('header_style'=>'atx') );`
-
- Headers of H3 priority and lower always use atx style.
-
-- Links and images are referenced inline. Footnote references (where image src and anchor href attributes are listed in the footnotes) are not used.
-- Blockquotes aren't line wrapped – it makes the converted Markdown easier to edit.
-
-### Dependencies
-
-HTML To Markdown requires PHP's [xml](http://www.php.net/manual/en/xml.installation.php), [lib-xml](http://www.php.net/manual/en/libxml.installation.php), and [dom](http://www.php.net/manual/en/dom.installation.php) extensions, all of which are enabled by default on most distributions.
-
-Errors such as "Fatal error: Class 'DOMDocument' not found" on distributions such as CentOS that disable PHP's xml extension can be resolved by installing php-xml.
-
-### Architecture notes
-
-HTML To Markdown is a single file that uses native DOM manipulation libraries (DOMDocument), not regex voodoo, to convert code.
-
-### Contributors
-
-Many thanks to all [contributors](https://github.com/nickcernis/html2markdown/graphs/contributors) so far. Further improvements and feature suggestions are very welcome.
-
-### How it works
-
-HTML To Markdown creates a DOMDocument from the supplied HTML, walks through the tree, and converts each node to a text node containing the equivalent markdown, starting from the most deeply nested node and working inwards towards the root node.
-
-### To-do
-
-- Support for nested lists and lists inside blockquotes.
-- Offer an option to preserve tags as HTML if they contain attributes that can't be represented with Markdown (e.g. `style`).
-
-### Trying to convert Markdown to HTML?
-
-Use [PHP Markdown](http://michelf.com/projects/php-markdown/) from Michel Fortin. No guarantees about the Elvish, though.
-
diff --git a/library/html-to-markdown/circle.yml b/library/html-to-markdown/circle.yml
deleted file mode 100644
index 9893a4b92..000000000
--- a/library/html-to-markdown/circle.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-test:
- override:
- - phpunit --no-configuration HTML_To_MarkdownTest ./tests/HTML_To_MarkdownTest.php
-
diff --git a/library/html-to-markdown/composer.json b/library/html-to-markdown/composer.json
deleted file mode 100644
index beb7faab4..000000000
--- a/library/html-to-markdown/composer.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "name": "nickcernis/html-to-markdown",
- "type": "library",
- "description": "An HTML-to-markdown conversion helper for PHP",
- "keywords": ["markdown", "html"],
- "homepage": "https://github.com/nickcernis/html-to-markdown",
- "license": "MIT",
- "authors": [
- {
- "name": "Nick Cernis",
- "email": "nick@cern.is",
- "homepage": "http://modernnerd.net"
- }
- ],
- "autoload": {
- "classmap": [ "HTML_To_Markdown.php" ]
- },
- "require": {
- "php": ">=5.3"
- },
- "require-dev": {
- "php": ">=5.3.3",
- "phpunit/phpunit": "4.*"
- }
-}
diff --git a/mod/wall_upload.php b/mod/wall_upload.php
index 1f71f36b6..d29efecc6 100644
--- a/mod/wall_upload.php
+++ b/mod/wall_upload.php
@@ -1,17 +1,33 @@
argc > 1) {
- if(! x($_FILES,'media')) {
+ if ($a->argc > 1) {
+ if (! x($_FILES, 'media')) {
$nick = $a->argv[1];
- $r = q("SELECT `user`.*, `contact`.`id` FROM `user` INNER JOIN `contact` on `user`.`uid` = `contact`.`uid` WHERE `user`.`nickname` = '%s' AND `user`.`blocked` = 0 and `contact`.`self` = 1 LIMIT 1",
+ $r = q("SELECT `user`.*, `contact`.`id` FROM `user`
+ INNER JOIN `contact` on `user`.`uid` = `contact`.`uid`
+ WHERE `user`.`nickname` = '%s' AND `user`.`blocked` = 0
+ AND `contact`.`self` = 1 LIMIT 1",
dbesc($nick)
);
@@ -24,7 +40,10 @@ function wall_upload_post(App $a, $desktopmode = true) {
}
} else {
$user_info = api_get_user($a);
- $r = q("SELECT `user`.*, `contact`.`id` FROM `user` INNER JOIN `contact` on `user`.`uid` = `contact`.`uid` WHERE `user`.`nickname` = '%s' AND `user`.`blocked` = 0 and `contact`.`self` = 1 LIMIT 1",
+ $r = q("SELECT `user`.*, `contact`.`id` FROM `user`
+ INNER JOIN `contact` on `user`.`uid` = `contact`.`uid`
+ WHERE `user`.`nickname` = '%s' AND `user`.`blocked` = 0
+ AND `contact`.`self` = 1 LIMIT 1",
dbesc($user_info['screen_name'])
);
}
@@ -36,6 +55,9 @@ function wall_upload_post(App $a, $desktopmode = true) {
return;
}
+ /*
+ * Setup permissions structures
+ */
$can_post = false;
$visitor = 0;
@@ -44,22 +66,24 @@ function wall_upload_post(App $a, $desktopmode = true) {
$page_owner_nick = $r[0]['nickname'];
$community_page = (($r[0]['page-flags'] == PAGE_COMMUNITY) ? true : false);
- if((local_user()) && (local_user() == $page_owner_uid))
+ if ((local_user()) && (local_user() == $page_owner_uid)) {
$can_post = true;
- else {
- if($community_page && remote_user()) {
+ } else {
+ if ($community_page && remote_user()) {
$contact_id = 0;
- if(is_array($_SESSION['remote'])) {
- foreach($_SESSION['remote'] as $v) {
- if($v['uid'] == $page_owner_uid) {
+ if (is_array($_SESSION['remote'])) {
+ foreach ($_SESSION['remote'] as $v) {
+ if ($v['uid'] == $page_owner_uid) {
$contact_id = $v['cid'];
break;
}
}
}
- if($contact_id) {
- $r = q("SELECT `uid` FROM `contact` WHERE `blocked` = 0 AND `pending` = 0 AND `id` = %d AND `uid` = %d LIMIT 1",
+ if ($contact_id) {
+ $r = q("SELECT `uid` FROM `contact`
+ WHERE `blocked` = 0 AND `pending` = 0
+ AND `id` = %d AND `uid` = %d LIMIT 1",
intval($contact_id),
intval($page_owner_uid)
);
@@ -72,16 +96,16 @@ function wall_upload_post(App $a, $desktopmode = true) {
}
- if(! $can_post) {
+ if (! $can_post) {
if ($r_json) {
echo json_encode(array('error'=>t('Permission denied.')));
killme();
}
- notice( t('Permission denied.') . EOL );
+ notice(t('Permission denied.') . EOL);
killme();
}
- if(! x($_FILES,'userfile') && ! x($_FILES,'media')){
+ if (! x($_FILES, 'userfile') && ! x($_FILES, 'media')) {
if ($r_json) {
echo json_encode(array('error'=>t('Invalid request.')));
}
@@ -89,32 +113,36 @@ function wall_upload_post(App $a, $desktopmode = true) {
}
$src = "";
- if(x($_FILES,'userfile')) {
+ if (x($_FILES, 'userfile')) {
$src = $_FILES['userfile']['tmp_name'];
$filename = basename($_FILES['userfile']['name']);
$filesize = intval($_FILES['userfile']['size']);
$filetype = $_FILES['userfile']['type'];
- }
- elseif(x($_FILES,'media')) {
- if (is_array($_FILES['media']['tmp_name']))
+
+ } elseif (x($_FILES, 'media')) {
+ if (is_array($_FILES['media']['tmp_name'])) {
$src = $_FILES['media']['tmp_name'][0];
- else
+ } else {
$src = $_FILES['media']['tmp_name'];
+ }
- if (is_array($_FILES['media']['name']))
+ if (is_array($_FILES['media']['name'])) {
$filename = basename($_FILES['media']['name'][0]);
- else
+ } else {
$filename = basename($_FILES['media']['name']);
+ }
- if (is_array($_FILES['media']['size']))
+ if (is_array($_FILES['media']['size'])) {
$filesize = intval($_FILES['media']['size'][0]);
- else
+ } else {
$filesize = intval($_FILES['media']['size']);
+ }
- if (is_array($_FILES['media']['type']))
+ if (is_array($_FILES['media']['type'])) {
$filetype = $_FILES['media']['type'][0];
- else
+ } else {
$filetype = $_FILES['media']['type'];
+ }
}
if ($src=="") {
@@ -127,28 +155,30 @@ function wall_upload_post(App $a, $desktopmode = true) {
}
// This is a special treatment for picture upload from Twidere
- if (($filename == "octet-stream") AND ($filetype != "")) {
+ if (($filename == "octet-stream") && ($filetype != "")) {
$filename = $filetype;
$filetype = "";
}
- if ($filetype=="")
+ if ($filetype=="") {
$filetype=guess_image_type($filename);
+ }
// If there is a temp name, then do a manual check
// This is more reliable than the provided value
$imagedata = getimagesize($src);
- if ($imagedata)
+ if ($imagedata) {
$filetype = $imagedata['mime'];
+ }
- logger("File upload src: ".$src." - filename: ".$filename.
- " - size: ".$filesize." - type: ".$filetype, LOGGER_DEBUG);
+ logger("File upload src: " . $src . " - filename: " . $filename .
+ " - size: " . $filesize . " - type: " . $filetype, LOGGER_DEBUG);
- $maximagesize = get_config('system','maximagesize');
+ $maximagesize = Config::get('system', 'maximagesize');
- if(($maximagesize) && ($filesize > $maximagesize)) {
- $msg = sprintf( t('Image exceeds size limit of %s'), formatBytes($maximagesize));
+ if (($maximagesize) && ($filesize > $maximagesize)) {
+ $msg = sprintf(t('Image exceeds size limit of %s'), formatBytes($maximagesize));
if ($r_json) {
echo json_encode(array('error'=>$msg));
} else {
@@ -159,10 +189,12 @@ function wall_upload_post(App $a, $desktopmode = true) {
}
- $limit = service_class_fetch($page_owner_uid,'photo_upload_limit');
+ $limit = service_class_fetch($page_owner_uid, 'photo_upload_limit');
if ($limit) {
- $r = q("select sum(octet_length(data)) as total from photo where uid = %d and scale = 0 and album != 'Contact Photos' ",
+ $r = q("SELECT SUM(OCTET_LENGTH(`data`)) AS `total` FROM `photo`
+ WHERE `uid` = %d AND `scale` = 0
+ AND `album` != 'Contact Photos' ",
intval($page_owner_uid)
);
$size = $r[0]['total'];
@@ -182,7 +214,7 @@ function wall_upload_post(App $a, $desktopmode = true) {
$imagedata = @file_get_contents($src);
$ph = new Photo($imagedata, $filetype);
- if(! $ph->is_valid()) {
+ if (! $ph->is_valid()) {
$msg = t('Unable to process image.');
if ($r_json) {
echo json_encode(array('error'=>$msg));
@@ -196,12 +228,13 @@ function wall_upload_post(App $a, $desktopmode = true) {
$ph->orient($src);
@unlink($src);
- $max_length = get_config('system','max_image_length');
- if(! $max_length)
+ $max_length = Config::get('system', 'max_image_length');
+ if (! $max_length) {
$max_length = MAX_IMAGE_LENGTH;
- if($max_length > 0) {
+ }
+ if ($max_length > 0) {
$ph->scaleImage($max_length);
- logger("File upload: Scaling picture to new size ".$max_length, LOGGER_DEBUG);
+ logger("File upload: Scaling picture to new size " . $max_length, LOGGER_DEBUG);
}
$width = $ph->getWidth();
@@ -211,11 +244,16 @@ function wall_upload_post(App $a, $desktopmode = true) {
$smallest = 0;
+ // If we don't have an album name use the Wall Photos album
+ if (! strlen($album)) {
+ $album = t('Wall Photos');
+ }
+
$defperm = '<' . $default_cid . '>';
- $r = $ph->store($page_owner_uid, $visitor, $hash, $filename, t('Wall Photos'), 0, 0, $defperm);
+ $r = $ph->store($page_owner_uid, $visitor, $hash, $filename, $album, 0, 0, $defperm);
- if(! $r) {
+ if (! $r) {
$msg = t('Image upload failed.');
if ($r_json) {
echo json_encode(array('error'=>$msg));
@@ -225,26 +263,31 @@ function wall_upload_post(App $a, $desktopmode = true) {
killme();
}
- if($width > 640 || $height > 640) {
+ if ($width > 640 || $height > 640) {
$ph->scaleImage(640);
- $r = $ph->store($page_owner_uid, $visitor, $hash, $filename, t('Wall Photos'), 1, 0, $defperm);
- if($r)
+ $r = $ph->store($page_owner_uid, $visitor, $hash, $filename, $album, 1, 0, $defperm);
+ if ($r) {
$smallest = 1;
+ }
}
- if($width > 320 || $height > 320) {
+ if ($width > 320 || $height > 320) {
$ph->scaleImage(320);
- $r = $ph->store($page_owner_uid, $visitor, $hash, $filename, t('Wall Photos'), 2, 0, $defperm);
- if($r AND ($smallest == 0))
+ $r = $ph->store($page_owner_uid, $visitor, $hash, $filename, $album, 2, 0, $defperm);
+ if ($r && ($smallest == 0)) {
$smallest = 2;
+ }
}
$basename = basename($filename);
if (!$desktopmode) {
-
- $r = q("SELECT `id`, `datasize`, `width`, `height`, `type` FROM `photo` WHERE `resource-id` = '%s' ORDER BY `width` DESC LIMIT 1", $hash);
- if (!$r){
+ $r = q("SELECT `id`, `datasize`, `width`, `height`, `type` FROM `photo`
+ WHERE `resource-id` = '%s'
+ ORDER BY `width` DESC LIMIT 1",
+ $hash
+ );
+ if (!$r) {
if ($r_json) {
echo json_encode(array('error'=>''));
killme();
@@ -253,14 +296,14 @@ function wall_upload_post(App $a, $desktopmode = true) {
}
$picture = array();
- $picture["id"] = $r[0]["id"];
- $picture["size"] = $r[0]["datasize"];
- $picture["width"] = $r[0]["width"];
- $picture["height"] = $r[0]["height"];
- $picture["type"] = $r[0]["type"];
- $picture["albumpage"] = App::get_baseurl().'/photos/'.$page_owner_nick.'/image/'.$hash;
- $picture["picture"] = App::get_baseurl()."/photo/{$hash}-0.".$ph->getExt();
- $picture["preview"] = App::get_baseurl()."/photo/{$hash}-{$smallest}.".$ph->getExt();
+ $picture["id"] = $r[0]["id"];
+ $picture["size"] = $r[0]["datasize"];
+ $picture["width"] = $r[0]["width"];
+ $picture["height"] = $r[0]["height"];
+ $picture["type"] = $r[0]["type"];
+ $picture["albumpage"] = App::get_baseurl() . '/photos/' . $page_owner_nick . '/image/' . $hash;
+ $picture["picture"] = App::get_baseurl() . "/photo/{$hash}-0." . $ph->getExt();
+ $picture["preview"] = App::get_baseurl() . "/photo/{$hash}-{$smallest}." . $ph->getExt();
if ($r_json) {
echo json_encode(array('picture'=>$picture));
@@ -276,7 +319,6 @@ function wall_upload_post(App $a, $desktopmode = true) {
}
/* mod Waitman Gobble NO WARRANTY */
-
// if we get the signal then return the image url info in BBCODE
if ($_REQUEST['hush']!='yeah') {
echo "\n\n" . '[url=' . App::get_baseurl() . '/photos/' . $page_owner_nick . '/image/' . $hash . '][img]' . App::get_baseurl() . "/photo/{$hash}-{$smallest}.".$ph->getExt()."[/img][/url]\n\n";
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/html-to-markdown b/vendor/bin/html-to-markdown
new file mode 100644
index 000000000..168731f99
--- /dev/null
+++ b/vendor/bin/html-to-markdown
@@ -0,0 +1,17 @@
+#!/usr/bin/env sh
+
+dir=$(d=${0%[/\\]*}; cd "$d"; cd "../league/html-to-markdown/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}/html-to-markdown" "$@"
diff --git a/vendor/bin/html-to-markdown.bat b/vendor/bin/html-to-markdown.bat
new file mode 100644
index 000000000..273f24a5d
--- /dev/null
+++ b/vendor/bin/html-to-markdown.bat
@@ -0,0 +1,4 @@
+@ECHO OFF
+setlocal DISABLEDELAYEDEXPANSION
+SET BIN_TARGET=%~dp0/../league/html-to-markdown/bin/html-to-markdown
+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..4553da2e2 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',
@@ -239,5 +241,136 @@ return array(
'HTMLPurifier_VarParser_Flexible' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Flexible.php',
'HTMLPurifier_VarParser_Native' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Native.php',
'HTMLPurifier_Zipper' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Zipper.php',
+ 'League\\HTMLToMarkdown\\Configuration' => $vendorDir . '/league/html-to-markdown/src/Configuration.php',
+ 'League\\HTMLToMarkdown\\ConfigurationAwareInterface' => $vendorDir . '/league/html-to-markdown/src/ConfigurationAwareInterface.php',
+ 'League\\HTMLToMarkdown\\Converter\\BlockquoteConverter' => $vendorDir . '/league/html-to-markdown/src/Converter/BlockquoteConverter.php',
+ 'League\\HTMLToMarkdown\\Converter\\CodeConverter' => $vendorDir . '/league/html-to-markdown/src/Converter/CodeConverter.php',
+ 'League\\HTMLToMarkdown\\Converter\\CommentConverter' => $vendorDir . '/league/html-to-markdown/src/Converter/CommentConverter.php',
+ 'League\\HTMLToMarkdown\\Converter\\ConverterInterface' => $vendorDir . '/league/html-to-markdown/src/Converter/ConverterInterface.php',
+ 'League\\HTMLToMarkdown\\Converter\\DefaultConverter' => $vendorDir . '/league/html-to-markdown/src/Converter/DefaultConverter.php',
+ 'League\\HTMLToMarkdown\\Converter\\DivConverter' => $vendorDir . '/league/html-to-markdown/src/Converter/DivConverter.php',
+ 'League\\HTMLToMarkdown\\Converter\\EmphasisConverter' => $vendorDir . '/league/html-to-markdown/src/Converter/EmphasisConverter.php',
+ 'League\\HTMLToMarkdown\\Converter\\HardBreakConverter' => $vendorDir . '/league/html-to-markdown/src/Converter/HardBreakConverter.php',
+ 'League\\HTMLToMarkdown\\Converter\\HeaderConverter' => $vendorDir . '/league/html-to-markdown/src/Converter/HeaderConverter.php',
+ 'League\\HTMLToMarkdown\\Converter\\HorizontalRuleConverter' => $vendorDir . '/league/html-to-markdown/src/Converter/HorizontalRuleConverter.php',
+ 'League\\HTMLToMarkdown\\Converter\\ImageConverter' => $vendorDir . '/league/html-to-markdown/src/Converter/ImageConverter.php',
+ 'League\\HTMLToMarkdown\\Converter\\LinkConverter' => $vendorDir . '/league/html-to-markdown/src/Converter/LinkConverter.php',
+ 'League\\HTMLToMarkdown\\Converter\\ListBlockConverter' => $vendorDir . '/league/html-to-markdown/src/Converter/ListBlockConverter.php',
+ 'League\\HTMLToMarkdown\\Converter\\ListItemConverter' => $vendorDir . '/league/html-to-markdown/src/Converter/ListItemConverter.php',
+ 'League\\HTMLToMarkdown\\Converter\\ParagraphConverter' => $vendorDir . '/league/html-to-markdown/src/Converter/ParagraphConverter.php',
+ 'League\\HTMLToMarkdown\\Converter\\PreformattedConverter' => $vendorDir . '/league/html-to-markdown/src/Converter/PreformattedConverter.php',
+ 'League\\HTMLToMarkdown\\Converter\\TextConverter' => $vendorDir . '/league/html-to-markdown/src/Converter/TextConverter.php',
+ 'League\\HTMLToMarkdown\\Element' => $vendorDir . '/league/html-to-markdown/src/Element.php',
+ 'League\\HTMLToMarkdown\\ElementInterface' => $vendorDir . '/league/html-to-markdown/src/ElementInterface.php',
+ 'League\\HTMLToMarkdown\\Environment' => $vendorDir . '/league/html-to-markdown/src/Environment.php',
+ 'League\\HTMLToMarkdown\\HtmlConverter' => $vendorDir . '/league/html-to-markdown/src/HtmlConverter.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_psr4.php b/vendor/composer/autoload_psr4.php
index a8d577d5e..61a440ffd 100644
--- a/vendor/composer/autoload_psr4.php
+++ b/vendor/composer/autoload_psr4.php
@@ -6,5 +6,6 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
+ 'League\\HTMLToMarkdown\\' => array($vendorDir . '/league/html-to-markdown/src'),
'Friendica\\' => array($baseDir . '/src'),
);
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..37d3c878b 100644
--- a/vendor/composer/autoload_static.php
+++ b/vendor/composer/autoload_static.php
@@ -11,6 +11,10 @@ class ComposerStaticInitFriendica
);
public static $prefixLengthsPsr4 = array (
+ 'L' =>
+ array (
+ 'League\\HTMLToMarkdown\\' => 22,
+ ),
'F' =>
array (
'Friendica\\' => 10,
@@ -18,6 +22,10 @@ class ComposerStaticInitFriendica
);
public static $prefixDirsPsr4 = array (
+ 'League\\HTMLToMarkdown\\' =>
+ array (
+ 0 => __DIR__ . '/..' . '/league/html-to-markdown/src',
+ ),
'Friendica\\' =>
array (
0 => __DIR__ . '/../..' . '/src',
@@ -42,6 +50,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',
@@ -275,7 +285,138 @@ class ComposerStaticInitFriendica
'HTMLPurifier_VarParser_Flexible' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Flexible.php',
'HTMLPurifier_VarParser_Native' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Native.php',
'HTMLPurifier_Zipper' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Zipper.php',
+ 'League\\HTMLToMarkdown\\Configuration' => __DIR__ . '/..' . '/league/html-to-markdown/src/Configuration.php',
+ 'League\\HTMLToMarkdown\\ConfigurationAwareInterface' => __DIR__ . '/..' . '/league/html-to-markdown/src/ConfigurationAwareInterface.php',
+ 'League\\HTMLToMarkdown\\Converter\\BlockquoteConverter' => __DIR__ . '/..' . '/league/html-to-markdown/src/Converter/BlockquoteConverter.php',
+ 'League\\HTMLToMarkdown\\Converter\\CodeConverter' => __DIR__ . '/..' . '/league/html-to-markdown/src/Converter/CodeConverter.php',
+ 'League\\HTMLToMarkdown\\Converter\\CommentConverter' => __DIR__ . '/..' . '/league/html-to-markdown/src/Converter/CommentConverter.php',
+ 'League\\HTMLToMarkdown\\Converter\\ConverterInterface' => __DIR__ . '/..' . '/league/html-to-markdown/src/Converter/ConverterInterface.php',
+ 'League\\HTMLToMarkdown\\Converter\\DefaultConverter' => __DIR__ . '/..' . '/league/html-to-markdown/src/Converter/DefaultConverter.php',
+ 'League\\HTMLToMarkdown\\Converter\\DivConverter' => __DIR__ . '/..' . '/league/html-to-markdown/src/Converter/DivConverter.php',
+ 'League\\HTMLToMarkdown\\Converter\\EmphasisConverter' => __DIR__ . '/..' . '/league/html-to-markdown/src/Converter/EmphasisConverter.php',
+ 'League\\HTMLToMarkdown\\Converter\\HardBreakConverter' => __DIR__ . '/..' . '/league/html-to-markdown/src/Converter/HardBreakConverter.php',
+ 'League\\HTMLToMarkdown\\Converter\\HeaderConverter' => __DIR__ . '/..' . '/league/html-to-markdown/src/Converter/HeaderConverter.php',
+ 'League\\HTMLToMarkdown\\Converter\\HorizontalRuleConverter' => __DIR__ . '/..' . '/league/html-to-markdown/src/Converter/HorizontalRuleConverter.php',
+ 'League\\HTMLToMarkdown\\Converter\\ImageConverter' => __DIR__ . '/..' . '/league/html-to-markdown/src/Converter/ImageConverter.php',
+ 'League\\HTMLToMarkdown\\Converter\\LinkConverter' => __DIR__ . '/..' . '/league/html-to-markdown/src/Converter/LinkConverter.php',
+ 'League\\HTMLToMarkdown\\Converter\\ListBlockConverter' => __DIR__ . '/..' . '/league/html-to-markdown/src/Converter/ListBlockConverter.php',
+ 'League\\HTMLToMarkdown\\Converter\\ListItemConverter' => __DIR__ . '/..' . '/league/html-to-markdown/src/Converter/ListItemConverter.php',
+ 'League\\HTMLToMarkdown\\Converter\\ParagraphConverter' => __DIR__ . '/..' . '/league/html-to-markdown/src/Converter/ParagraphConverter.php',
+ 'League\\HTMLToMarkdown\\Converter\\PreformattedConverter' => __DIR__ . '/..' . '/league/html-to-markdown/src/Converter/PreformattedConverter.php',
+ 'League\\HTMLToMarkdown\\Converter\\TextConverter' => __DIR__ . '/..' . '/league/html-to-markdown/src/Converter/TextConverter.php',
+ 'League\\HTMLToMarkdown\\Element' => __DIR__ . '/..' . '/league/html-to-markdown/src/Element.php',
+ 'League\\HTMLToMarkdown\\ElementInterface' => __DIR__ . '/..' . '/league/html-to-markdown/src/ElementInterface.php',
+ 'League\\HTMLToMarkdown\\Environment' => __DIR__ . '/..' . '/league/html-to-markdown/src/Environment.php',
+ 'League\\HTMLToMarkdown\\HtmlConverter' => __DIR__ . '/..' . '/league/html-to-markdown/src/HtmlConverter.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."
+ },
+ {
+ "name": "league/html-to-markdown",
+ "version": "4.4.1",
+ "version_normalized": "4.4.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/thephpleague/html-to-markdown.git",
+ "reference": "82ea375b5b2b1da1da222644c0565c695bf88186"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/82ea375b5b2b1da1da222644c0565c695bf88186",
+ "reference": "82ea375b5b2b1da1da222644c0565c695bf88186",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-xml": "*",
+ "php": ">=5.3.3"
+ },
+ "require-dev": {
+ "mikehaertl/php-shellcommand": "~1.1.0",
+ "phpunit/phpunit": "4.*",
+ "scrutinizer/ocular": "~1.1"
+ },
+ "time": "2017-03-16T00:45:59+00:00",
+ "bin": [
+ "bin/html-to-markdown"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.5-dev"
+ }
+ },
+ "installation-source": "dist",
+ "autoload": {
+ "psr-4": {
+ "League\\HTMLToMarkdown\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Colin O'Dell",
+ "email": "colinodell@gmail.com",
+ "homepage": "http://www.colinodell.com",
+ "role": "Lead Developer"
+ },
+ {
+ "name": "Nick Cernis",
+ "email": "nick@cern.is",
+ "homepage": "http://modernnerd.net",
+ "role": "Original Author"
+ }
+ ],
+ "description": "An HTML-to-markdown conversion helper for PHP",
+ "homepage": "https://github.com/thephpleague/html-to-markdown",
+ "keywords": [
+ "html",
+ "markdown"
+ ]
}
]
diff --git a/vendor/league/html-to-markdown/CHANGELOG.md b/vendor/league/html-to-markdown/CHANGELOG.md
new file mode 100644
index 000000000..067864412
--- /dev/null
+++ b/vendor/league/html-to-markdown/CHANGELOG.md
@@ -0,0 +1,214 @@
+# Change Log
+All notable changes to this project will be documented in this file.
+Updates should follow the [Keep a CHANGELOG](http://keepachangelog.com/) principles.
+
+## [Unreleased][unreleased]
+
+## [4.4.1]
+
+### Fixed
+ - Fixed autolinking of invalid URLs (#129)
+
+## [4.4.0]
+
+### Added
+ - Added `hard_break` configuration option (#112, #115)
+ - The `HtmlConverter` can now be instantiated with an `Environment` (#118)
+
+### Fixed
+ - Fixed handling of paragraphs in list item elements (#47, #110)
+ - Fixed phantom spaces when newlines follow `br` elements (#116, #117)
+ - Fixed link converter not sanitizing inner spaces properly (#119, #120)
+
+## [4.3.1]
+### Changed
+ - Revised the sanitization implementation (#109)
+
+### Fixed
+ - Fixed tag-like content not being escaped (#67, #109)
+ - Fixed thematic break-like content not being escaped (#65, #109)
+ - Fixed codefence-like content not being escaped (#64, #109)
+
+## [4.3.0]
+### Added
+ - Added full support for PHP 7.0 and 7.1
+
+### Changed
+ - Changed `` and `` conversions to use backticks instead of indendation (#102)
+
+### Fixed
+ - Fixed issue where specified code language was not preserved (#70, #102)
+ - Fixed issue where `` tags nested in `` was not converted properly (#70, #102)
+ - Fixed header-like content not being escaped (#76, #105)
+ - Fixed blockquote-like content not being escaped (#77, #103)
+ - Fixed ordered list-like content not being escaped (#73, #106)
+ - Fixed unordered list-like content not being escaped (#71, #107)
+
+## [4.2.2]
+### Fixed
+ - Fixed sanitization bug which sometimes removes desired content (#63, #101)
+
+## [4.2.1]
+### Fixed
+ - Fixed path to autoload.php when used as a library (#98)
+ - Fixed edge case for tags containing only whitespace (#99)
+
+### Removed
+ - Removed double HTML entity decoding, as this is not desireable (#60)
+
+## [4.2.0]
+
+### Added
+ - Added the ability to invoke HtmlConverter objects as functions (#85)
+
+### Fixed
+ - Fixed improper handling of nested list items (#19 and #84)
+ - Fixed preceeding or trailing spaces within emphasis tags (#83)
+
+## [4.1.1]
+
+### Fixed
+ - Fixed conversion of empty paragraphs (#78)
+ - Fixed `preg_replace` so it wouldn't break UTF-8 characters (#79)
+
+## [4.1.0]
+
+### Added
+ - Added `bin/html-to-markdown` script
+
+### Changed
+ - Changed default italic character to `_` (#58)
+
+## [4.0.1]
+
+### Fixed
+ - Added escaping to avoid * and _ in a text being rendered as emphasis (#48)
+
+### Removed
+ - Removed the demo (#51)
+ - `.styleci.yml` and `CONTRIBUTING.md` are no longer included in distributions (#50)
+
+## [4.0.0]
+
+This release changes the visibility of several methods/properties. #42 and #43 brought to light that some visiblities were
+not ideally set, so this releases fixes that. Moving forwards this should reduce the chance of introducing BC-breaking changes.
+
+### Added
+ - Added new `HtmlConverter::getEnvironment()` method to expose the `Environment` (#42, #43)
+
+### Changed
+ - Changed `Environment::addConverter()` from `protected` to `public`, enabling custom converters to be added (#42, #43)
+ - Changed `HtmlConverter::createDOMDocument()` from `protected` to `private`
+ - Changed `Element::nextCached` from `protected` to `private`
+ - Made the `Environment` class `final`
+
+## [3.1.1]
+### Fixed
+ - Empty HTML strings now result in empty Markdown documents (#40, #41)
+
+## [3.1.0]
+### Added
+ - Added new `equals` method to `Element` to check for equality
+
+### Changes
+ - Use Linux line endings consistently instead of plaform-specific line endings (#36)
+
+### Fixed
+ - Cleaned up code style
+
+## [3.0.0]
+### Changed
+ - Changed namespace to `League\HTMLToMarkdown`
+ - Changed packagist name to `league/html-to-markdown`
+ - Re-organized code into several separate classes
+ - `` tags with identical href and inner text are now rendered using angular bracket syntax (#31)
+ - `` elements are now treated as block-level elements (#33)
+
+## [2.2.2]
+### Added
+ - Added support for PHP 5.6 and HHVM
+ - Enabled testing against PHP 7 nightlies
+ - Added this CHANGELOG.md
+
+### Fixed
+ - Fixed whitespace preservation between inline elements (#9 and #10)
+
+## [2.2.1]
+### Fixed
+ - Preserve placeholder links (#22)
+
+## [2.2.0]
+### Added
+ - Added CircleCI config
+
+### Changed
+ - `` blocks are now treated as code elements
+
+### Removed
+ - Dropped support for PHP 5.2
+ - Removed incorrect README comment regarding `#text` nodes (#17)
+
+## [2.1.2]
+### Added
+ - Added the ability to blacklist/remove specific node types (#11)
+
+### Changed
+ - Line breaks are now placed after divs instead of before them
+ - Newlines inside of link texts are now removed
+ - Updated the minimum PHPUnit version to 4.*
+
+## [2.1.1]
+### Added
+ - Added options to customize emphasis characters
+
+## [2.1.0]
+### Added
+ - Added option to strip HTML tags without Markdown equivalents
+ - Added `convert()` method for converter reuse
+ - Added ability to set options after instance construction
+ - Documented the required PHP extensions (#4)
+
+### Changed
+ - ATX style now used for h1 and h2 tags inside blockquotes
+
+### Fixed
+ - Newlines inside blockquotes are now started with a bracket
+ - Fixed some incorrect docblocks
+ - `__toString()` now returns an empty string if input is empty
+ - Convert head tag if body tag is empty (#7)
+ - Preserve special characters inside tags without md equivalents (#6)
+
+
+## [2.0.1]
+### Fixed
+ - Fixed first line indentation for multi-line code blocks
+ - Fixed consecutive anchors get separating spaces stripped (#3)
+
+## [2.0.0]
+### Added
+ - Initial release
+
+[unreleased]: https://github.com/thephpleague/html-to-markdown/compare/4.4.1...master
+[4.4.1]: https://github.com/thephpleague/html-to-markdown/compare/4.4.0...4.4.1
+[4.4.0]: https://github.com/thephpleague/html-to-markdown/compare/4.3.1...4.4.0
+[4.3.1]: https://github.com/thephpleague/html-to-markdown/compare/4.3.0...4.3.1
+[4.3.0]: https://github.com/thephpleague/html-to-markdown/compare/4.2.2...4.3.0
+[4.2.2]: https://github.com/thephpleague/html-to-markdown/compare/4.2.1...4.2.2
+[4.2.1]: https://github.com/thephpleague/html-to-markdown/compare/4.2.0...4.2.1
+[4.2.0]: https://github.com/thephpleague/html-to-markdown/compare/4.1.1...4.2.0
+[4.1.1]: https://github.com/thephpleague/html-to-markdown/compare/4.1.0...4.1.1
+[4.1.0]: https://github.com/thephpleague/html-to-markdown/compare/4.0.1...4.1.0
+[4.0.1]: https://github.com/thephpleague/html-to-markdown/compare/4.0.0...4.0.1
+[4.0.0]: https://github.com/thephpleague/html-to-markdown/compare/3.1.1...4.0.0
+[3.1.1]: https://github.com/thephpleague/html-to-markdown/compare/3.1.0...3.1.1
+[3.1.0]: https://github.com/thephpleague/html-to-markdown/compare/3.0.0...3.1.0
+[3.0.0]: https://github.com/thephpleague/html-to-markdown/compare/2.2.2...3.0.0
+[2.2.2]: https://github.com/thephpleague/html-to-markdown/compare/2.2.1...2.2.2
+[2.2.1]: https://github.com/thephpleague/html-to-markdown/compare/2.2.0...2.2.1
+[2.2.0]: https://github.com/thephpleague/html-to-markdown/compare/2.1.2...2.2.0
+[2.1.2]: https://github.com/thephpleague/html-to-markdown/compare/2.1.1...2.1.2
+[2.1.1]: https://github.com/thephpleague/html-to-markdown/compare/2.1.0...2.1.1
+[2.1.0]: https://github.com/thephpleague/html-to-markdown/compare/2.0.1...2.1.0
+[2.0.1]: https://github.com/thephpleague/html-to-markdown/compare/2.0.0...2.0.1
+[2.0.0]: https://github.com/thephpleague/html-to-markdown/compare/775f91e...2.0.0
+
diff --git a/vendor/league/html-to-markdown/CONDUCT.md b/vendor/league/html-to-markdown/CONDUCT.md
new file mode 100644
index 000000000..01b8644f1
--- /dev/null
+++ b/vendor/league/html-to-markdown/CONDUCT.md
@@ -0,0 +1,22 @@
+# Contributor Code of Conduct
+
+As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
+
+We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality.
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery
+* Personal attacks
+* Trolling or insulting/derogatory comments
+* Public or private harassment
+* Publishing other's private information, such as physical or electronic addresses, without explicit permission
+* Other unethical or unprofessional conduct.
+
+Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team.
+
+This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
+
+This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/)
diff --git a/library/html-to-markdown/LICENSE b/vendor/league/html-to-markdown/LICENSE
similarity index 93%
rename from library/html-to-markdown/LICENSE
rename to vendor/league/html-to-markdown/LICENSE
index f538c2ac9..6c04a59dd 100644
--- a/library/html-to-markdown/LICENSE
+++ b/vendor/league/html-to-markdown/LICENSE
@@ -1,6 +1,8 @@
The MIT License (MIT)
-Copyright (c) 2013 Nick Cernis
+Copyright (c) 2015 Colin O'Dell
+
+Originally created by Nick Cernis
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
diff --git a/vendor/league/html-to-markdown/README.md b/vendor/league/html-to-markdown/README.md
new file mode 100644
index 000000000..8d75649d6
--- /dev/null
+++ b/vendor/league/html-to-markdown/README.md
@@ -0,0 +1,196 @@
+HTML To Markdown for PHP
+========================
+
+[![Join the chat at https://gitter.im/thephpleague/html-to-markdown](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/thephpleague/html-to-markdown?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+
+[![Latest Version](https://img.shields.io/packagist/v/league/html-to-markdown.svg?style=flat-square)](https://packagist.org/packages/league/html-to-markdown)
+[![Software License](http://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE)
+[![Build Status](https://img.shields.io/travis/thephpleague/html-to-markdown/master.svg?style=flat-square)](https://travis-ci.org/thephpleague/html-to-markdown)
+[![Coverage Status](https://img.shields.io/scrutinizer/coverage/g/thephpleague/html-to-markdown.svg?style=flat-square)](https://scrutinizer-ci.com/g/thephpleague/html-to-markdown/code-structure)
+[![Quality Score](https://img.shields.io/scrutinizer/g/thephpleague/html-to-markdown.svg?style=flat-square)](https://scrutinizer-ci.com/g/thephpleague/html-to-markdown)
+[![Total Downloads](https://img.shields.io/packagist/dt/league/html-to-markdown.svg?style=flat-square)](https://packagist.org/packages/league/html-to-markdown)
+
+Library which converts HTML to [Markdown](http://daringfireball.net/projects/markdown/) for your sanity and convenience.
+
+
+**Requires**: PHP 5.3+
+
+**Lead Developer**: [@colinodell](http://twitter.com/colinodell)
+
+**Original Author**: [@nickcernis](http://twitter.com/nickcernis)
+
+
+### Why convert HTML to Markdown?
+
+*"What alchemy is this?"* you mutter. *"I can see why you'd convert [Markdown to HTML](https://github.com/thephpleague/commonmark),"* you continue, already labouring the question somewhat, *"but why go the other way?"*
+
+Typically you would convert HTML to Markdown if:
+
+1. You have an existing HTML document that needs to be edited by people with good taste.
+2. You want to store new content in HTML format but edit it as Markdown.
+3. You want to convert HTML email to plain text email.
+4. You know a guy who's been converting HTML to Markdown for years, and now he can speak Elvish. You'd quite like to be able to speak Elvish.
+5. You just really like Markdown.
+
+### How to use it
+
+Require the library by issuing this command:
+
+```bash
+composer require league/html-to-markdown
+```
+
+Add `require 'vendor/autoload.php';` to the top of your script.
+
+Next, create a new HtmlConverter instance, passing in your valid HTML code to its `convert()` function:
+
+```php
+use League\HTMLToMarkdown\HtmlConverter;
+
+$converter = new HtmlConverter();
+
+$html = "Quick, to the Batpoles!
";
+$markdown = $converter->convert($html);
+```
+
+The `$markdown` variable now contains the Markdown version of your HTML as a string:
+
+```php
+echo $markdown; // ==> ### Quick, to the Batpoles!
+```
+
+The included `demo` directory contains an HTML->Markdown conversion form to try out.
+
+### Conversion options
+
+By default, HTML To Markdown preserves HTML tags without Markdown equivalents, like `` and ``.
+
+To strip HTML tags that don't have a Markdown equivalent while preserving the content inside them, set `strip_tags` to true, like this:
+
+```php
+$converter = new HtmlConverter(array('strip_tags' => true));
+
+$html = 'Turnips!';
+$markdown = $converter->convert($html); // $markdown now contains "Turnips!"
+```
+
+Or more explicitly, like this:
+
+```php
+$converter = new HtmlConverter();
+$converter->getConfig()->setOption('strip_tags', true);
+
+$html = 'Turnips!';
+$markdown = $converter->convert($html); // $markdown now contains "Turnips!"
+```
+
+Note that only the tags themselves are stripped, not the content they hold.
+
+To strip tags and their content, pass a space-separated list of tags in `remove_nodes`, like this:
+
+```php
+$converter = new HtmlConverter(array('remove_nodes' => 'span div'));
+
+$html = 'Turnips!Monkeys!';
+$markdown = $converter->convert($html); // $markdown now contains ""
+```
+
+### Style options
+
+Bold and italic tags are converted using the asterisk syntax by default. Change this to the underlined syntax using the `bold_style` and `italic_style` options.
+
+```php
+$converter = new HtmlConverter();
+$converter->getConfig()->setOption('italic_style', '_');
+$converter->getConfig()->setOption('bold_style', '__');
+
+$html = 'Italic and a bold';
+$markdown = $converter->convert($html); // $markdown now contains "_Italic_ and a __bold__"
+```
+
+### Line break options
+
+By default, `br` tags are converted to two spaces followed by a newline character as per [traditional Markdown](https://daringfireball.net/projects/markdown/syntax#p). Set `hard_break` to `true` to omit the two spaces, as per GitHub Flavored Markdown (GFM).
+
+```php
+$converter = new HtmlConverter();
+$html = 'test
line break
';
+
+$converter->getConfig()->setOption('hard_break', true);
+$markdown = $converter->convert($html); // $markdown now contains "test\nline break"
+
+$converter->getConfig()->setOption('hard_break', false); // default
+$markdown = $converter->convert($html); // $markdown now contains "test \nline break"
+```
+
+### Passing custom Environment object
+
+You can pass current `Environment` object to customize i.e. which converters should be used.
+
+```php
+$environment = new Environment(array(
+ // your configuration here
+));
+$environment->addConverter(new HeaderConverter()); // optionally - add converter manually
+
+$converter = new HtmlConverter($environment);
+
+$html = 'Header
+
+';
+$markdown = $converter->convert($html); // $markdown now contains "### Header" and ""
+```
+
+### Limitations
+
+- Markdown Extra, MultiMarkdown and other variants aren't supported – just Markdown.
+
+### Known issues
+
+- Nested lists and lists containing multiple paragraphs aren't converted correctly.
+- Lists inside blockquotes aren't converted correctly.
+- Any reported [open issues here](https://github.com/thephpleague/html-to-markdown/issues?state=open).
+
+[Report your issue or request a feature here.](https://github.com/thephpleague/html-to-markdown/issues/new) Issues with patches or failing tests are especially welcome.
+
+### Style notes
+
+- Setext (underlined) headers are the default for H1 and H2. If you prefer the ATX style for H1 and H2 (# Header 1 and ## Header 2), set `header_style` to 'atx' in the options array when you instantiate the object:
+
+ `$converter = new HtmlConverter(array('header_style'=>'atx'));`
+
+ Headers of H3 priority and lower always use atx style.
+
+- Links and images are referenced inline. Footnote references (where image src and anchor href attributes are listed in the footnotes) are not used.
+- Blockquotes aren't line wrapped – it makes the converted Markdown easier to edit.
+
+### Dependencies
+
+HTML To Markdown requires PHP's [xml](http://www.php.net/manual/en/xml.installation.php), [lib-xml](http://www.php.net/manual/en/libxml.installation.php), and [dom](http://www.php.net/manual/en/dom.installation.php) extensions, all of which are enabled by default on most distributions.
+
+Errors such as "Fatal error: Class 'DOMDocument' not found" on distributions such as CentOS that disable PHP's xml extension can be resolved by installing php-xml.
+
+### Contributors
+
+Many thanks to all [contributors](https://github.com/thephpleague/html-to-markdown/graphs/contributors) so far. Further improvements and feature suggestions are very welcome.
+
+### How it works
+
+HTML To Markdown creates a DOMDocument from the supplied HTML, walks through the tree, and converts each node to a text node containing the equivalent markdown, starting from the most deeply nested node and working inwards towards the root node.
+
+### To-do
+
+- Support for nested lists and lists inside blockquotes.
+- Offer an option to preserve tags as HTML if they contain attributes that can't be represented with Markdown (e.g. `style`).
+
+### Trying to convert Markdown to HTML?
+
+Use one of these great libraries:
+
+ - [league/commonmark](https://github.com/thephpleague/commonmark) (recommended)
+ - [cebe/markdown](https://github.com/cebe/markdown)
+ - [PHP Markdown](https://michelf.ca/projects/php-markdown/)
+ - [Parsedown](https://github.com/erusev/parsedown)
+
+No guarantees about the Elvish, though.
+
diff --git a/vendor/league/html-to-markdown/bin/html-to-markdown b/vendor/league/html-to-markdown/bin/html-to-markdown
new file mode 100644
index 000000000..2815a7cef
--- /dev/null
+++ b/vendor/league/html-to-markdown/bin/html-to-markdown
@@ -0,0 +1,108 @@
+#!/usr/bin/env php
+ $arg) {
+ if ($i === 0) {
+ continue;
+ }
+
+ if (substr($arg, 0, 1) === '-') {
+ switch ($arg) {
+ case '-h':
+ case '--help':
+ echo getHelpText();
+ exit(0);
+ default:
+ fail('Unknown option: ' . $arg);
+ }
+ } else {
+ $src = $argv[1];
+ }
+}
+
+if (isset($src)) {
+ if (!file_exists($src)) {
+ fail('File not found: ' . $src);
+ }
+
+ $html = file_get_contents($src);
+} else {
+ $stdin = fopen('php://stdin', 'r');
+ stream_set_blocking($stdin, false);
+ $html = stream_get_contents($stdin);
+ fclose($stdin);
+
+ if (empty($html)) {
+ fail(getHelpText());
+ }
+}
+
+
+$converter = new League\HTMLToMarkdown\HtmlConverter();
+echo $converter->convert($html);
+
+/**
+ * Get help and usage info
+ *
+ * @return string
+ */
+function getHelpText()
+{
+ return << output.md
+
+ Converting from STDIN:
+
+ echo -e 'Hello World!
' | html-to-markdown
+
+ Converting from STDIN and saving the output:
+
+ echo -e 'Hello World!
' | html-to-markdown > output.md
+
+HELP;
+}
+
+/**
+ * @param string $message Error message
+ */
+function fail($message)
+{
+ fwrite(STDERR, $message . "\n");
+ exit(1);
+}
+
+function requireAutoloader()
+{
+ $autoloadPaths = array(
+ // Local package usage
+ __DIR__ . '/../vendor/autoload.php',
+ // Package was included as a library
+ __DIR__ . '/../../../autoload.php',
+ );
+ foreach ($autoloadPaths as $path) {
+ if (file_exists($path)) {
+ require_once $path;
+ break;
+ }
+ }
+}
diff --git a/vendor/league/html-to-markdown/composer.json b/vendor/league/html-to-markdown/composer.json
new file mode 100644
index 000000000..58764bcb5
--- /dev/null
+++ b/vendor/league/html-to-markdown/composer.json
@@ -0,0 +1,48 @@
+{
+ "name": "league/html-to-markdown",
+ "type": "library",
+ "description": "An HTML-to-markdown conversion helper for PHP",
+ "keywords": ["markdown", "html"],
+ "homepage": "https://github.com/thephpleague/html-to-markdown",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Colin O'Dell",
+ "email": "colinodell@gmail.com",
+ "homepage": "http://www.colinodell.com",
+ "role": "Lead Developer"
+ },
+ {
+ "name": "Nick Cernis",
+ "email": "nick@cern.is",
+ "homepage": "http://modernnerd.net",
+ "role": "Original Author"
+ }
+ ],
+ "autoload": {
+ "psr-4": {
+ "League\\HTMLToMarkdown\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "League\\HTMLToMarkdown\\Test\\": "tests"
+ }
+ },
+ "require": {
+ "php": ">=5.3.3",
+ "ext-dom": "*",
+ "ext-xml": "*"
+ },
+ "require-dev": {
+ "mikehaertl/php-shellcommand": "~1.1.0",
+ "phpunit/phpunit": "4.*",
+ "scrutinizer/ocular": "~1.1"
+ },
+ "bin": ["bin/html-to-markdown"],
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.5-dev"
+ }
+ }
+}
diff --git a/vendor/league/html-to-markdown/src/Configuration.php b/vendor/league/html-to-markdown/src/Configuration.php
new file mode 100644
index 000000000..2943383aa
--- /dev/null
+++ b/vendor/league/html-to-markdown/src/Configuration.php
@@ -0,0 +1,60 @@
+config = $config;
+ }
+
+ /**
+ * @param array $config
+ */
+ public function merge(array $config = array())
+ {
+ $this->config = array_replace_recursive($this->config, $config);
+ }
+
+ /**
+ * @param array $config
+ */
+ public function replace(array $config = array())
+ {
+ $this->config = $config;
+ }
+
+ /**
+ * @param string $key
+ * @param mixed $value
+ */
+ public function setOption($key, $value)
+ {
+ $this->config[$key] = $value;
+ }
+
+ /**
+ * @param string|null $key
+ * @param mixed|null $default
+ *
+ * @return mixed|null
+ */
+ public function getOption($key = null, $default = null)
+ {
+ if ($key === null) {
+ return $this->config;
+ }
+
+ if (!isset($this->config[$key])) {
+ return $default;
+ }
+
+ return $this->config[$key];
+ }
+}
diff --git a/vendor/league/html-to-markdown/src/ConfigurationAwareInterface.php b/vendor/league/html-to-markdown/src/ConfigurationAwareInterface.php
new file mode 100644
index 000000000..8aca530be
--- /dev/null
+++ b/vendor/league/html-to-markdown/src/ConfigurationAwareInterface.php
@@ -0,0 +1,11 @@
+' symbols to each line.
+
+ $markdown = '';
+
+ $quote_content = trim($element->getValue());
+
+ $lines = preg_split('/\r\n|\r|\n/', $quote_content);
+
+ $total_lines = count($lines);
+
+ foreach ($lines as $i => $line) {
+ $markdown .= '> ' . $line . "\n";
+ if ($i + 1 === $total_lines) {
+ $markdown .= "\n";
+ }
+ }
+
+ return $markdown;
+ }
+
+ /**
+ * @return string[]
+ */
+ public function getSupportedTags()
+ {
+ return array('blockquote');
+ }
+}
diff --git a/vendor/league/html-to-markdown/src/Converter/CodeConverter.php b/vendor/league/html-to-markdown/src/Converter/CodeConverter.php
new file mode 100644
index 000000000..c8ec2c005
--- /dev/null
+++ b/vendor/league/html-to-markdown/src/Converter/CodeConverter.php
@@ -0,0 +1,62 @@
+getAttribute('class');
+
+ if ($classes) {
+ // Since tags can have more than one class, we need to find the one that starts with 'language-'
+ $classes = explode(' ', $classes);
+ foreach ($classes as $class) {
+ if (strpos($class, 'language-') !== false) {
+ // Found one, save it as the selected language and stop looping over the classes.
+ // The space after the language avoids gluing the actual code with the language tag
+ $language = str_replace('language-', '', $class) . ' ';
+ break;
+ }
+ }
+ }
+
+ $markdown = '';
+ $code = html_entity_decode($element->getChildrenAsString());
+
+ // In order to remove the code tags we need to search for them and, in the case of the opening tag
+ // use a regular expression to find the tag and the other attributes it might have
+ $code = preg_replace('/]*>/', '', $code);
+ $code = str_replace('
', '', $code);
+
+ // Checking if the code has multiple lines
+ $lines = preg_split('/\r\n|\r|\n/', $code);
+ if (count($lines) > 1) {
+ // Multiple lines detected, adding three backticks and newlines
+ $markdown .= '```' . $language . "\n" . $code . "\n" . '```';
+ } else {
+ // One line of code, wrapping it on one backtick.
+ $markdown .= '`' . $language . $code . '`';
+ }
+
+ return $markdown;
+ }
+
+ /**
+ * @return string[]
+ */
+ public function getSupportedTags()
+ {
+ return array('code');
+ }
+}
diff --git a/vendor/league/html-to-markdown/src/Converter/CommentConverter.php b/vendor/league/html-to-markdown/src/Converter/CommentConverter.php
new file mode 100644
index 000000000..55038b254
--- /dev/null
+++ b/vendor/league/html-to-markdown/src/Converter/CommentConverter.php
@@ -0,0 +1,26 @@
+config = $config;
+ }
+
+ /**
+ * @param ElementInterface $element
+ *
+ * @return string
+ */
+ public function convert(ElementInterface $element)
+ {
+ // If strip_tags is false (the default), preserve tags that don't have Markdown equivalents,
+ // such as nodes on their own. C14N() canonicalizes the node to a string.
+ // See: http://www.php.net/manual/en/domnode.c14n.php
+ if ($this->config->getOption('strip_tags', false)) {
+ return $element->getValue();
+ }
+
+ return html_entity_decode($element->getChildrenAsString());
+ }
+
+ /**
+ * @return string[]
+ */
+ public function getSupportedTags()
+ {
+ return array(self::DEFAULT_CONVERTER);
+ }
+}
diff --git a/vendor/league/html-to-markdown/src/Converter/DivConverter.php b/vendor/league/html-to-markdown/src/Converter/DivConverter.php
new file mode 100644
index 000000000..656a0ba4d
--- /dev/null
+++ b/vendor/league/html-to-markdown/src/Converter/DivConverter.php
@@ -0,0 +1,45 @@
+config = $config;
+ }
+
+ /**
+ * @param ElementInterface $element
+ *
+ * @return string
+ */
+ public function convert(ElementInterface $element)
+ {
+ if ($this->config->getOption('strip_tags', false)) {
+ return $element->getValue() . "\n\n";
+ }
+
+ return html_entity_decode($element->getChildrenAsString());
+ }
+
+ /**
+ * @return string[]
+ */
+ public function getSupportedTags()
+ {
+ return array('div');
+ }
+}
diff --git a/vendor/league/html-to-markdown/src/Converter/EmphasisConverter.php b/vendor/league/html-to-markdown/src/Converter/EmphasisConverter.php
new file mode 100644
index 000000000..67250769b
--- /dev/null
+++ b/vendor/league/html-to-markdown/src/Converter/EmphasisConverter.php
@@ -0,0 +1,57 @@
+config = $config;
+ }
+
+ /**
+ * @param ElementInterface $element
+ *
+ * @return string
+ */
+ public function convert(ElementInterface $element)
+ {
+ $tag = $element->getTagName();
+ $value = $element->getValue();
+
+ if (!trim($value)) {
+ return '';
+ }
+
+ if ($tag === 'i' || $tag === 'em') {
+ $style = $this->config->getOption('italic_style');
+ } else {
+ $style = $this->config->getOption('bold_style');
+ }
+
+ $prefix = ltrim($value) !== $value ? ' ' : '';
+ $suffix = rtrim($value) !== $value ? ' ' : '';
+
+ return $prefix . $style . trim($value) . $style . $suffix;
+ }
+
+ /**
+ * @return string[]
+ */
+ public function getSupportedTags()
+ {
+ return array('em', 'i', 'strong', 'b');
+ }
+}
diff --git a/vendor/league/html-to-markdown/src/Converter/HardBreakConverter.php b/vendor/league/html-to-markdown/src/Converter/HardBreakConverter.php
new file mode 100644
index 000000000..37cd44e73
--- /dev/null
+++ b/vendor/league/html-to-markdown/src/Converter/HardBreakConverter.php
@@ -0,0 +1,41 @@
+config = $config;
+ }
+
+ /**
+ * @param ElementInterface $element
+ *
+ * @return string
+ */
+ public function convert(ElementInterface $element)
+ {
+ return $this->config->getOption('hard_break') ? "\n" : " \n";
+ }
+
+ /**
+ * @return string[]
+ */
+ public function getSupportedTags()
+ {
+ return array('br');
+ }
+}
diff --git a/vendor/league/html-to-markdown/src/Converter/HeaderConverter.php b/vendor/league/html-to-markdown/src/Converter/HeaderConverter.php
new file mode 100644
index 000000000..d117e7d36
--- /dev/null
+++ b/vendor/league/html-to-markdown/src/Converter/HeaderConverter.php
@@ -0,0 +1,78 @@
+config = $config;
+ }
+
+ /**
+ * @param ElementInterface $element
+ *
+ * @return string
+ */
+ public function convert(ElementInterface $element)
+ {
+ $level = (int) substr($element->getTagName(), 1, 1);
+ $style = $this->config->getOption('header_style', self::STYLE_SETEXT);
+
+ if (($level === 1 || $level === 2) && !$element->isDescendantOf('blockquote') && $style === self::STYLE_SETEXT) {
+ return $this->createSetextHeader($level, $element->getValue());
+ }
+
+ return $this->createAtxHeader($level, $element->getValue());
+ }
+
+ /**
+ * @return string[]
+ */
+ public function getSupportedTags()
+ {
+ return array('h1', 'h2', 'h3', 'h4', 'h5', 'h6');
+ }
+
+ /**
+ * @param int $level
+ * @param string $content
+ *
+ * @return string
+ */
+ private function createSetextHeader($level, $content)
+ {
+ $length = function_exists('mb_strlen') ? mb_strlen($content, 'utf-8') : strlen($content);
+ $underline = ($level === 1) ? '=' : '-';
+
+ return $content . "\n" . str_repeat($underline, $length) . "\n\n";
+ }
+
+ /**
+ * @param int $level
+ * @param string $content
+ *
+ * @return string
+ */
+ private function createAtxHeader($level, $content)
+ {
+ $prefix = str_repeat('#', $level) . ' ';
+
+ return $prefix . $content . "\n\n";
+ }
+}
diff --git a/vendor/league/html-to-markdown/src/Converter/HorizontalRuleConverter.php b/vendor/league/html-to-markdown/src/Converter/HorizontalRuleConverter.php
new file mode 100644
index 000000000..8f54f9397
--- /dev/null
+++ b/vendor/league/html-to-markdown/src/Converter/HorizontalRuleConverter.php
@@ -0,0 +1,26 @@
+getAttribute('src');
+ $alt = $element->getAttribute('alt');
+ $title = $element->getAttribute('title');
+
+ if ($title !== '') {
+ // No newlines added. should be in a block-level element.
+ return '![' . $alt . '](' . $src . ' "' . $title . '")';
+ }
+
+ return '![' . $alt . '](' . $src . ')';
+ }
+
+ /**
+ * @return string[]
+ */
+ public function getSupportedTags()
+ {
+ return array('img');
+ }
+}
diff --git a/vendor/league/html-to-markdown/src/Converter/LinkConverter.php b/vendor/league/html-to-markdown/src/Converter/LinkConverter.php
new file mode 100644
index 000000000..f0765f38b
--- /dev/null
+++ b/vendor/league/html-to-markdown/src/Converter/LinkConverter.php
@@ -0,0 +1,52 @@
+getAttribute('href');
+ $title = $element->getAttribute('title');
+ $text = trim($element->getValue());
+
+ if ($title !== '') {
+ $markdown = '[' . $text . '](' . $href . ' "' . $title . '")';
+ } elseif ($href === $text && $this->isValidAutolink($href)) {
+ $markdown = '<' . $href . '>';
+ } else {
+ $markdown = '[' . $text . '](' . $href . ')';
+ }
+
+ if (!$href) {
+ $markdown = html_entity_decode($element->getChildrenAsString());
+ }
+
+ return $markdown;
+ }
+
+ /**
+ * @return string[]
+ */
+ public function getSupportedTags()
+ {
+ return array('a');
+ }
+
+ /**
+ * @param string $href
+ *
+ * @return bool
+ */
+ private function isValidAutolink($href)
+ {
+ return preg_match('/^[A-Za-z][A-Za-z0-9.+-]{1,31}:[^<>\x00-\x20]*/i', $href) === 1;
+ }
+}
diff --git a/vendor/league/html-to-markdown/src/Converter/ListBlockConverter.php b/vendor/league/html-to-markdown/src/Converter/ListBlockConverter.php
new file mode 100644
index 000000000..07a4c85a9
--- /dev/null
+++ b/vendor/league/html-to-markdown/src/Converter/ListBlockConverter.php
@@ -0,0 +1,26 @@
+getValue() . "\n";
+ }
+
+ /**
+ * @return string[]
+ */
+ public function getSupportedTags()
+ {
+ return array('ol', 'ul');
+ }
+}
diff --git a/vendor/league/html-to-markdown/src/Converter/ListItemConverter.php b/vendor/league/html-to-markdown/src/Converter/ListItemConverter.php
new file mode 100644
index 000000000..dafec077c
--- /dev/null
+++ b/vendor/league/html-to-markdown/src/Converter/ListItemConverter.php
@@ -0,0 +1,47 @@
+getParent()->getTagName();
+
+ // Add spaces to start for nested list items
+ $level = $element->getListItemLevel($element);
+
+ $prefixForParagraph = str_repeat(' ', $level + 1);
+ $value = trim(implode("\n" . $prefixForParagraph, explode("\n", trim($element->getValue()))));
+
+ // If list item is the first in a nested list, add a newline before it
+ $prefix = '';
+ if ($level > 0 && $element->getSiblingPosition() === 1) {
+ $prefix = "\n";
+ }
+
+ if ($list_type === 'ul') {
+ return $prefix . '- ' . $value . "\n";
+ }
+
+ $number = $element->getSiblingPosition();
+
+ return $prefix . $number . '. ' . $value . "\n";
+ }
+
+ /**
+ * @return string[]
+ */
+ public function getSupportedTags()
+ {
+ return array('li');
+ }
+}
diff --git a/vendor/league/html-to-markdown/src/Converter/ParagraphConverter.php b/vendor/league/html-to-markdown/src/Converter/ParagraphConverter.php
new file mode 100644
index 000000000..cf852bfcf
--- /dev/null
+++ b/vendor/league/html-to-markdown/src/Converter/ParagraphConverter.php
@@ -0,0 +1,124 @@
+getValue();
+
+ $markdown = '';
+
+ $lines = preg_split('/\r\n|\r|\n/', $value);
+ foreach ($lines as $line) {
+ /*
+ * Some special characters need to be escaped based on the position that they appear
+ * The following function will deal with those special cases.
+ */
+ $markdown .= $this->escapeSpecialCharacters($line);
+ $markdown .= "\n";
+ }
+
+ return trim($markdown) !== '' ? rtrim($markdown) . "\n\n" : '';
+ }
+
+ /**
+ * @return string[]
+ */
+ public function getSupportedTags()
+ {
+ return array('p');
+ }
+
+ /**
+ * @param string $line
+ *
+ * @return string
+ */
+ private function escapeSpecialCharacters($line)
+ {
+ $line = $this->escapeFirstCharacters($line);
+ $line = $this->escapeOtherCharacters($line);
+ $line = $this->escapeOtherCharactersRegex($line);
+
+ return $line;
+ }
+
+ /**
+ * @param string $line
+ *
+ * @return string
+ */
+ private function escapeFirstCharacters($line)
+ {
+ $escapable = array(
+ '>',
+ '- ',
+ '+ ',
+ '--',
+ '~~~',
+ '---',
+ '- - -'
+ );
+
+ foreach ($escapable as $i) {
+ if (strpos(ltrim($line), $i) === 0) {
+ // Found a character that must be escaped, adding a backslash before
+ return '\\' . ltrim($line);
+ }
+ }
+
+ return $line;
+ }
+
+ /**
+ * @param string $line
+ *
+ * @return string
+ */
+ private function escapeOtherCharacters($line)
+ {
+ $escapable = array(
+ '\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 and tags into a single tag with
+ * tags.
+ */
+ function flattenFilelist()
+ {
+ if (isset($this->_packageInfo['bundle'])) {
+ return;
+ }
+ $filelist = array();
+ if (isset($this->_packageInfo['contents']['dir']['dir'])) {
+ $this->_getFlattenedFilelist($filelist, $this->_packageInfo['contents']['dir']);
+ if (!isset($filelist[1])) {
+ $filelist = $filelist[0];
+ }
+ $this->_packageInfo['contents']['dir']['file'] = $filelist;
+ unset($this->_packageInfo['contents']['dir']['dir']);
+ } else {
+ // else already flattened but check for baseinstalldir propagation
+ if (isset($this->_packageInfo['contents']['dir']['attribs']['baseinstalldir'])) {
+ if (isset($this->_packageInfo['contents']['dir']['file'][0])) {
+ foreach ($this->_packageInfo['contents']['dir']['file'] as $i => $file) {
+ if (isset($file['attribs']['baseinstalldir'])) {
+ continue;
+ }
+ $this->_packageInfo['contents']['dir']['file'][$i]['attribs']['baseinstalldir']
+ = $this->_packageInfo['contents']['dir']['attribs']['baseinstalldir'];
+ }
+ } else {
+ if (!isset($this->_packageInfo['contents']['dir']['file']['attribs']['baseinstalldir'])) {
+ $this->_packageInfo['contents']['dir']['file']['attribs']['baseinstalldir']
+ = $this->_packageInfo['contents']['dir']['attribs']['baseinstalldir'];
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * @param array the final flattened file list
+ * @param array the current directory being processed
+ * @param string|false any recursively inherited baeinstalldir attribute
+ * @param string private recursion variable
+ * @return array
+ * @access protected
+ */
+ function _getFlattenedFilelist(&$files, $dir, $baseinstall = false, $path = '')
+ {
+ if (isset($dir['attribs']) && isset($dir['attribs']['baseinstalldir'])) {
+ $baseinstall = $dir['attribs']['baseinstalldir'];
+ }
+ if (isset($dir['dir'])) {
+ if (!isset($dir['dir'][0])) {
+ $dir['dir'] = array($dir['dir']);
+ }
+ foreach ($dir['dir'] as $subdir) {
+ if (!isset($subdir['attribs']) || !isset($subdir['attribs']['name'])) {
+ $name = '*unknown*';
+ } else {
+ $name = $subdir['attribs']['name'];
+ }
+ $newpath = empty($path) ? $name :
+ $path . '/' . $name;
+ $this->_getFlattenedFilelist($files, $subdir,
+ $baseinstall, $newpath);
+ }
+ }
+ if (isset($dir['file'])) {
+ if (!isset($dir['file'][0])) {
+ $dir['file'] = array($dir['file']);
+ }
+ foreach ($dir['file'] as $file) {
+ $attrs = $file['attribs'];
+ $name = $attrs['name'];
+ if ($baseinstall && !isset($attrs['baseinstalldir'])) {
+ $attrs['baseinstalldir'] = $baseinstall;
+ }
+ $attrs['name'] = empty($path) ? $name : $path . '/' . $name;
+ $attrs['name'] = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'),
+ $attrs['name']);
+ $file['attribs'] = $attrs;
+ $files[] = $file;
+ }
+ }
+ }
+
+ function setConfig(&$config)
+ {
+ $this->_config = &$config;
+ $this->_registry = &$config->getRegistry();
+ }
+
+ function setLogger(&$logger)
+ {
+ if (!is_object($logger) || !method_exists($logger, 'log')) {
+ return PEAR::raiseError('Logger must be compatible with PEAR_Common::log');
+ }
+ $this->_logger = &$logger;
+ }
+
+ /**
+ * WARNING - do not use this function directly unless you know what you're doing
+ */
+ function setDeps($deps)
+ {
+ $this->_packageInfo['dependencies'] = $deps;
+ }
+
+ /**
+ * WARNING - do not use this function directly unless you know what you're doing
+ */
+ function setCompatible($compat)
+ {
+ $this->_packageInfo['compatible'] = $compat;
+ }
+
+ function setPackagefile($file, $archive = false)
+ {
+ $this->_packageFile = $file;
+ $this->_archiveFile = $archive ? $archive : $file;
+ }
+
+ /**
+ * 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);
+ }
+
+ function getPackageFile()
+ {
+ return $this->_packageFile;
+ }
+
+ function getArchiveFile()
+ {
+ return $this->_archiveFile;
+ }
+
+
+ /**
+ * Directly set the array that defines this packagefile
+ *
+ * WARNING: no validation. This should only be performed by internal methods
+ * inside PEAR or by inputting an array saved from an existing PEAR_PackageFile_v2
+ * @param array
+ */
+ function fromArray($pinfo)
+ {
+ unset($pinfo['old']);
+ unset($pinfo['xsdversion']);
+ // If the changelog isn't an array then it was passed in as an empty tag
+ if (isset($pinfo['changelog']) && !is_array($pinfo['changelog'])) {
+ unset($pinfo['changelog']);
+ }
+ $this->_incomplete = false;
+ $this->_packageInfo = $pinfo;
+ }
+
+ function isIncomplete()
+ {
+ return $this->_incomplete;
+ }
+
+ /**
+ * @return array
+ */
+ function toArray($forreg = false)
+ {
+ if (!$this->validate(PEAR_VALIDATE_NORMAL)) {
+ return false;
+ }
+ return $this->getArray($forreg);
+ }
+
+ function getArray($forReg = false)
+ {
+ if ($forReg) {
+ $arr = $this->_packageInfo;
+ $arr['old'] = array();
+ $arr['old']['version'] = $this->getVersion();
+ $arr['old']['release_date'] = $this->getDate();
+ $arr['old']['release_state'] = $this->getState();
+ $arr['old']['release_license'] = $this->getLicense();
+ $arr['old']['release_notes'] = $this->getNotes();
+ $arr['old']['release_deps'] = $this->getDeps();
+ $arr['old']['maintainers'] = $this->getMaintainers();
+ $arr['xsdversion'] = '2.0';
+ return $arr;
+ } else {
+ $info = $this->_packageInfo;
+ unset($info['dirtree']);
+ if (isset($info['_lastversion'])) {
+ unset($info['_lastversion']);
+ }
+ if (isset($info['#binarypackage'])) {
+ unset($info['#binarypackage']);
+ }
+ return $info;
+ }
+ }
+
+ function packageInfo($field)
+ {
+ $arr = $this->getArray(true);
+ if ($field == 'state') {
+ return $arr['stability']['release'];
+ }
+ if ($field == 'api-version') {
+ return $arr['version']['api'];
+ }
+ if ($field == 'api-state') {
+ return $arr['stability']['api'];
+ }
+ if (isset($arr['old'][$field])) {
+ if (!is_string($arr['old'][$field])) {
+ return null;
+ }
+ return $arr['old'][$field];
+ }
+ if (isset($arr[$field])) {
+ if (!is_string($arr[$field])) {
+ return null;
+ }
+ return $arr[$field];
+ }
+ return null;
+ }
+
+ function getName()
+ {
+ return $this->getPackage();
+ }
+
+ function getPackage()
+ {
+ if (isset($this->_packageInfo['name'])) {
+ return $this->_packageInfo['name'];
+ }
+ return false;
+ }
+
+ function getChannel()
+ {
+ if (isset($this->_packageInfo['uri'])) {
+ return '__uri';
+ }
+ if (isset($this->_packageInfo['channel'])) {
+ return strtolower($this->_packageInfo['channel']);
+ }
+ return false;
+ }
+
+ function getUri()
+ {
+ if (isset($this->_packageInfo['uri'])) {
+ return $this->_packageInfo['uri'];
+ }
+ return false;
+ }
+
+ function getExtends()
+ {
+ if (isset($this->_packageInfo['extends'])) {
+ return $this->_packageInfo['extends'];
+ }
+ return false;
+ }
+
+ function getSummary()
+ {
+ if (isset($this->_packageInfo['summary'])) {
+ return $this->_packageInfo['summary'];
+ }
+ return false;
+ }
+
+ function getDescription()
+ {
+ if (isset($this->_packageInfo['description'])) {
+ return $this->_packageInfo['description'];
+ }
+ return false;
+ }
+
+ function getMaintainers($raw = false)
+ {
+ if (!isset($this->_packageInfo['lead'])) {
+ return false;
+ }
+ if ($raw) {
+ $ret = array('lead' => $this->_packageInfo['lead']);
+ (isset($this->_packageInfo['developer'])) ?
+ $ret['developer'] = $this->_packageInfo['developer'] :null;
+ (isset($this->_packageInfo['contributor'])) ?
+ $ret['contributor'] = $this->_packageInfo['contributor'] :null;
+ (isset($this->_packageInfo['helper'])) ?
+ $ret['helper'] = $this->_packageInfo['helper'] :null;
+ return $ret;
+ } else {
+ $ret = array();
+ $leads = isset($this->_packageInfo['lead'][0]) ? $this->_packageInfo['lead'] :
+ array($this->_packageInfo['lead']);
+ foreach ($leads as $lead) {
+ $s = $lead;
+ $s['handle'] = $s['user'];
+ unset($s['user']);
+ $s['role'] = 'lead';
+ $ret[] = $s;
+ }
+ if (isset($this->_packageInfo['developer'])) {
+ $leads = isset($this->_packageInfo['developer'][0]) ?
+ $this->_packageInfo['developer'] :
+ array($this->_packageInfo['developer']);
+ foreach ($leads as $maintainer) {
+ $s = $maintainer;
+ $s['handle'] = $s['user'];
+ unset($s['user']);
+ $s['role'] = 'developer';
+ $ret[] = $s;
+ }
+ }
+ if (isset($this->_packageInfo['contributor'])) {
+ $leads = isset($this->_packageInfo['contributor'][0]) ?
+ $this->_packageInfo['contributor'] :
+ array($this->_packageInfo['contributor']);
+ foreach ($leads as $maintainer) {
+ $s = $maintainer;
+ $s['handle'] = $s['user'];
+ unset($s['user']);
+ $s['role'] = 'contributor';
+ $ret[] = $s;
+ }
+ }
+ if (isset($this->_packageInfo['helper'])) {
+ $leads = isset($this->_packageInfo['helper'][0]) ?
+ $this->_packageInfo['helper'] :
+ array($this->_packageInfo['helper']);
+ foreach ($leads as $maintainer) {
+ $s = $maintainer;
+ $s['handle'] = $s['user'];
+ unset($s['user']);
+ $s['role'] = 'helper';
+ $ret[] = $s;
+ }
+ }
+ return $ret;
+ }
+ return false;
+ }
+
+ function getLeads()
+ {
+ if (isset($this->_packageInfo['lead'])) {
+ return $this->_packageInfo['lead'];
+ }
+ return false;
+ }
+
+ function getDevelopers()
+ {
+ if (isset($this->_packageInfo['developer'])) {
+ return $this->_packageInfo['developer'];
+ }
+ return false;
+ }
+
+ function getContributors()
+ {
+ if (isset($this->_packageInfo['contributor'])) {
+ return $this->_packageInfo['contributor'];
+ }
+ return false;
+ }
+
+ function getHelpers()
+ {
+ if (isset($this->_packageInfo['helper'])) {
+ return $this->_packageInfo['helper'];
+ }
+ return false;
+ }
+
+ function setDate($date)
+ {
+ if (!isset($this->_packageInfo['date'])) {
+ // ensure that the extends tag is set up in the right location
+ $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
+ array('time', 'version',
+ 'stability', 'license', 'notes', 'contents', 'compatible',
+ 'dependencies', 'providesextension', 'srcpackage', 'srcuri',
+ 'phprelease', 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease',
+ 'zendextbinrelease', 'bundle', 'changelog'), array(), 'date');
+ }
+ $this->_packageInfo['date'] = $date;
+ $this->_isValid = 0;
+ }
+
+ function setTime($time)
+ {
+ $this->_isValid = 0;
+ if (!isset($this->_packageInfo['time'])) {
+ // ensure that the time tag is set up in the right location
+ $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
+ array('version',
+ 'stability', 'license', 'notes', 'contents', 'compatible',
+ 'dependencies', 'providesextension', 'srcpackage', 'srcuri',
+ 'phprelease', 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease',
+ 'zendextbinrelease', 'bundle', 'changelog'), $time, 'time');
+ }
+ $this->_packageInfo['time'] = $time;
+ }
+
+ function getDate()
+ {
+ if (isset($this->_packageInfo['date'])) {
+ return $this->_packageInfo['date'];
+ }
+ return false;
+ }
+
+ function getTime()
+ {
+ if (isset($this->_packageInfo['time'])) {
+ return $this->_packageInfo['time'];
+ }
+ return false;
+ }
+
+ /**
+ * @param package|api version category to return
+ */
+ function getVersion($key = 'release')
+ {
+ if (isset($this->_packageInfo['version'][$key])) {
+ return $this->_packageInfo['version'][$key];
+ }
+ return false;
+ }
+
+ function getStability()
+ {
+ if (isset($this->_packageInfo['stability'])) {
+ return $this->_packageInfo['stability'];
+ }
+ return false;
+ }
+
+ function getState($key = 'release')
+ {
+ if (isset($this->_packageInfo['stability'][$key])) {
+ return $this->_packageInfo['stability'][$key];
+ }
+ return false;
+ }
+
+ function getLicense($raw = false)
+ {
+ if (isset($this->_packageInfo['license'])) {
+ if ($raw) {
+ return $this->_packageInfo['license'];
+ }
+ if (is_array($this->_packageInfo['license'])) {
+ return $this->_packageInfo['license']['_content'];
+ } else {
+ return $this->_packageInfo['license'];
+ }
+ }
+ return false;
+ }
+
+ function getLicenseLocation()
+ {
+ if (!isset($this->_packageInfo['license']) || !is_array($this->_packageInfo['license'])) {
+ return false;
+ }
+ return $this->_packageInfo['license']['attribs'];
+ }
+
+ function getNotes()
+ {
+ if (isset($this->_packageInfo['notes'])) {
+ return $this->_packageInfo['notes'];
+ }
+ return false;
+ }
+
+ /**
+ * Return the tag contents, if any
+ * @return array|false
+ */
+ function getUsesrole()
+ {
+ if (isset($this->_packageInfo['usesrole'])) {
+ return $this->_packageInfo['usesrole'];
+ }
+ return false;
+ }
+
+ /**
+ * Return the tag contents, if any
+ * @return array|false
+ */
+ function getUsestask()
+ {
+ if (isset($this->_packageInfo['usestask'])) {
+ return $this->_packageInfo['usestask'];
+ }
+ return false;
+ }
+
+ /**
+ * This should only be used to retrieve filenames and install attributes
+ */
+ function getFilelist($preserve = false)
+ {
+ if (isset($this->_packageInfo['filelist']) && !$preserve) {
+ return $this->_packageInfo['filelist'];
+ }
+ $this->flattenFilelist();
+ if ($contents = $this->getContents()) {
+ $ret = array();
+ if (!isset($contents['dir'])) {
+ return false;
+ }
+ if (!isset($contents['dir']['file'][0])) {
+ $contents['dir']['file'] = array($contents['dir']['file']);
+ }
+ foreach ($contents['dir']['file'] as $file) {
+ if (!isset($file['attribs']['name'])) {
+ continue;
+ }
+ $name = $file['attribs']['name'];
+ if (!$preserve) {
+ $file = $file['attribs'];
+ }
+ $ret[$name] = $file;
+ }
+ if (!$preserve) {
+ $this->_packageInfo['filelist'] = $ret;
+ }
+ return $ret;
+ }
+ return false;
+ }
+
+ /**
+ * Return configure options array, if any
+ *
+ * @return array|false
+ */
+ function getConfigureOptions()
+ {
+ if ($this->getPackageType() != 'extsrc' && $this->getPackageType() != 'zendextsrc') {
+ return false;
+ }
+
+ $releases = $this->getReleases();
+ if (isset($releases[0])) {
+ $releases = $releases[0];
+ }
+
+ if (isset($releases['configureoption'])) {
+ if (!isset($releases['configureoption'][0])) {
+ $releases['configureoption'] = array($releases['configureoption']);
+ }
+
+ for ($i = 0; $i < count($releases['configureoption']); $i++) {
+ $releases['configureoption'][$i] = $releases['configureoption'][$i]['attribs'];
+ }
+
+ return $releases['configureoption'];
+ }
+
+ return false;
+ }
+
+ /**
+ * This is only used at install-time, after all serialization
+ * is over.
+ */
+ function resetFilelist()
+ {
+ $this->_packageInfo['filelist'] = array();
+ }
+
+ /**
+ * Retrieve a list of files that should be installed on this computer
+ * @return array
+ */
+ function getInstallationFilelist($forfilecheck = false)
+ {
+ $contents = $this->getFilelist(true);
+ if (isset($contents['dir']['attribs']['baseinstalldir'])) {
+ $base = $contents['dir']['attribs']['baseinstalldir'];
+ }
+ if (isset($this->_packageInfo['bundle'])) {
+ return PEAR::raiseError(
+ 'Exception: bundles should be handled in download code only');
+ }
+ $release = $this->getReleases();
+ if ($release) {
+ if (!isset($release[0])) {
+ if (!isset($release['installconditions']) && !isset($release['filelist'])) {
+ if ($forfilecheck) {
+ return $this->getFilelist();
+ }
+ return $contents;
+ }
+ $release = array($release);
+ }
+ $depchecker = &$this->getPEARDependency2($this->_config, array(),
+ array('channel' => $this->getChannel(), 'package' => $this->getPackage()),
+ PEAR_VALIDATE_INSTALLING);
+ foreach ($release as $instance) {
+ if (isset($instance['installconditions'])) {
+ $installconditions = $instance['installconditions'];
+ if (is_array($installconditions)) {
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ foreach ($installconditions as $type => $conditions) {
+ if (!isset($conditions[0])) {
+ $conditions = array($conditions);
+ }
+ foreach ($conditions as $condition) {
+ $ret = $depchecker->{"validate{$type}Dependency"}($condition);
+ if (PEAR::isError($ret)) {
+ PEAR::popErrorHandling();
+ continue 3; // skip this release
+ }
+ }
+ }
+ PEAR::popErrorHandling();
+ }
+ }
+ // this is the release to use
+ if (isset($instance['filelist'])) {
+ // ignore files
+ if (isset($instance['filelist']['ignore'])) {
+ $ignore = isset($instance['filelist']['ignore'][0]) ?
+ $instance['filelist']['ignore'] :
+ array($instance['filelist']['ignore']);
+ foreach ($ignore as $ig) {
+ unset ($contents[$ig['attribs']['name']]);
+ }
+ }
+ // install files as this name
+ if (isset($instance['filelist']['install'])) {
+ $installas = isset($instance['filelist']['install'][0]) ?
+ $instance['filelist']['install'] :
+ array($instance['filelist']['install']);
+ foreach ($installas as $as) {
+ $contents[$as['attribs']['name']]['attribs']['install-as'] =
+ $as['attribs']['as'];
+ }
+ }
+ }
+ if ($forfilecheck) {
+ foreach ($contents as $file => $attrs) {
+ $contents[$file] = $attrs['attribs'];
+ }
+ }
+ return $contents;
+ }
+ } else { // simple release - no installconditions or install-as
+ if ($forfilecheck) {
+ return $this->getFilelist();
+ }
+ return $contents;
+ }
+ // no releases matched
+ return PEAR::raiseError('No releases in package.xml matched the existing operating ' .
+ 'system, extensions installed, or architecture, cannot install');
+ }
+
+ /**
+ * This is only used at install-time, after all serialization
+ * is over.
+ * @param string file name
+ * @param string installed path
+ */
+ function setInstalledAs($file, $path)
+ {
+ if ($path) {
+ return $this->_packageInfo['filelist'][$file]['installed_as'] = $path;
+ }
+ unset($this->_packageInfo['filelist'][$file]['installed_as']);
+ }
+
+ function getInstalledLocation($file)
+ {
+ if (isset($this->_packageInfo['filelist'][$file]['installed_as'])) {
+ return $this->_packageInfo['filelist'][$file]['installed_as'];
+ }
+ return false;
+ }
+
+ /**
+ * This is only used at install-time, after all serialization
+ * is over.
+ */
+ function installedFile($file, $atts)
+ {
+ if (isset($this->_packageInfo['filelist'][$file])) {
+ $this->_packageInfo['filelist'][$file] =
+ array_merge($this->_packageInfo['filelist'][$file], $atts['attribs']);
+ } else {
+ $this->_packageInfo['filelist'][$file] = $atts['attribs'];
+ }
+ }
+
+ /**
+ * Retrieve the contents tag
+ */
+ function getContents()
+ {
+ if (isset($this->_packageInfo['contents'])) {
+ return $this->_packageInfo['contents'];
+ }
+ return false;
+ }
+
+ /**
+ * @param string full path to file
+ * @param string attribute name
+ * @param string attribute value
+ * @param int risky but fast - use this to choose a file based on its position in the list
+ * of files. Index is zero-based like PHP arrays.
+ * @return bool success of operation
+ */
+ function setFileAttribute($filename, $attr, $value, $index = false)
+ {
+ $this->_isValid = 0;
+ if (in_array($attr, array('role', 'name', 'baseinstalldir'))) {
+ $this->_filesValid = false;
+ }
+ if ($index !== false &&
+ isset($this->_packageInfo['contents']['dir']['file'][$index]['attribs'])) {
+ $this->_packageInfo['contents']['dir']['file'][$index]['attribs'][$attr] = $value;
+ return true;
+ }
+ if (!isset($this->_packageInfo['contents']['dir']['file'])) {
+ return false;
+ }
+ $files = $this->_packageInfo['contents']['dir']['file'];
+ if (!isset($files[0])) {
+ $files = array($files);
+ $ind = false;
+ } else {
+ $ind = true;
+ }
+ foreach ($files as $i => $file) {
+ if (isset($file['attribs'])) {
+ if ($file['attribs']['name'] == $filename) {
+ if ($ind) {
+ $this->_packageInfo['contents']['dir']['file'][$i]['attribs'][$attr] = $value;
+ } else {
+ $this->_packageInfo['contents']['dir']['file']['attribs'][$attr] = $value;
+ }
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ 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']);
+ }
+
+ /**
+ * Determines whether this package claims it is compatible with the version of
+ * the package that has a recommended version dependency
+ * @param PEAR_PackageFile_v2|PEAR_PackageFile_v1|PEAR_Downloader_Package
+ * @return boolean
+ */
+ function isCompatible($pf)
+ {
+ if (!isset($this->_packageInfo['compatible'])) {
+ return false;
+ }
+ if (!isset($this->_packageInfo['channel'])) {
+ return false;
+ }
+ $me = $pf->getVersion();
+ $compatible = $this->_packageInfo['compatible'];
+ if (!isset($compatible[0])) {
+ $compatible = array($compatible);
+ }
+ $found = false;
+ foreach ($compatible as $info) {
+ if (strtolower($info['name']) == strtolower($pf->getPackage())) {
+ if (strtolower($info['channel']) == strtolower($pf->getChannel())) {
+ $found = true;
+ break;
+ }
+ }
+ }
+ if (!$found) {
+ return false;
+ }
+ if (isset($info['exclude'])) {
+ if (!isset($info['exclude'][0])) {
+ $info['exclude'] = array($info['exclude']);
+ }
+ foreach ($info['exclude'] as $exclude) {
+ if (version_compare($me, $exclude, '==')) {
+ return false;
+ }
+ }
+ }
+ if (version_compare($me, $info['min'], '>=') && version_compare($me, $info['max'], '<=')) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @return array|false
+ */
+ function getCompatible()
+ {
+ if (isset($this->_packageInfo['compatible'])) {
+ return $this->_packageInfo['compatible'];
+ }
+ return false;
+ }
+
+ function getDependencies()
+ {
+ if (isset($this->_packageInfo['dependencies'])) {
+ return $this->_packageInfo['dependencies'];
+ }
+ return false;
+ }
+
+ function isSubpackageOf($p)
+ {
+ return $p->isSubpackage($this);
+ }
+
+ /**
+ * Determines whether the passed in package is a subpackage of this package.
+ *
+ * No version checking is done, only name verification.
+ * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+ * @return bool
+ */
+ function isSubpackage($p)
+ {
+ $sub = array();
+ if (isset($this->_packageInfo['dependencies']['required']['subpackage'])) {
+ $sub = $this->_packageInfo['dependencies']['required']['subpackage'];
+ if (!isset($sub[0])) {
+ $sub = array($sub);
+ }
+ }
+ if (isset($this->_packageInfo['dependencies']['optional']['subpackage'])) {
+ $sub1 = $this->_packageInfo['dependencies']['optional']['subpackage'];
+ if (!isset($sub1[0])) {
+ $sub1 = array($sub1);
+ }
+ $sub = array_merge($sub, $sub1);
+ }
+ if (isset($this->_packageInfo['dependencies']['group'])) {
+ $group = $this->_packageInfo['dependencies']['group'];
+ if (!isset($group[0])) {
+ $group = array($group);
+ }
+ foreach ($group as $deps) {
+ if (isset($deps['subpackage'])) {
+ $sub2 = $deps['subpackage'];
+ if (!isset($sub2[0])) {
+ $sub2 = array($sub2);
+ }
+ $sub = array_merge($sub, $sub2);
+ }
+ }
+ }
+ foreach ($sub as $dep) {
+ if (strtolower($dep['name']) == strtolower($p->getPackage())) {
+ if (isset($dep['channel'])) {
+ if (strtolower($dep['channel']) == strtolower($p->getChannel())) {
+ return true;
+ }
+ } else {
+ if ($dep['uri'] == $p->getURI()) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ function dependsOn($package, $channel)
+ {
+ if (!($deps = $this->getDependencies())) {
+ return false;
+ }
+ foreach (array('package', 'subpackage') as $type) {
+ foreach (array('required', 'optional') as $needed) {
+ if (isset($deps[$needed][$type])) {
+ if (!isset($deps[$needed][$type][0])) {
+ $deps[$needed][$type] = array($deps[$needed][$type]);
+ }
+ foreach ($deps[$needed][$type] as $dep) {
+ $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri';
+ if (strtolower($dep['name']) == strtolower($package) &&
+ $depchannel == $channel) {
+ return true;
+ }
+ }
+ }
+ }
+ if (isset($deps['group'])) {
+ if (!isset($deps['group'][0])) {
+ $dep['group'] = array($deps['group']);
+ }
+ foreach ($deps['group'] as $group) {
+ if (isset($group[$type])) {
+ if (!is_array($group[$type])) {
+ $group[$type] = array($group[$type]);
+ }
+ foreach ($group[$type] as $dep) {
+ $depchannel = isset($dep['channel']) ? $dep['channel'] : '__uri';
+ if (strtolower($dep['name']) == strtolower($package) &&
+ $depchannel == $channel) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Get the contents of a dependency group
+ * @param string
+ * @return array|false
+ */
+ function getDependencyGroup($name)
+ {
+ $name = strtolower($name);
+ if (!isset($this->_packageInfo['dependencies']['group'])) {
+ return false;
+ }
+ $groups = $this->_packageInfo['dependencies']['group'];
+ if (!isset($groups[0])) {
+ $groups = array($groups);
+ }
+ foreach ($groups as $group) {
+ if (strtolower($group['attribs']['name']) == $name) {
+ return $group;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Retrieve a partial package.xml 1.0 representation of dependencies
+ *
+ * a very limited representation of dependencies is returned by this method.
+ * The tag for excluding certain versions of a dependency is
+ * completely ignored. In addition, dependency groups are ignored, with the
+ * assumption that all dependencies in dependency groups are also listed in
+ * the optional group that work with all dependency groups
+ * @param boolean return package.xml 2.0 tag
+ * @return array|false
+ */
+ function getDeps($raw = false, $nopearinstaller = false)
+ {
+ if (isset($this->_packageInfo['dependencies'])) {
+ if ($raw) {
+ return $this->_packageInfo['dependencies'];
+ }
+ $ret = array();
+ $map = array(
+ 'php' => 'php',
+ 'package' => 'pkg',
+ 'subpackage' => 'pkg',
+ 'extension' => 'ext',
+ 'os' => 'os',
+ 'pearinstaller' => 'pkg',
+ );
+ foreach (array('required', 'optional') as $type) {
+ $optional = ($type == 'optional') ? 'yes' : 'no';
+ if (!isset($this->_packageInfo['dependencies'][$type])
+ || empty($this->_packageInfo['dependencies'][$type])) {
+ continue;
+ }
+ foreach ($this->_packageInfo['dependencies'][$type] as $dtype => $deps) {
+ if ($dtype == 'pearinstaller' && $nopearinstaller) {
+ continue;
+ }
+ if (!isset($deps[0])) {
+ $deps = array($deps);
+ }
+ foreach ($deps as $dep) {
+ if (!isset($map[$dtype])) {
+ // no support for arch type
+ continue;
+ }
+ if ($dtype == 'pearinstaller') {
+ $dep['name'] = 'PEAR';
+ $dep['channel'] = 'pear.php.net';
+ }
+ $s = array('type' => $map[$dtype]);
+ if (isset($dep['channel'])) {
+ $s['channel'] = $dep['channel'];
+ }
+ if (isset($dep['uri'])) {
+ $s['uri'] = $dep['uri'];
+ }
+ if (isset($dep['name'])) {
+ $s['name'] = $dep['name'];
+ }
+ if (isset($dep['conflicts'])) {
+ $s['rel'] = 'not';
+ } else {
+ if (!isset($dep['min']) &&
+ !isset($dep['max'])) {
+ $s['rel'] = 'has';
+ $s['optional'] = $optional;
+ } elseif (isset($dep['min']) &&
+ isset($dep['max'])) {
+ $s['rel'] = 'ge';
+ $s1 = $s;
+ $s1['rel'] = 'le';
+ $s['version'] = $dep['min'];
+ $s1['version'] = $dep['max'];
+ if (isset($dep['channel'])) {
+ $s1['channel'] = $dep['channel'];
+ }
+ if ($dtype != 'php') {
+ $s['name'] = $dep['name'];
+ $s1['name'] = $dep['name'];
+ }
+ $s['optional'] = $optional;
+ $s1['optional'] = $optional;
+ $ret[] = $s1;
+ } elseif (isset($dep['min'])) {
+ if (isset($dep['exclude']) &&
+ $dep['exclude'] == $dep['min']) {
+ $s['rel'] = 'gt';
+ } else {
+ $s['rel'] = 'ge';
+ }
+ $s['version'] = $dep['min'];
+ $s['optional'] = $optional;
+ if ($dtype != 'php') {
+ $s['name'] = $dep['name'];
+ }
+ } elseif (isset($dep['max'])) {
+ if (isset($dep['exclude']) &&
+ $dep['exclude'] == $dep['max']) {
+ $s['rel'] = 'lt';
+ } else {
+ $s['rel'] = 'le';
+ }
+ $s['version'] = $dep['max'];
+ $s['optional'] = $optional;
+ if ($dtype != 'php') {
+ $s['name'] = $dep['name'];
+ }
+ }
+ }
+ $ret[] = $s;
+ }
+ }
+ }
+ if (count($ret)) {
+ return $ret;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @return php|extsrc|extbin|zendextsrc|zendextbin|bundle|false
+ */
+ function getPackageType()
+ {
+ if (isset($this->_packageInfo['phprelease'])) {
+ return 'php';
+ }
+ if (isset($this->_packageInfo['extsrcrelease'])) {
+ return 'extsrc';
+ }
+ if (isset($this->_packageInfo['extbinrelease'])) {
+ return 'extbin';
+ }
+ if (isset($this->_packageInfo['zendextsrcrelease'])) {
+ return 'zendextsrc';
+ }
+ if (isset($this->_packageInfo['zendextbinrelease'])) {
+ return 'zendextbin';
+ }
+ if (isset($this->_packageInfo['bundle'])) {
+ return 'bundle';
+ }
+ return false;
+ }
+
+ /**
+ * @return array|false
+ */
+ function getReleases()
+ {
+ $type = $this->getPackageType();
+ if ($type != 'bundle') {
+ $type .= 'release';
+ }
+ if ($this->getPackageType() && isset($this->_packageInfo[$type])) {
+ return $this->_packageInfo[$type];
+ }
+ return false;
+ }
+
+ /**
+ * @return array
+ */
+ function getChangelog()
+ {
+ if (isset($this->_packageInfo['changelog'])) {
+ return $this->_packageInfo['changelog'];
+ }
+ return false;
+ }
+
+ function hasDeps()
+ {
+ return isset($this->_packageInfo['dependencies']);
+ }
+
+ function getPackagexmlVersion()
+ {
+ if (isset($this->_packageInfo['zendextsrcrelease'])) {
+ return '2.1';
+ }
+ if (isset($this->_packageInfo['zendextbinrelease'])) {
+ return '2.1';
+ }
+ return '2.0';
+ }
+
+ /**
+ * @return array|false
+ */
+ function getSourcePackage()
+ {
+ if (isset($this->_packageInfo['extbinrelease']) ||
+ isset($this->_packageInfo['zendextbinrelease'])) {
+ return array('channel' => $this->_packageInfo['srcchannel'],
+ 'package' => $this->_packageInfo['srcpackage']);
+ }
+ return false;
+ }
+
+ function getBundledPackages()
+ {
+ if (isset($this->_packageInfo['bundle'])) {
+ return $this->_packageInfo['contents']['bundledpackage'];
+ }
+ return false;
+ }
+
+ function getLastModified()
+ {
+ if (isset($this->_packageInfo['_lastmodified'])) {
+ return $this->_packageInfo['_lastmodified'];
+ }
+ return false;
+ }
+
+ /**
+ * 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
+ $tar = new Archive_Tar($this->_archiveFile);
+ $tar->pushErrorHandling(PEAR_ERROR_RETURN);
+ if ($file != 'package.xml' && $file != 'package2.xml') {
+ $file = $this->getPackage() . '-' . $this->getVersion() . '/' . $file;
+ }
+ $file = $tar->extractInString($file);
+ $tar->popErrorHandling();
+ if (PEAR::isError($file)) {
+ return PEAR::raiseError("Cannot locate file '$file' in archive");
+ }
+ return $file;
+ }
+ }
+
+ function &getRW()
+ {
+ if (!class_exists('PEAR_PackageFile_v2_rw')) {
+ require_once 'PEAR/PackageFile/v2/rw.php';
+ }
+ $a = new PEAR_PackageFile_v2_rw;
+ foreach (get_object_vars($this) as $name => $unused) {
+ if (!isset($this->$name)) {
+ continue;
+ }
+ if ($name == '_config' || $name == '_logger'|| $name == '_registry' ||
+ $name == '_stack') {
+ $a->$name = &$this->$name;
+ } else {
+ $a->$name = $this->$name;
+ }
+ }
+ return $a;
+ }
+
+ function &getDefaultGenerator()
+ {
+ if (!class_exists('PEAR_PackageFile_Generator_v2')) {
+ require_once 'PEAR/PackageFile/Generator/v2.php';
+ }
+ $a = new PEAR_PackageFile_Generator_v2($this);
+ return $a;
+ }
+
+ function analyzeSourceCode($file, $string = false)
+ {
+ if (!isset($this->_v2Validator) ||
+ !is_a($this->_v2Validator, 'PEAR_PackageFile_v2_Validator')) {
+ if (!class_exists('PEAR_PackageFile_v2_Validator')) {
+ require_once 'PEAR/PackageFile/v2/Validator.php';
+ }
+ $this->_v2Validator = new PEAR_PackageFile_v2_Validator;
+ }
+ return $this->_v2Validator->analyzeSourceCode($file, $string);
+ }
+
+ function validate($state = PEAR_VALIDATE_NORMAL)
+ {
+ if (!isset($this->_packageInfo) || !is_array($this->_packageInfo)) {
+ return false;
+ }
+ if (!isset($this->_v2Validator) ||
+ !is_a($this->_v2Validator, 'PEAR_PackageFile_v2_Validator')) {
+ if (!class_exists('PEAR_PackageFile_v2_Validator')) {
+ require_once 'PEAR/PackageFile/v2/Validator.php';
+ }
+ $this->_v2Validator = new PEAR_PackageFile_v2_Validator;
+ }
+ if (isset($this->_packageInfo['xsdversion'])) {
+ unset($this->_packageInfo['xsdversion']);
+ }
+ return $this->_v2Validator->validate($this, $state);
+ }
+
+ function getTasksNs()
+ {
+ if (!isset($this->_tasksNs)) {
+ if (isset($this->_packageInfo['attribs'])) {
+ foreach ($this->_packageInfo['attribs'] as $name => $value) {
+ if ($value == 'http://pear.php.net/dtd/tasks-1.0') {
+ $this->_tasksNs = str_replace('xmlns:', '', $name);
+ break;
+ }
+ }
+ }
+ }
+ return $this->_tasksNs;
+ }
+
+ /**
+ * Determine whether a task name is a valid task. Custom tasks may be defined
+ * using subdirectories by putting a "-" in the name, as in
+ *
+ * Note that this method will auto-load the task class file and test for the existence
+ * of the name with "-" replaced by "_" as in PEAR/Task/mycustom/task.php makes class
+ * PEAR_Task_mycustom_task
+ * @param string
+ * @return boolean
+ */
+ function getTask($task)
+ {
+ $this->getTasksNs();
+ // transform all '-' to '/' and 'tasks:' to '' so tasks:replace becomes replace
+ $task = str_replace(array($this->_tasksNs . ':', '-'), array('', ' '), $task);
+ $taskfile = str_replace(' ', '/', ucwords($task));
+ $task = str_replace(array(' ', '/'), '_', ucwords($task));
+ if (class_exists("PEAR_Task_$task")) {
+ return "PEAR_Task_$task";
+ }
+ $fp = @fopen("PEAR/Task/$taskfile.php", 'r', true);
+ if ($fp) {
+ fclose($fp);
+ require_once "PEAR/Task/$taskfile.php";
+ return "PEAR_Task_$task";
+ }
+ return false;
+ }
+
+ /**
+ * Key-friendly array_splice
+ * @param tagname to splice a value in before
+ * @param mixed the value to splice in
+ * @param string the new tag name
+ */
+ function _ksplice($array, $key, $value, $newkey)
+ {
+ $offset = array_search($key, array_keys($array));
+ $after = array_slice($array, $offset);
+ $before = array_slice($array, 0, $offset);
+ $before[$newkey] = $value;
+ return array_merge($before, $after);
+ }
+
+ /**
+ * @param array a list of possible keys, in the order they may occur
+ * @param mixed contents of the new package.xml tag
+ * @param string tag name
+ * @access private
+ */
+ function _insertBefore($array, $keys, $contents, $newkey)
+ {
+ foreach ($keys as $key) {
+ if (isset($array[$key])) {
+ return $array = $this->_ksplice($array, $key, $contents, $newkey);
+ }
+ }
+ $array[$newkey] = $contents;
+ return $array;
+ }
+
+ /**
+ * @param subsection of {@link $_packageInfo}
+ * @param array|string tag contents
+ * @param array format:
+ *
+ * array(
+ * tagname => array(list of tag names that follow this one),
+ * childtagname => array(list of child tag names that follow this one),
+ * )
+ *
+ *
+ * This allows construction of nested tags
+ * @access private
+ */
+ function _mergeTag($manip, $contents, $order)
+ {
+ if (count($order)) {
+ foreach ($order as $tag => $curorder) {
+ if (!isset($manip[$tag])) {
+ // ensure that the tag is set up
+ $manip = $this->_insertBefore($manip, $curorder, array(), $tag);
+ }
+ if (count($order) > 1) {
+ $manip[$tag] = $this->_mergeTag($manip[$tag], $contents, array_slice($order, 1));
+ return $manip;
+ }
+ }
+ } else {
+ return $manip;
+ }
+ if (is_array($manip[$tag]) && !empty($manip[$tag]) && isset($manip[$tag][0])) {
+ $manip[$tag][] = $contents;
+ } else {
+ if (!count($manip[$tag])) {
+ $manip[$tag] = $contents;
+ } else {
+ $manip[$tag] = array($manip[$tag]);
+ $manip[$tag][] = $contents;
+ }
+ }
+ return $manip;
+ }
+}
+?>
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/PackageFile/v2/Validator.php b/vendor/pear-pear.php.net/PEAR/PEAR/PackageFile/v2/Validator.php
new file mode 100644
index 000000000..f7c8921e1
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/PackageFile/v2/Validator.php
@@ -0,0 +1,2135 @@
+
+ * @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.0a8
+ */
+/**
+ * Private validation class used by PEAR_PackageFile_v2 - do not use directly, its
+ * sole purpose is to split up the PEAR/PackageFile/v2.php file to make it smaller
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a8
+ * @access private
+ */
+class PEAR_PackageFile_v2_Validator
+{
+ /**
+ * @var array
+ */
+ var $_packageInfo;
+ /**
+ * @var PEAR_PackageFile_v2
+ */
+ var $_pf;
+ /**
+ * @var PEAR_ErrorStack
+ */
+ var $_stack;
+ /**
+ * @var int
+ */
+ var $_isValid = 0;
+ /**
+ * @var int
+ */
+ var $_filesValid = 0;
+ /**
+ * @var int
+ */
+ var $_curState = 0;
+ /**
+ * @param PEAR_PackageFile_v2
+ * @param int
+ */
+ function validate(&$pf, $state = PEAR_VALIDATE_NORMAL)
+ {
+ $this->_pf = &$pf;
+ $this->_curState = $state;
+ $this->_packageInfo = $this->_pf->getArray();
+ $this->_isValid = $this->_pf->_isValid;
+ $this->_filesValid = $this->_pf->_filesValid;
+ $this->_stack = &$pf->_stack;
+ $this->_stack->getErrors(true);
+ if (($this->_isValid & $state) == $state) {
+ return true;
+ }
+ if (!isset($this->_packageInfo) || !is_array($this->_packageInfo)) {
+ return false;
+ }
+ if (!isset($this->_packageInfo['attribs']['version']) ||
+ ($this->_packageInfo['attribs']['version'] != '2.0' &&
+ $this->_packageInfo['attribs']['version'] != '2.1')
+ ) {
+ $this->_noPackageVersion();
+ }
+ $structure =
+ array(
+ 'name',
+ 'channel|uri',
+ '*extends', // can't be multiple, but this works fine
+ 'summary',
+ 'description',
+ '+lead', // these all need content checks
+ '*developer',
+ '*contributor',
+ '*helper',
+ 'date',
+ '*time',
+ 'version',
+ 'stability',
+ 'license->?uri->?filesource',
+ 'notes',
+ 'contents', //special validation needed
+ '*compatible',
+ 'dependencies', //special validation needed
+ '*usesrole',
+ '*usestask', // reserve these for 1.4.0a1 to implement
+ // this will allow a package.xml to gracefully say it
+ // needs a certain package installed in order to implement a role or task
+ '*providesextension',
+ '*srcpackage|*srcuri',
+ '+phprelease|+extsrcrelease|+extbinrelease|' .
+ '+zendextsrcrelease|+zendextbinrelease|bundle', //special validation needed
+ '*changelog',
+ );
+ $test = $this->_packageInfo;
+ if (isset($test['dependencies']) &&
+ isset($test['dependencies']['required']) &&
+ isset($test['dependencies']['required']['pearinstaller']) &&
+ isset($test['dependencies']['required']['pearinstaller']['min']) &&
+ '1.10.3' != '@package' . '_version@' &&
+ version_compare('1.10.3',
+ $test['dependencies']['required']['pearinstaller']['min'], '<')
+ ) {
+ $this->_pearVersionTooLow($test['dependencies']['required']['pearinstaller']['min']);
+ return false;
+ }
+ // ignore post-installation array fields
+ if (array_key_exists('filelist', $test)) {
+ unset($test['filelist']);
+ }
+ if (array_key_exists('_lastmodified', $test)) {
+ unset($test['_lastmodified']);
+ }
+ if (array_key_exists('#binarypackage', $test)) {
+ unset($test['#binarypackage']);
+ }
+ if (array_key_exists('old', $test)) {
+ unset($test['old']);
+ }
+ if (array_key_exists('_lastversion', $test)) {
+ unset($test['_lastversion']);
+ }
+ if (!$this->_stupidSchemaValidate($structure, $test, '')) {
+ return false;
+ }
+ if (empty($this->_packageInfo['name'])) {
+ $this->_tagCannotBeEmpty('name');
+ }
+ $test = isset($this->_packageInfo['uri']) ? 'uri' :'channel';
+ if (empty($this->_packageInfo[$test])) {
+ $this->_tagCannotBeEmpty($test);
+ }
+ if (is_array($this->_packageInfo['license']) &&
+ (!isset($this->_packageInfo['license']['_content']) ||
+ empty($this->_packageInfo['license']['_content']))) {
+ $this->_tagCannotBeEmpty('license');
+ } elseif (empty($this->_packageInfo['license'])) {
+ $this->_tagCannotBeEmpty('license');
+ }
+ if (empty($this->_packageInfo['summary'])) {
+ $this->_tagCannotBeEmpty('summary');
+ }
+ if (empty($this->_packageInfo['description'])) {
+ $this->_tagCannotBeEmpty('description');
+ }
+ if (empty($this->_packageInfo['date'])) {
+ $this->_tagCannotBeEmpty('date');
+ }
+ if (empty($this->_packageInfo['notes'])) {
+ $this->_tagCannotBeEmpty('notes');
+ }
+ if (isset($this->_packageInfo['time']) && empty($this->_packageInfo['time'])) {
+ $this->_tagCannotBeEmpty('time');
+ }
+ if (isset($this->_packageInfo['dependencies'])) {
+ $this->_validateDependencies();
+ }
+ if (isset($this->_packageInfo['compatible'])) {
+ $this->_validateCompatible();
+ }
+ if (!isset($this->_packageInfo['bundle'])) {
+ if (empty($this->_packageInfo['contents'])) {
+ $this->_tagCannotBeEmpty('contents');
+ }
+ if (!isset($this->_packageInfo['contents']['dir'])) {
+ $this->_filelistMustContainDir('contents');
+ return false;
+ }
+ if (isset($this->_packageInfo['contents']['file'])) {
+ $this->_filelistCannotContainFile('contents');
+ return false;
+ }
+ }
+ $this->_validateMaintainers();
+ $this->_validateStabilityVersion();
+ $fail = false;
+ if (array_key_exists('usesrole', $this->_packageInfo)) {
+ $roles = $this->_packageInfo['usesrole'];
+ if (!is_array($roles) || !isset($roles[0])) {
+ $roles = array($roles);
+ }
+ foreach ($roles as $role) {
+ if (!isset($role['role'])) {
+ $this->_usesroletaskMustHaveRoleTask('usesrole', 'role');
+ $fail = true;
+ } else {
+ if (!isset($role['channel'])) {
+ if (!isset($role['uri'])) {
+ $this->_usesroletaskMustHaveChannelOrUri($role['role'], 'usesrole');
+ $fail = true;
+ }
+ } elseif (!isset($role['package'])) {
+ $this->_usesroletaskMustHavePackage($role['role'], 'usesrole');
+ $fail = true;
+ }
+ }
+ }
+ }
+ if (array_key_exists('usestask', $this->_packageInfo)) {
+ $roles = $this->_packageInfo['usestask'];
+ if (!is_array($roles) || !isset($roles[0])) {
+ $roles = array($roles);
+ }
+ foreach ($roles as $role) {
+ if (!isset($role['task'])) {
+ $this->_usesroletaskMustHaveRoleTask('usestask', 'task');
+ $fail = true;
+ } else {
+ if (!isset($role['channel'])) {
+ if (!isset($role['uri'])) {
+ $this->_usesroletaskMustHaveChannelOrUri($role['task'], 'usestask');
+ $fail = true;
+ }
+ } elseif (!isset($role['package'])) {
+ $this->_usesroletaskMustHavePackage($role['task'], 'usestask');
+ $fail = true;
+ }
+ }
+ }
+ }
+
+ if ($fail) {
+ return false;
+ }
+
+ $list = $this->_packageInfo['contents'];
+ if (isset($list['dir']) && is_array($list['dir']) && isset($list['dir'][0])) {
+ $this->_multipleToplevelDirNotAllowed();
+ return $this->_isValid = 0;
+ }
+
+ $this->_validateFilelist();
+ $this->_validateRelease();
+ if (!$this->_stack->hasErrors()) {
+ $chan = $this->_pf->_registry->getChannel($this->_pf->getChannel(), true);
+ if (PEAR::isError($chan)) {
+ $this->_unknownChannel($this->_pf->getChannel());
+ } else {
+ $valpack = $chan->getValidationPackage();
+ // for channel validator packages, always use the default PEAR validator.
+ // otherwise, they can't be installed or packaged
+ $validator = $chan->getValidationObject($this->_pf->getPackage());
+ if (!$validator) {
+ $this->_stack->push(__FUNCTION__, 'error',
+ array('channel' => $chan->getName(),
+ 'package' => $this->_pf->getPackage(),
+ 'name' => $valpack['_content'],
+ 'version' => $valpack['attribs']['version']),
+ 'package "%channel%/%package%" cannot be properly validated without ' .
+ 'validation package "%channel%/%name%-%version%"');
+ return $this->_isValid = 0;
+ }
+ $validator->setPackageFile($this->_pf);
+ $validator->validate($state);
+ $failures = $validator->getFailures();
+ foreach ($failures['errors'] as $error) {
+ $this->_stack->push(__FUNCTION__, 'error', $error,
+ 'Channel validator error: field "%field%" - %reason%');
+ }
+ foreach ($failures['warnings'] as $warning) {
+ $this->_stack->push(__FUNCTION__, 'warning', $warning,
+ 'Channel validator warning: field "%field%" - %reason%');
+ }
+ }
+ }
+
+ $this->_pf->_isValid = $this->_isValid = !$this->_stack->hasErrors('error');
+ if ($this->_isValid && $state == PEAR_VALIDATE_PACKAGING && !$this->_filesValid) {
+ if ($this->_pf->getPackageType() == 'bundle') {
+ if ($this->_analyzeBundledPackages()) {
+ $this->_filesValid = $this->_pf->_filesValid = true;
+ } else {
+ $this->_pf->_isValid = $this->_isValid = 0;
+ }
+ } else {
+ if (!$this->_analyzePhpFiles()) {
+ $this->_pf->_isValid = $this->_isValid = 0;
+ } else {
+ $this->_filesValid = $this->_pf->_filesValid = true;
+ }
+ }
+ }
+
+ if ($this->_isValid) {
+ return $this->_pf->_isValid = $this->_isValid = $state;
+ }
+
+ return $this->_pf->_isValid = $this->_isValid = 0;
+ }
+
+ function _stupidSchemaValidate($structure, $xml, $root)
+ {
+ if (!is_array($xml)) {
+ $xml = array();
+ }
+ $keys = array_keys($xml);
+ reset($keys);
+ $key = current($keys);
+ while ($key == 'attribs' || $key == '_contents') {
+ $key = next($keys);
+ }
+ $unfoundtags = $optionaltags = array();
+ $ret = true;
+ $mismatch = false;
+ foreach ($structure as $struc) {
+ if ($key) {
+ $tag = $xml[$key];
+ }
+ $test = $this->_processStructure($struc);
+ if (isset($test['choices'])) {
+ $loose = true;
+ foreach ($test['choices'] as $choice) {
+ if ($key == $choice['tag']) {
+ $key = next($keys);
+ while ($key == 'attribs' || $key == '_contents') {
+ $key = next($keys);
+ }
+ $unfoundtags = $optionaltags = array();
+ $mismatch = false;
+ if ($key && $key != $choice['tag'] && isset($choice['multiple'])) {
+ $unfoundtags[] = $choice['tag'];
+ $optionaltags[] = $choice['tag'];
+ if ($key) {
+ $mismatch = true;
+ }
+ }
+ $ret &= $this->_processAttribs($choice, $tag, $root);
+ continue 2;
+ } else {
+ $unfoundtags[] = $choice['tag'];
+ $mismatch = true;
+ }
+ if (!isset($choice['multiple']) || $choice['multiple'] != '*') {
+ $loose = false;
+ } else {
+ $optionaltags[] = $choice['tag'];
+ }
+ }
+ if (!$loose) {
+ $this->_invalidTagOrder($unfoundtags, $key, $root);
+ return false;
+ }
+ } else {
+ if ($key != $test['tag']) {
+ if (isset($test['multiple']) && $test['multiple'] != '*') {
+ $unfoundtags[] = $test['tag'];
+ $this->_invalidTagOrder($unfoundtags, $key, $root);
+ return false;
+ } else {
+ if ($key) {
+ $mismatch = true;
+ }
+ $unfoundtags[] = $test['tag'];
+ $optionaltags[] = $test['tag'];
+ }
+ if (!isset($test['multiple'])) {
+ $this->_invalidTagOrder($unfoundtags, $key, $root);
+ return false;
+ }
+ continue;
+ } else {
+ $unfoundtags = $optionaltags = array();
+ $mismatch = false;
+ }
+ $key = next($keys);
+ while ($key == 'attribs' || $key == '_contents') {
+ $key = next($keys);
+ }
+ if ($key && $key != $test['tag'] && isset($test['multiple'])) {
+ $unfoundtags[] = $test['tag'];
+ $optionaltags[] = $test['tag'];
+ $mismatch = true;
+ }
+ $ret &= $this->_processAttribs($test, $tag, $root);
+ continue;
+ }
+ }
+ if (!$mismatch && count($optionaltags)) {
+ // don't error out on any optional tags
+ $unfoundtags = array_diff($unfoundtags, $optionaltags);
+ }
+ if (count($unfoundtags)) {
+ $this->_invalidTagOrder($unfoundtags, $key, $root);
+ } elseif ($key) {
+ // unknown tags
+ $this->_invalidTagOrder('*no tags allowed here*', $key, $root);
+ while ($key = next($keys)) {
+ $this->_invalidTagOrder('*no tags allowed here*', $key, $root);
+ }
+ }
+ return $ret;
+ }
+
+ function _processAttribs($choice, $tag, $context)
+ {
+ if (isset($choice['attribs'])) {
+ if (!is_array($tag)) {
+ $tag = array($tag);
+ }
+ $tags = $tag;
+ if (!isset($tags[0])) {
+ $tags = array($tags);
+ }
+ $ret = true;
+ foreach ($tags as $i => $tag) {
+ if (!is_array($tag) || !isset($tag['attribs'])) {
+ foreach ($choice['attribs'] as $attrib) {
+ if ($attrib{0} != '?') {
+ $ret &= $this->_tagHasNoAttribs($choice['tag'],
+ $context);
+ continue 2;
+ }
+ }
+ }
+ foreach ($choice['attribs'] as $attrib) {
+ if ($attrib{0} != '?') {
+ if (!isset($tag['attribs'][$attrib])) {
+ $ret &= $this->_tagMissingAttribute($choice['tag'],
+ $attrib, $context);
+ }
+ }
+ }
+ }
+ return $ret;
+ }
+ return true;
+ }
+
+ function _processStructure($key)
+ {
+ $ret = array();
+ if (count($pieces = explode('|', $key)) > 1) {
+ $ret['choices'] = array();
+ foreach ($pieces as $piece) {
+ $ret['choices'][] = $this->_processStructure($piece);
+ }
+ return $ret;
+ }
+ $multi = $key{0};
+ if ($multi == '+' || $multi == '*') {
+ $ret['multiple'] = $key{0};
+ $key = substr($key, 1);
+ }
+ if (count($attrs = explode('->', $key)) > 1) {
+ $ret['tag'] = array_shift($attrs);
+ $ret['attribs'] = $attrs;
+ } else {
+ $ret['tag'] = $key;
+ }
+ return $ret;
+ }
+
+ function _validateStabilityVersion()
+ {
+ $structure = array('release', 'api');
+ $a = $this->_stupidSchemaValidate($structure, $this->_packageInfo['version'], '');
+ $a &= $this->_stupidSchemaValidate($structure, $this->_packageInfo['stability'], '');
+ if ($a) {
+ if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
+ $this->_packageInfo['version']['release'])) {
+ $this->_invalidVersion('release', $this->_packageInfo['version']['release']);
+ }
+ if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
+ $this->_packageInfo['version']['api'])) {
+ $this->_invalidVersion('api', $this->_packageInfo['version']['api']);
+ }
+ if (!in_array($this->_packageInfo['stability']['release'],
+ array('snapshot', 'devel', 'alpha', 'beta', 'stable'))) {
+ $this->_invalidState('release', $this->_packageInfo['stability']['release']);
+ }
+ if (!in_array($this->_packageInfo['stability']['api'],
+ array('devel', 'alpha', 'beta', 'stable'))) {
+ $this->_invalidState('api', $this->_packageInfo['stability']['api']);
+ }
+ }
+ }
+
+ function _validateMaintainers()
+ {
+ $structure =
+ array(
+ 'name',
+ 'user',
+ 'email',
+ 'active',
+ );
+ foreach (array('lead', 'developer', 'contributor', 'helper') as $type) {
+ if (!isset($this->_packageInfo[$type])) {
+ continue;
+ }
+ if (isset($this->_packageInfo[$type][0])) {
+ foreach ($this->_packageInfo[$type] as $lead) {
+ $this->_stupidSchemaValidate($structure, $lead, '<' . $type . '>');
+ }
+ } else {
+ $this->_stupidSchemaValidate($structure, $this->_packageInfo[$type],
+ '<' . $type . '>');
+ }
+ }
+ }
+
+ function _validatePhpDep($dep, $installcondition = false)
+ {
+ $structure = array(
+ 'min',
+ '*max',
+ '*exclude',
+ );
+ $type = $installcondition ? '' : '';
+ $this->_stupidSchemaValidate($structure, $dep, $type);
+ if (isset($dep['min'])) {
+ if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/',
+ $dep['min'])) {
+ $this->_invalidVersion($type . '', $dep['min']);
+ }
+ }
+ if (isset($dep['max'])) {
+ if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/',
+ $dep['max'])) {
+ $this->_invalidVersion($type . '', $dep['max']);
+ }
+ }
+ if (isset($dep['exclude'])) {
+ if (!is_array($dep['exclude'])) {
+ $dep['exclude'] = array($dep['exclude']);
+ }
+ foreach ($dep['exclude'] as $exclude) {
+ if (!preg_match(
+ '/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/',
+ $exclude)) {
+ $this->_invalidVersion($type . '', $exclude);
+ }
+ }
+ }
+ }
+
+ function _validatePearinstallerDep($dep)
+ {
+ $structure = array(
+ 'min',
+ '*max',
+ '*recommended',
+ '*exclude',
+ );
+ $this->_stupidSchemaValidate($structure, $dep, '');
+ if (isset($dep['min'])) {
+ if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
+ $dep['min'])) {
+ $this->_invalidVersion('',
+ $dep['min']);
+ }
+ }
+ if (isset($dep['max'])) {
+ if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
+ $dep['max'])) {
+ $this->_invalidVersion('',
+ $dep['max']);
+ }
+ }
+ if (isset($dep['recommended'])) {
+ if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
+ $dep['recommended'])) {
+ $this->_invalidVersion('',
+ $dep['recommended']);
+ }
+ }
+ if (isset($dep['exclude'])) {
+ if (!is_array($dep['exclude'])) {
+ $dep['exclude'] = array($dep['exclude']);
+ }
+ foreach ($dep['exclude'] as $exclude) {
+ if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
+ $exclude)) {
+ $this->_invalidVersion('',
+ $exclude);
+ }
+ }
+ }
+ }
+
+ function _validatePackageDep($dep, $group, $type = '')
+ {
+ if (isset($dep['uri'])) {
+ if (isset($dep['conflicts'])) {
+ $structure = array(
+ 'name',
+ 'uri',
+ 'conflicts',
+ '*providesextension',
+ );
+ } else {
+ $structure = array(
+ 'name',
+ 'uri',
+ '*providesextension',
+ );
+ }
+ } else {
+ if (isset($dep['conflicts'])) {
+ $structure = array(
+ 'name',
+ 'channel',
+ '*min',
+ '*max',
+ '*exclude',
+ 'conflicts',
+ '*providesextension',
+ );
+ } else {
+ $structure = array(
+ 'name',
+ 'channel',
+ '*min',
+ '*max',
+ '*recommended',
+ '*exclude',
+ '*nodefault',
+ '*providesextension',
+ );
+ }
+ }
+ if (isset($dep['name'])) {
+ $type .= '' . $dep['name'] . ' ';
+ }
+ $this->_stupidSchemaValidate($structure, $dep, '' . $group . $type);
+ if (isset($dep['uri']) && (isset($dep['min']) || isset($dep['max']) ||
+ isset($dep['recommended']) || isset($dep['exclude']))) {
+ $this->_uriDepsCannotHaveVersioning('' . $group . $type);
+ }
+ if (isset($dep['channel']) && strtolower($dep['channel']) == '__uri') {
+ $this->_DepchannelCannotBeUri('' . $group . $type);
+ }
+ if (isset($dep['min'])) {
+ if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
+ $dep['min'])) {
+ $this->_invalidVersion('' . $group . $type . '', $dep['min']);
+ }
+ }
+ if (isset($dep['max'])) {
+ if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
+ $dep['max'])) {
+ $this->_invalidVersion('' . $group . $type . '', $dep['max']);
+ }
+ }
+ if (isset($dep['recommended'])) {
+ if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
+ $dep['recommended'])) {
+ $this->_invalidVersion('' . $group . $type . '',
+ $dep['recommended']);
+ }
+ }
+ if (isset($dep['exclude'])) {
+ if (!is_array($dep['exclude'])) {
+ $dep['exclude'] = array($dep['exclude']);
+ }
+ foreach ($dep['exclude'] as $exclude) {
+ if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
+ $exclude)) {
+ $this->_invalidVersion('' . $group . $type . '',
+ $exclude);
+ }
+ }
+ }
+ }
+
+ function _validateSubpackageDep($dep, $group)
+ {
+ $this->_validatePackageDep($dep, $group, '');
+ if (isset($dep['providesextension'])) {
+ $this->_subpackageCannotProvideExtension(isset($dep['name']) ? $dep['name'] : '');
+ }
+ if (isset($dep['conflicts'])) {
+ $this->_subpackagesCannotConflict(isset($dep['name']) ? $dep['name'] : '');
+ }
+ }
+
+ function _validateExtensionDep($dep, $group = false, $installcondition = false)
+ {
+ if (isset($dep['conflicts'])) {
+ $structure = array(
+ 'name',
+ '*min',
+ '*max',
+ '*exclude',
+ 'conflicts',
+ );
+ } else {
+ $structure = array(
+ 'name',
+ '*min',
+ '*max',
+ '*recommended',
+ '*exclude',
+ );
+ }
+ if ($installcondition) {
+ $type = '';
+ } else {
+ $type = '' . $group . '';
+ }
+ if (isset($dep['name'])) {
+ $type .= '' . $dep['name'] . ' ';
+ }
+ $this->_stupidSchemaValidate($structure, $dep, $type);
+ if (isset($dep['min'])) {
+ if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
+ $dep['min'])) {
+ $this->_invalidVersion(substr($type, 1) . '_invalidVersion(substr($type, 1) . '_invalidVersion(substr($type, 1) . '_invalidVersion(substr($type, 1) . '' : '';
+ if ($this->_stupidSchemaValidate($structure, $dep, $type)) {
+ if ($dep['name'] == '*') {
+ if (array_key_exists('conflicts', $dep)) {
+ $this->_cannotConflictWithAllOs($type);
+ }
+ }
+ }
+ }
+
+ function _validateArchDep($dep, $installcondition = false)
+ {
+ $structure = array(
+ 'pattern',
+ '*conflicts',
+ );
+ $type = $installcondition ? '' : '';
+ $this->_stupidSchemaValidate($structure, $dep, $type);
+ }
+
+ function _validateInstallConditions($cond, $release)
+ {
+ $structure = array(
+ '*php',
+ '*extension',
+ '*os',
+ '*arch',
+ );
+ if (!$this->_stupidSchemaValidate($structure,
+ $cond, $release)) {
+ return false;
+ }
+ foreach (array('php', 'extension', 'os', 'arch') as $type) {
+ if (isset($cond[$type])) {
+ $iter = $cond[$type];
+ if (!is_array($iter) || !isset($iter[0])) {
+ $iter = array($iter);
+ }
+ foreach ($iter as $package) {
+ if ($type == 'extension') {
+ $this->{"_validate{$type}Dep"}($package, false, true);
+ } else {
+ $this->{"_validate{$type}Dep"}($package, true);
+ }
+ }
+ }
+ }
+ }
+
+ function _validateDependencies()
+ {
+ $structure = array(
+ 'required',
+ '*optional',
+ '*group->name->hint'
+ );
+ if (!$this->_stupidSchemaValidate($structure,
+ $this->_packageInfo['dependencies'], '')) {
+ return false;
+ }
+ foreach (array('required', 'optional') as $simpledep) {
+ if (isset($this->_packageInfo['dependencies'][$simpledep])) {
+ if ($simpledep == 'optional') {
+ $structure = array(
+ '*package',
+ '*subpackage',
+ '*extension',
+ );
+ } else {
+ $structure = array(
+ 'php',
+ 'pearinstaller',
+ '*package',
+ '*subpackage',
+ '*extension',
+ '*os',
+ '*arch',
+ );
+ }
+ if ($this->_stupidSchemaValidate($structure,
+ $this->_packageInfo['dependencies'][$simpledep],
+ "<$simpledep>")) {
+ foreach (array('package', 'subpackage', 'extension') as $type) {
+ if (isset($this->_packageInfo['dependencies'][$simpledep][$type])) {
+ $iter = $this->_packageInfo['dependencies'][$simpledep][$type];
+ if (!isset($iter[0])) {
+ $iter = array($iter);
+ }
+ foreach ($iter as $package) {
+ if ($type != 'extension') {
+ if (isset($package['uri'])) {
+ if (isset($package['channel'])) {
+ $this->_UrlOrChannel($type,
+ $package['name']);
+ }
+ } else {
+ if (!isset($package['channel'])) {
+ $this->_NoChannel($type, $package['name']);
+ }
+ }
+ }
+ $this->{"_validate{$type}Dep"}($package, "<$simpledep>");
+ }
+ }
+ }
+ if ($simpledep == 'optional') {
+ continue;
+ }
+ foreach (array('php', 'pearinstaller', 'os', 'arch') as $type) {
+ if (isset($this->_packageInfo['dependencies'][$simpledep][$type])) {
+ $iter = $this->_packageInfo['dependencies'][$simpledep][$type];
+ if (!isset($iter[0])) {
+ $iter = array($iter);
+ }
+ foreach ($iter as $package) {
+ $this->{"_validate{$type}Dep"}($package);
+ }
+ }
+ }
+ }
+ }
+ }
+ if (isset($this->_packageInfo['dependencies']['group'])) {
+ $groups = $this->_packageInfo['dependencies']['group'];
+ if (!isset($groups[0])) {
+ $groups = array($groups);
+ }
+ $structure = array(
+ '*package',
+ '*subpackage',
+ '*extension',
+ );
+ foreach ($groups as $group) {
+ if ($this->_stupidSchemaValidate($structure, $group, '')) {
+ if (!PEAR_Validate::validGroupName($group['attribs']['name'])) {
+ $this->_invalidDepGroupName($group['attribs']['name']);
+ }
+ foreach (array('package', 'subpackage', 'extension') as $type) {
+ if (isset($group[$type])) {
+ $iter = $group[$type];
+ if (!isset($iter[0])) {
+ $iter = array($iter);
+ }
+ foreach ($iter as $package) {
+ if ($type != 'extension') {
+ if (isset($package['uri'])) {
+ if (isset($package['channel'])) {
+ $this->_UrlOrChannelGroup($type,
+ $package['name'],
+ $group['name']);
+ }
+ } else {
+ if (!isset($package['channel'])) {
+ $this->_NoChannelGroup($type,
+ $package['name'],
+ $group['name']);
+ }
+ }
+ }
+ $this->{"_validate{$type}Dep"}($package, '');
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ function _validateCompatible()
+ {
+ $compat = $this->_packageInfo['compatible'];
+ if (!isset($compat[0])) {
+ $compat = array($compat);
+ }
+ $required = array('name', 'channel', 'min', 'max', '*exclude');
+ foreach ($compat as $package) {
+ $type = '';
+ if (is_array($package) && array_key_exists('name', $package)) {
+ $type .= '' . $package['name'] . ' ';
+ }
+ $this->_stupidSchemaValidate($required, $package, $type);
+ if (is_array($package) && array_key_exists('min', $package)) {
+ if (!preg_match('/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/',
+ $package['min'])) {
+ $this->_invalidVersion(substr($type, 1) . '_invalidVersion(substr($type, 1) . '_invalidVersion(substr($type, 1) . '_NoBundledPackages();
+ }
+ if (!is_array($list['bundledpackage']) || !isset($list['bundledpackage'][0])) {
+ return $this->_AtLeast2BundledPackages();
+ }
+ foreach ($list['bundledpackage'] as $package) {
+ if (!is_string($package)) {
+ $this->_bundledPackagesMustBeFilename();
+ }
+ }
+ }
+
+ function _validateFilelist($list = false, $allowignore = false, $dirs = '')
+ {
+ $iscontents = false;
+ if (!$list) {
+ $iscontents = true;
+ $list = $this->_packageInfo['contents'];
+ if (isset($this->_packageInfo['bundle'])) {
+ return $this->_validateBundle($list);
+ }
+ }
+ if ($allowignore) {
+ $struc = array(
+ '*install->name->as',
+ '*ignore->name'
+ );
+ } else {
+ $struc = array(
+ '*dir->name->?baseinstalldir',
+ '*file->name->role->?baseinstalldir->?md5sum'
+ );
+ if (isset($list['dir']) && isset($list['file'])) {
+ // stave off validation errors without requiring a set order.
+ $_old = $list;
+ if (isset($list['attribs'])) {
+ $list = array('attribs' => $_old['attribs']);
+ }
+ $list['dir'] = $_old['dir'];
+ $list['file'] = $_old['file'];
+ }
+ }
+ if (!isset($list['attribs']) || !isset($list['attribs']['name'])) {
+ $unknown = $allowignore ? '' : '';
+ $dirname = $iscontents ? '' : $unknown;
+ } else {
+ $dirname = '';
+ if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~',
+ str_replace('\\', '/', $list['attribs']['name']))) {
+ // file contains .. parent directory or . cur directory
+ $this->_invalidDirName($list['attribs']['name']);
+ }
+ }
+ $res = $this->_stupidSchemaValidate($struc, $list, $dirname);
+ if ($allowignore && $res) {
+ $ignored_or_installed = array();
+ $this->_pf->getFilelist();
+ $fcontents = $this->_pf->getContents();
+ $filelist = array();
+ if (!isset($fcontents['dir']['file'][0])) {
+ $fcontents['dir']['file'] = array($fcontents['dir']['file']);
+ }
+ foreach ($fcontents['dir']['file'] as $file) {
+ $filelist[$file['attribs']['name']] = true;
+ }
+ if (isset($list['install'])) {
+ if (!isset($list['install'][0])) {
+ $list['install'] = array($list['install']);
+ }
+ foreach ($list['install'] as $file) {
+ if (!isset($filelist[$file['attribs']['name']])) {
+ $this->_notInContents($file['attribs']['name'], 'install');
+ continue;
+ }
+ if (array_key_exists($file['attribs']['name'], $ignored_or_installed)) {
+ $this->_multipleInstallAs($file['attribs']['name']);
+ }
+ if (!isset($ignored_or_installed[$file['attribs']['name']])) {
+ $ignored_or_installed[$file['attribs']['name']] = array();
+ }
+ $ignored_or_installed[$file['attribs']['name']][] = 1;
+ if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~',
+ str_replace('\\', '/', $file['attribs']['as']))) {
+ // file contains .. parent directory or . cur directory references
+ $this->_invalidFileInstallAs($file['attribs']['name'],
+ $file['attribs']['as']);
+ }
+ }
+ }
+ if (isset($list['ignore'])) {
+ if (!isset($list['ignore'][0])) {
+ $list['ignore'] = array($list['ignore']);
+ }
+ foreach ($list['ignore'] as $file) {
+ if (!isset($filelist[$file['attribs']['name']])) {
+ $this->_notInContents($file['attribs']['name'], 'ignore');
+ continue;
+ }
+ if (array_key_exists($file['attribs']['name'], $ignored_or_installed)) {
+ $this->_ignoreAndInstallAs($file['attribs']['name']);
+ }
+ }
+ }
+ }
+ if (!$allowignore && isset($list['file'])) {
+ if (is_string($list['file'])) {
+ $this->_oldStyleFileNotAllowed();
+ return false;
+ }
+ if (!isset($list['file'][0])) {
+ // single file
+ $list['file'] = array($list['file']);
+ }
+ foreach ($list['file'] as $i => $file)
+ {
+ if (isset($file['attribs']) && isset($file['attribs']['name'])) {
+ if ($file['attribs']['name']{0} == '.' &&
+ $file['attribs']['name']{1} == '/') {
+ // name is something like "./doc/whatever.txt"
+ $this->_invalidFileName($file['attribs']['name'], $dirname);
+ }
+ if (preg_match('~/\.\.?(/|\\z)|^\.\.?/~',
+ str_replace('\\', '/', $file['attribs']['name']))) {
+ // file contains .. parent directory or . cur directory
+ $this->_invalidFileName($file['attribs']['name'], $dirname);
+ }
+ }
+ if (isset($file['attribs']) && isset($file['attribs']['role'])) {
+ if (!$this->_validateRole($file['attribs']['role'])) {
+ if (isset($this->_packageInfo['usesrole'])) {
+ $roles = $this->_packageInfo['usesrole'];
+ if (!isset($roles[0])) {
+ $roles = array($roles);
+ }
+ foreach ($roles as $role) {
+ if ($role['role'] = $file['attribs']['role']) {
+ $msg = 'This package contains role "%role%" and requires ' .
+ 'package "%package%" to be used';
+ if (isset($role['uri'])) {
+ $params = array('role' => $role['role'],
+ 'package' => $role['uri']);
+ } else {
+ $params = array('role' => $role['role'],
+ 'package' => $this->_pf->_registry->
+ parsedPackageNameToString(array('package' =>
+ $role['package'], 'channel' => $role['channel']),
+ true));
+ }
+ $this->_stack->push('_mustInstallRole', 'error', $params, $msg);
+ }
+ }
+ }
+ $this->_invalidFileRole($file['attribs']['name'],
+ $dirname, $file['attribs']['role']);
+ }
+ }
+ if (!isset($file['attribs'])) {
+ continue;
+ }
+ $save = $file['attribs'];
+ if ($dirs) {
+ $save['name'] = $dirs . '/' . $save['name'];
+ }
+ unset($file['attribs']);
+ if (count($file) && $this->_curState != PEAR_VALIDATE_DOWNLOADING) { // has tasks
+ foreach ($file as $task => $value) {
+ if ($tagClass = $this->_pf->getTask($task)) {
+ if (!is_array($value) || !isset($value[0])) {
+ $value = array($value);
+ }
+ foreach ($value as $v) {
+ $ret = call_user_func(array($tagClass, 'validateXml'),
+ $this->_pf, $v, $this->_pf->_config, $save);
+ if (is_array($ret)) {
+ $this->_invalidTask($task, $ret, isset($save['name']) ?
+ $save['name'] : '');
+ }
+ }
+ } else {
+ if (isset($this->_packageInfo['usestask'])) {
+ $roles = $this->_packageInfo['usestask'];
+ if (!isset($roles[0])) {
+ $roles = array($roles);
+ }
+ foreach ($roles as $role) {
+ if ($role['task'] = $task) {
+ $msg = 'This package contains task "%task%" and requires ' .
+ 'package "%package%" to be used';
+ if (isset($role['uri'])) {
+ $params = array('task' => $role['task'],
+ 'package' => $role['uri']);
+ } else {
+ $params = array('task' => $role['task'],
+ 'package' => $this->_pf->_registry->
+ parsedPackageNameToString(array('package' =>
+ $role['package'], 'channel' => $role['channel']),
+ true));
+ }
+ $this->_stack->push('_mustInstallTask', 'error',
+ $params, $msg);
+ }
+ }
+ }
+ $this->_unknownTask($task, $save['name']);
+ }
+ }
+ }
+ }
+ }
+ if (isset($list['ignore'])) {
+ if (!$allowignore) {
+ $this->_ignoreNotAllowed('ignore');
+ }
+ }
+ if (isset($list['install'])) {
+ if (!$allowignore) {
+ $this->_ignoreNotAllowed('install');
+ }
+ }
+ if (isset($list['file'])) {
+ if ($allowignore) {
+ $this->_fileNotAllowed('file');
+ }
+ }
+ if (isset($list['dir'])) {
+ if ($allowignore) {
+ $this->_fileNotAllowed('dir');
+ } else {
+ if (!isset($list['dir'][0])) {
+ $list['dir'] = array($list['dir']);
+ }
+ foreach ($list['dir'] as $dir) {
+ if (isset($dir['attribs']) && isset($dir['attribs']['name'])) {
+ if ($dir['attribs']['name'] == '/' ||
+ !isset($this->_packageInfo['contents']['dir']['dir'])) {
+ // always use nothing if the filelist has already been flattened
+ $newdirs = '';
+ } elseif ($dirs == '') {
+ $newdirs = $dir['attribs']['name'];
+ } else {
+ $newdirs = $dirs . '/' . $dir['attribs']['name'];
+ }
+ } else {
+ $newdirs = $dirs;
+ }
+ $this->_validateFilelist($dir, $allowignore, $newdirs);
+ }
+ }
+ }
+ }
+
+ function _validateRelease()
+ {
+ if (isset($this->_packageInfo['phprelease'])) {
+ $release = 'phprelease';
+ if (isset($this->_packageInfo['providesextension'])) {
+ $this->_cannotProvideExtension($release);
+ }
+ if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) {
+ $this->_cannotHaveSrcpackage($release);
+ }
+ $releases = $this->_packageInfo['phprelease'];
+ if (!is_array($releases)) {
+ return true;
+ }
+ if (!isset($releases[0])) {
+ $releases = array($releases);
+ }
+ foreach ($releases as $rel) {
+ $this->_stupidSchemaValidate(array(
+ '*installconditions',
+ '*filelist',
+ ), $rel, '');
+ }
+ }
+ foreach (array('', 'zend') as $prefix) {
+ $releasetype = $prefix . 'extsrcrelease';
+ if (isset($this->_packageInfo[$releasetype])) {
+ $release = $releasetype;
+ if (!isset($this->_packageInfo['providesextension'])) {
+ $this->_mustProvideExtension($release);
+ }
+ if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) {
+ $this->_cannotHaveSrcpackage($release);
+ }
+ $releases = $this->_packageInfo[$releasetype];
+ if (!is_array($releases)) {
+ return true;
+ }
+ if (!isset($releases[0])) {
+ $releases = array($releases);
+ }
+ foreach ($releases as $rel) {
+ $this->_stupidSchemaValidate(array(
+ '*installconditions',
+ '*configureoption->name->prompt->?default',
+ '*binarypackage',
+ '*filelist',
+ ), $rel, '<' . $releasetype . '>');
+ if (isset($rel['binarypackage'])) {
+ if (!is_array($rel['binarypackage']) || !isset($rel['binarypackage'][0])) {
+ $rel['binarypackage'] = array($rel['binarypackage']);
+ }
+ foreach ($rel['binarypackage'] as $bin) {
+ if (!is_string($bin)) {
+ $this->_binaryPackageMustBePackagename();
+ }
+ }
+ }
+ }
+ }
+ $releasetype = 'extbinrelease';
+ if (isset($this->_packageInfo[$releasetype])) {
+ $release = $releasetype;
+ if (!isset($this->_packageInfo['providesextension'])) {
+ $this->_mustProvideExtension($release);
+ }
+ if (isset($this->_packageInfo['channel']) &&
+ !isset($this->_packageInfo['srcpackage'])) {
+ $this->_mustSrcPackage($release);
+ }
+ if (isset($this->_packageInfo['uri']) && !isset($this->_packageInfo['srcuri'])) {
+ $this->_mustSrcuri($release);
+ }
+ $releases = $this->_packageInfo[$releasetype];
+ if (!is_array($releases)) {
+ return true;
+ }
+ if (!isset($releases[0])) {
+ $releases = array($releases);
+ }
+ foreach ($releases as $rel) {
+ $this->_stupidSchemaValidate(array(
+ '*installconditions',
+ '*filelist',
+ ), $rel, '<' . $releasetype . '>');
+ }
+ }
+ }
+ if (isset($this->_packageInfo['bundle'])) {
+ $release = 'bundle';
+ if (isset($this->_packageInfo['providesextension'])) {
+ $this->_cannotProvideExtension($release);
+ }
+ if (isset($this->_packageInfo['srcpackage']) || isset($this->_packageInfo['srcuri'])) {
+ $this->_cannotHaveSrcpackage($release);
+ }
+ $releases = $this->_packageInfo['bundle'];
+ if (!is_array($releases) || !isset($releases[0])) {
+ $releases = array($releases);
+ }
+ foreach ($releases as $rel) {
+ $this->_stupidSchemaValidate(array(
+ '*installconditions',
+ '*filelist',
+ ), $rel, '');
+ }
+ }
+ foreach ($releases as $rel) {
+ if (is_array($rel) && array_key_exists('installconditions', $rel)) {
+ $this->_validateInstallConditions($rel['installconditions'],
+ "<$release>");
+ }
+ if (is_array($rel) && array_key_exists('filelist', $rel)) {
+ if ($rel['filelist']) {
+
+ $this->_validateFilelist($rel['filelist'], true);
+ }
+ }
+ }
+ }
+
+ /**
+ * This is here to allow role extension through plugins
+ * @param string
+ */
+ function _validateRole($role)
+ {
+ return in_array($role, PEAR_Installer_Role::getValidRoles($this->_pf->getPackageType()));
+ }
+
+ function _pearVersionTooLow($version)
+ {
+ $this->_stack->push(__FUNCTION__, 'error',
+ array('version' => $version),
+ 'This package.xml requires PEAR version %version% to parse properly, we are ' .
+ 'version 1.10.3');
+ }
+
+ function _invalidTagOrder($oktags, $actual, $root)
+ {
+ $this->_stack->push(__FUNCTION__, 'error',
+ array('oktags' => $oktags, 'actual' => $actual, 'root' => $root),
+ 'Invalid tag order in %root%, found <%actual%> expected one of "%oktags%"');
+ }
+
+ function _ignoreNotAllowed($type)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('type' => $type),
+ '<%type%> is not allowed inside global , only inside ' .
+ '//, use and only');
+ }
+
+ function _fileNotAllowed($type)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('type' => $type),
+ '<%type%> is not allowed inside release , only inside ' .
+ ', use and only');
+ }
+
+ function _oldStyleFileNotAllowed()
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array(),
+ 'Old-style name is not allowed. Use' .
+ ' ');
+ }
+
+ function _tagMissingAttribute($tag, $attr, $context)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag,
+ 'attribute' => $attr, 'context' => $context),
+ 'tag <%tag%> in context "%context%" has no attribute "%attribute%"');
+ }
+
+ function _tagHasNoAttribs($tag, $context)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag,
+ 'context' => $context),
+ 'tag <%tag%> has no attributes in context "%context%"');
+ }
+
+ function _invalidInternalStructure()
+ {
+ $this->_stack->push(__FUNCTION__, 'exception', array(),
+ 'internal array was not generated by compatible parser, or extreme parser error, cannot continue');
+ }
+
+ function _invalidFileRole($file, $dir, $role)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array(
+ 'file' => $file, 'dir' => $dir, 'role' => $role,
+ 'roles' => PEAR_Installer_Role::getValidRoles($this->_pf->getPackageType())),
+ 'File "%file%" in directory "%dir%" has invalid role "%role%", should be one of %roles%');
+ }
+
+ function _invalidFileName($file, $dir)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array(
+ 'file' => $file),
+ 'File "%file%" in directory "%dir%" cannot begin with "./" or contain ".."');
+ }
+
+ function _invalidFileInstallAs($file, $as)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array(
+ 'file' => $file, 'as' => $as),
+ 'File "%file%" cannot contain "./" or contain ".."');
+ }
+
+ function _invalidDirName($dir)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array(
+ 'dir' => $file),
+ 'Directory "%dir%" cannot begin with "./" or contain ".."');
+ }
+
+ function _filelistCannotContainFile($filelist)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('tag' => $filelist),
+ '<%tag%> can only contain , contains . Use ' .
+ ' as the first dir element');
+ }
+
+ function _filelistMustContainDir($filelist)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('tag' => $filelist),
+ '<%tag%> must contain . Use as the ' .
+ 'first dir element');
+ }
+
+ function _tagCannotBeEmpty($tag)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag),
+ '<%tag%> cannot be empty (<%tag%/>)');
+ }
+
+ function _UrlOrChannel($type, $name)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('type' => $type,
+ 'name' => $name),
+ 'Required dependency <%type%> "%name%" can have either url OR ' .
+ 'channel attributes, and not both');
+ }
+
+ function _NoChannel($type, $name)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('type' => $type,
+ 'name' => $name),
+ 'Required dependency <%type%> "%name%" must have either url OR ' .
+ 'channel attributes');
+ }
+
+ function _UrlOrChannelGroup($type, $name, $group)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('type' => $type,
+ 'name' => $name, 'group' => $group),
+ 'Group "%group%" dependency <%type%> "%name%" can have either url OR ' .
+ 'channel attributes, and not both');
+ }
+
+ function _NoChannelGroup($type, $name, $group)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('type' => $type,
+ 'name' => $name, 'group' => $group),
+ 'Group "%group%" dependency <%type%> "%name%" must have either url OR ' .
+ 'channel attributes');
+ }
+
+ function _unknownChannel($channel)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('channel' => $channel),
+ 'Unknown channel "%channel%"');
+ }
+
+ function _noPackageVersion()
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array(),
+ 'package.xml tag has no version attribute, or version is not 2.0');
+ }
+
+ function _NoBundledPackages()
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array(),
+ 'No tag was found in , required for bundle packages');
+ }
+
+ function _AtLeast2BundledPackages()
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array(),
+ 'At least 2 packages must be bundled in a bundle package');
+ }
+
+ function _ChannelOrUri($name)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('name' => $name),
+ 'Bundled package "%name%" can have either a uri or a channel, not both');
+ }
+
+ function _noChildTag($child, $tag)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('child' => $child, 'tag' => $tag),
+ 'Tag <%tag%> is missing child tag <%child%>');
+ }
+
+ function _invalidVersion($type, $value)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, 'value' => $value),
+ 'Version type <%type%> is not a valid version (%value%)');
+ }
+
+ function _invalidState($type, $value)
+ {
+ $states = array('stable', 'beta', 'alpha', 'devel');
+ if ($type != 'api') {
+ $states[] = 'snapshot';
+ }
+ if (strtolower($value) == 'rc') {
+ $this->_stack->push(__FUNCTION__, 'error',
+ array('version' => $this->_packageInfo['version']['release']),
+ 'RC is not a state, it is a version postfix, try %version%RC1, stability beta');
+ }
+ $this->_stack->push(__FUNCTION__, 'error', array('type' => $type, 'value' => $value,
+ 'types' => $states),
+ 'Stability type <%type%> is not a valid stability (%value%), must be one of ' .
+ '%types%');
+ }
+
+ function _invalidTask($task, $ret, $file)
+ {
+ switch ($ret[0]) {
+ case PEAR_TASK_ERROR_MISSING_ATTRIB :
+ $info = array('attrib' => $ret[1], 'task' => $task, 'file' => $file);
+ $msg = 'task <%task%> is missing attribute "%attrib%" in file %file%';
+ break;
+ case PEAR_TASK_ERROR_NOATTRIBS :
+ $info = array('task' => $task, 'file' => $file);
+ $msg = 'task <%task%> has no attributes in file %file%';
+ break;
+ case PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE :
+ $info = array('attrib' => $ret[1], 'values' => $ret[3],
+ 'was' => $ret[2], 'task' => $task, 'file' => $file);
+ $msg = 'task <%task%> attribute "%attrib%" has the wrong value "%was%" '.
+ 'in file %file%, expecting one of "%values%"';
+ break;
+ case PEAR_TASK_ERROR_INVALID :
+ $info = array('reason' => $ret[1], 'task' => $task, 'file' => $file);
+ $msg = 'task <%task%> in file %file% is invalid because of "%reason%"';
+ break;
+ }
+ $this->_stack->push(__FUNCTION__, 'error', $info, $msg);
+ }
+
+ function _unknownTask($task, $file)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('task' => $task, 'file' => $file),
+ 'Unknown task "%task%" passed in file ');
+ }
+
+ function _subpackageCannotProvideExtension($name)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('name' => $name),
+ 'Subpackage dependency "%name%" cannot use , ' .
+ 'only package dependencies can use this tag');
+ }
+
+ function _subpackagesCannotConflict($name)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('name' => $name),
+ 'Subpackage dependency "%name%" cannot use , ' .
+ 'only package dependencies can use this tag');
+ }
+
+ function _cannotProvideExtension($release)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('release' => $release),
+ '<%release%> packages cannot use , only extbinrelease, extsrcrelease, zendextsrcrelease, and zendextbinrelease can provide a PHP extension');
+ }
+
+ function _mustProvideExtension($release)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('release' => $release),
+ '<%release%> packages must use to indicate which PHP extension is provided');
+ }
+
+ function _cannotHaveSrcpackage($release)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('release' => $release),
+ '<%release%> packages cannot specify a source code package, only extension binaries may use the tag');
+ }
+
+ function _mustSrcPackage($release)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('release' => $release),
+ '/ packages must specify a source code package with ');
+ }
+
+ function _mustSrcuri($release)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('release' => $release),
+ '/ packages must specify a source code package with ');
+ }
+
+ function _uriDepsCannotHaveVersioning($type)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('type' => $type),
+ '%type%: dependencies with a tag cannot have any versioning information');
+ }
+
+ function _conflictingDepsCannotHaveVersioning($type)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('type' => $type),
+ '%type%: conflicting dependencies cannot have versioning info, use to ' .
+ 'exclude specific versions of a dependency');
+ }
+
+ function _DepchannelCannotBeUri($type)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('type' => $type),
+ '%type%: channel cannot be __uri, this is a pseudo-channel reserved for uri ' .
+ 'dependencies only');
+ }
+
+ function _bundledPackagesMustBeFilename()
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array(),
+ ' tags must contain only the filename of a package release ' .
+ 'in the bundle');
+ }
+
+ function _binaryPackageMustBePackagename()
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array(),
+ ' tags must contain the name of a package that is ' .
+ 'a compiled version of this extsrc/zendextsrc package');
+ }
+
+ function _fileNotFound($file)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('file' => $file),
+ 'File "%file%" in package.xml does not exist');
+ }
+
+ function _notInContents($file, $tag)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('file' => $file, 'tag' => $tag),
+ '<%tag% name="%file%"> is invalid, file is not in ');
+ }
+
+ function _cannotValidateNoPathSet()
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array(),
+ 'Cannot validate files, no path to package file is set (use setPackageFile())');
+ }
+
+ function _usesroletaskMustHaveChannelOrUri($role, $tag)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('role' => $role, 'tag' => $tag),
+ '<%tag%> for role "%role%" must contain either , or and ');
+ }
+
+ function _usesroletaskMustHavePackage($role, $tag)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('role' => $role, 'tag' => $tag),
+ '<%tag%> for role "%role%" must contain ');
+ }
+
+ function _usesroletaskMustHaveRoleTask($tag, $type)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag, 'type' => $type),
+ '<%tag%> must contain <%type%> defining the %type% to be used');
+ }
+
+ function _cannotConflictWithAllOs($type)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('tag' => $tag),
+ '%tag% cannot conflict with all OSes');
+ }
+
+ function _invalidDepGroupName($name)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('name' => $name),
+ 'Invalid dependency group name "%name%"');
+ }
+
+ function _multipleToplevelDirNotAllowed()
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array(),
+ 'Multiple top-level tags are not allowed. Enclose them ' .
+ 'in a ');
+ }
+
+ function _multipleInstallAs($file)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('file' => $file),
+ 'Only one tag is allowed for file "%file%"');
+ }
+
+ function _ignoreAndInstallAs($file)
+ {
+ $this->_stack->push(__FUNCTION__, 'error', array('file' => $file),
+ 'Cannot have both and tags for file "%file%"');
+ }
+
+ function _analyzeBundledPackages()
+ {
+ if (!$this->_isValid) {
+ return false;
+ }
+ if (!$this->_pf->getPackageType() == 'bundle') {
+ return false;
+ }
+ if (!isset($this->_pf->_packageFile)) {
+ return false;
+ }
+ $dir_prefix = dirname($this->_pf->_packageFile);
+ $common = new PEAR_Common;
+ $log = isset($this->_pf->_logger) ? array(&$this->_pf->_logger, 'log') :
+ array($common, 'log');
+ $info = $this->_pf->getContents();
+ $info = $info['bundledpackage'];
+ if (!is_array($info)) {
+ $info = array($info);
+ }
+ $pkg = new PEAR_PackageFile($this->_pf->_config);
+ foreach ($info as $package) {
+ if (!file_exists($dir_prefix . DIRECTORY_SEPARATOR . $package)) {
+ $this->_fileNotFound($dir_prefix . DIRECTORY_SEPARATOR . $package);
+ $this->_isValid = 0;
+ continue;
+ }
+ call_user_func_array($log, array(1, "Analyzing bundled package $package"));
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ $ret = $pkg->fromAnyFile($dir_prefix . DIRECTORY_SEPARATOR . $package,
+ PEAR_VALIDATE_NORMAL);
+ PEAR::popErrorHandling();
+ if (PEAR::isError($ret)) {
+ call_user_func_array($log, array(0, "ERROR: package $package is not a valid " .
+ 'package'));
+ $inf = $ret->getUserInfo();
+ if (is_array($inf)) {
+ foreach ($inf as $err) {
+ call_user_func_array($log, array(1, $err['message']));
+ }
+ }
+ return false;
+ }
+ }
+ return true;
+ }
+
+ function _analyzePhpFiles()
+ {
+ if (!$this->_isValid) {
+ return false;
+ }
+ if (!isset($this->_pf->_packageFile)) {
+ $this->_cannotValidateNoPathSet();
+ return false;
+ }
+ $dir_prefix = dirname($this->_pf->_packageFile);
+ $common = new PEAR_Common;
+ $log = isset($this->_pf->_logger) ? array(&$this->_pf->_logger, 'log') :
+ array(&$common, 'log');
+ $info = $this->_pf->getContents();
+ if (!$info || !isset($info['dir']['file'])) {
+ $this->_tagCannotBeEmpty('contents>_fileNotFound($dir_prefix . DIRECTORY_SEPARATOR . $file);
+ $this->_isValid = 0;
+ continue;
+ }
+ if (in_array($fa['role'], PEAR_Installer_Role::getPhpRoles()) && $dir_prefix) {
+ call_user_func_array($log, array(1, "Analyzing $file"));
+ $srcinfo = $this->analyzeSourceCode($dir_prefix . DIRECTORY_SEPARATOR . $file);
+ if ($srcinfo) {
+ $provides = array_merge($provides, $this->_buildProvidesArray($srcinfo));
+ }
+ }
+ }
+ $this->_packageName = $pn = $this->_pf->getPackage();
+ $pnl = strlen($pn);
+ foreach ($provides as $key => $what) {
+ if (isset($what['explicit']) || !$what) {
+ // skip conformance checks if the provides entry is
+ // specified in the package.xml file
+ continue;
+ }
+ extract($what);
+ if ($type == 'class') {
+ if (!strncasecmp($name, $pn, $pnl)) {
+ continue;
+ }
+ $this->_stack->push(__FUNCTION__, 'warning',
+ array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn),
+ 'in %file%: %type% "%name%" not prefixed with package name "%package%"');
+ } elseif ($type == 'function') {
+ if (strstr($name, '::') || !strncasecmp($name, $pn, $pnl)) {
+ continue;
+ }
+ $this->_stack->push(__FUNCTION__, 'warning',
+ array('file' => $file, 'type' => $type, 'name' => $name, 'package' => $pn),
+ 'in %file%: %type% "%name%" not prefixed with package name "%package%"');
+ }
+ }
+ return $this->_isValid;
+ }
+
+ /**
+ * Analyze the source code of the given PHP file
+ *
+ * @param string Filename of the PHP file
+ * @param boolean whether to analyze $file as the file contents
+ * @return mixed
+ */
+ function analyzeSourceCode($file, $string = false)
+ {
+ if (!function_exists("token_get_all")) {
+ $this->_stack->push(__FUNCTION__, 'error', array('file' => $file),
+ 'Parser error: token_get_all() function must exist to analyze source code, PHP may have been compiled with --disable-tokenizer');
+ return false;
+ }
+
+ 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 ($string) {
+ $contents = $file;
+ } else {
+ if (!$fp = @fopen($file, "r")) {
+ return false;
+ }
+ fclose($fp);
+ $contents = file_get_contents($file);
+ }
+
+ // Silence this function so we can catch PHP Warnings and show our own custom message
+ $tokens = @token_get_all($contents);
+ if (isset($php_errormsg)) {
+ if (isset($this->_stack)) {
+ $pn = $this->_pf->getPackage();
+ $this->_stack->push(__FUNCTION__, 'warning',
+ array('file' => $file, 'package' => $pn),
+ 'in %file%: Could not process file for unknown reasons,' .
+ ' possibly a PHP parse error in %file% from %package%');
+ }
+ }
+/*
+ for ($i = 0; $i < sizeof($tokens); $i++) {
+ @list($token, $data) = $tokens[$i];
+ if (is_string($token)) {
+ var_dump($token);
+ } else {
+ print token_name($token) . ' ';
+ var_dump(rtrim($data));
+ }
+ }
+*/
+ $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)) {
+ if (isset($this->_stack)) {
+ $this->_stack->push(__FUNCTION__, 'error', array('file' => $file),
+ 'Parser error: invalid PHP found in file "%file%"');
+ } else {
+ PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"",
+ PEAR_COMMON_ERROR_INVALIDPHP);
+ }
+
+ return false;
+ }
+ case T_FUNCTION:
+ case T_NEW:
+ case T_EXTENDS:
+ case T_IMPLEMENTS:
+ $look_for = $token;
+ continue 2;
+ case T_STRING:
+ if ($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:
+ $token = $tokens[$i - 1][0];
+ if (!($token == T_WHITESPACE || $token == T_STRING || $token == T_STATIC || $token == T_VARIABLE)) {
+ if (isset($this->_stack)) {
+ $this->_stack->push(__FUNCTION__, 'warning', array('file' => $file),
+ 'Parser error: invalid PHP found in file "%file%"');
+ } else {
+ PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"",
+ PEAR_COMMON_ERROR_INVALIDPHP);
+ }
+
+ return false;
+ }
+
+ $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 array();
+ }
+
+ $providesret = array();
+ $file = basename($srcinfo['source_file']);
+ $pn = isset($this->_pf) ? $this->_pf->getPackage() : '';
+ $pnl = strlen($pn);
+ foreach ($srcinfo['declared_classes'] as $class) {
+ $key = "class;$class";
+ if (isset($providesret[$key])) {
+ continue;
+ }
+
+ $providesret[$key] =
+ array('file'=> $file, 'type' => 'class', 'name' => $class);
+ if (isset($srcinfo['inheritance'][$class])) {
+ $providesret[$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($providesret[$key])) {
+ continue;
+ }
+
+ $providesret[$key] =
+ array('file'=> $file, 'type' => 'function', 'name' => $function);
+ }
+ }
+
+ foreach ($srcinfo['declared_functions'] as $function) {
+ $key = "function;$function";
+ if ($function{0} == '_' || isset($providesret[$key])) {
+ continue;
+ }
+
+ if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) {
+ $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\"";
+ }
+
+ $providesret[$key] =
+ array('file'=> $file, 'type' => 'function', 'name' => $function);
+ }
+
+ return $providesret;
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/PackageFile/v2/rw.php b/vendor/pear-pear.php.net/PEAR/PEAR/PackageFile/v2/rw.php
new file mode 100644
index 000000000..c52ff4f3c
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/PackageFile/v2/rw.php
@@ -0,0 +1,1603 @@
+
+ * @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.0a8
+ */
+/**
+ * For base class
+ */
+require_once 'PEAR/PackageFile/v2.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.0a8
+ */
+class PEAR_PackageFile_v2_rw extends PEAR_PackageFile_v2
+{
+ /**
+ * @param string Extension name
+ * @return bool success of operation
+ */
+ function setProvidesExtension($extension)
+ {
+ if (in_array($this->getPackageType(),
+ array('extsrc', 'extbin', 'zendextsrc', 'zendextbin'))) {
+ if (!isset($this->_packageInfo['providesextension'])) {
+ // ensure that the channel tag is set up in the right location
+ $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
+ array('usesrole', 'usestask', 'srcpackage', 'srcuri', 'phprelease',
+ 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease', 'zendextbinrelease',
+ 'bundle', 'changelog'),
+ $extension, 'providesextension');
+ }
+ $this->_packageInfo['providesextension'] = $extension;
+ return true;
+ }
+ return false;
+ }
+
+ function setPackage($package)
+ {
+ $this->_isValid = 0;
+ if (!isset($this->_packageInfo['attribs'])) {
+ $this->_packageInfo = array_merge(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
+ 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',
+ )), $this->_packageInfo);
+ }
+ if (!isset($this->_packageInfo['name'])) {
+ return $this->_packageInfo = array_merge(array('name' => $package),
+ $this->_packageInfo);
+ }
+ $this->_packageInfo['name'] = $package;
+ }
+
+ /**
+ * set this as a package.xml version 2.1
+ * @access private
+ */
+ function _setPackageVersion2_1()
+ {
+ $info = array(
+ 'version' => '2.1',
+ 'xmlns' => 'http://pear.php.net/dtd/package-2.1',
+ '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.1
+ http://pear.php.net/dtd/package-2.1.xsd',
+ );
+ if (!isset($this->_packageInfo['attribs'])) {
+ $this->_packageInfo = array_merge(array('attribs' => $info), $this->_packageInfo);
+ } else {
+ $this->_packageInfo['attribs'] = $info;
+ }
+ }
+
+ function setUri($uri)
+ {
+ unset($this->_packageInfo['channel']);
+ $this->_isValid = 0;
+ if (!isset($this->_packageInfo['uri'])) {
+ // ensure that the uri tag is set up in the right location
+ $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
+ array('extends', 'summary', 'description', 'lead',
+ 'developer', 'contributor', 'helper', 'date', 'time', 'version',
+ 'stability', 'license', 'notes', 'contents', 'compatible',
+ 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
+ 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease',
+ 'extbinrelease', 'bundle', 'changelog'), $uri, 'uri');
+ }
+ $this->_packageInfo['uri'] = $uri;
+ }
+
+ function setChannel($channel)
+ {
+ unset($this->_packageInfo['uri']);
+ $this->_isValid = 0;
+ if (!isset($this->_packageInfo['channel'])) {
+ // ensure that the channel tag is set up in the right location
+ $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
+ array('extends', 'summary', 'description', 'lead',
+ 'developer', 'contributor', 'helper', 'date', 'time', 'version',
+ 'stability', 'license', 'notes', 'contents', 'compatible',
+ 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
+ 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease',
+ 'extbinrelease', 'bundle', 'changelog'), $channel, 'channel');
+ }
+ $this->_packageInfo['channel'] = $channel;
+ }
+
+ function setExtends($extends)
+ {
+ $this->_isValid = 0;
+ if (!isset($this->_packageInfo['extends'])) {
+ // ensure that the extends tag is set up in the right location
+ $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
+ array('summary', 'description', 'lead',
+ 'developer', 'contributor', 'helper', 'date', 'time', 'version',
+ 'stability', 'license', 'notes', 'contents', 'compatible',
+ 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
+ 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease',
+ 'extbinrelease', 'bundle', 'changelog'), $extends, 'extends');
+ }
+ $this->_packageInfo['extends'] = $extends;
+ }
+
+ function setSummary($summary)
+ {
+ $this->_isValid = 0;
+ if (!isset($this->_packageInfo['summary'])) {
+ // ensure that the summary tag is set up in the right location
+ $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
+ array('description', 'lead',
+ 'developer', 'contributor', 'helper', 'date', 'time', 'version',
+ 'stability', 'license', 'notes', 'contents', 'compatible',
+ 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
+ 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease',
+ 'extbinrelease', 'bundle', 'changelog'), $summary, 'summary');
+ }
+ $this->_packageInfo['summary'] = $summary;
+ }
+
+ function setDescription($desc)
+ {
+ $this->_isValid = 0;
+ if (!isset($this->_packageInfo['description'])) {
+ // ensure that the description tag is set up in the right location
+ $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
+ array('lead',
+ 'developer', 'contributor', 'helper', 'date', 'time', 'version',
+ 'stability', 'license', 'notes', 'contents', 'compatible',
+ 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
+ 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease',
+ 'extbinrelease', 'bundle', 'changelog'), $desc, 'description');
+ }
+ $this->_packageInfo['description'] = $desc;
+ }
+
+ /**
+ * Adds a new maintainer - no checking of duplicates is performed, use
+ * updatemaintainer for that purpose.
+ */
+ function addMaintainer($role, $handle, $name, $email, $active = 'yes')
+ {
+ if (!in_array($role, array('lead', 'developer', 'contributor', 'helper'))) {
+ return false;
+ }
+ if (isset($this->_packageInfo[$role])) {
+ if (!isset($this->_packageInfo[$role][0])) {
+ $this->_packageInfo[$role] = array($this->_packageInfo[$role]);
+ }
+ $this->_packageInfo[$role][] =
+ array(
+ 'name' => $name,
+ 'user' => $handle,
+ 'email' => $email,
+ 'active' => $active,
+ );
+ } else {
+ $testarr = array('lead',
+ 'developer', 'contributor', 'helper', 'date', 'time', 'version',
+ 'stability', 'license', 'notes', 'contents', 'compatible',
+ 'dependencies', 'providesextension', 'usesrole', 'usestask',
+ 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease',
+ 'extbinrelease', 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog');
+ foreach (array('lead', 'developer', 'contributor', 'helper') as $testrole) {
+ array_shift($testarr);
+ if ($role == $testrole) {
+ break;
+ }
+ }
+ if (!isset($this->_packageInfo[$role])) {
+ // ensure that the extends tag is set up in the right location
+ $this->_packageInfo = $this->_insertBefore($this->_packageInfo, $testarr,
+ array(), $role);
+ }
+ $this->_packageInfo[$role] =
+ array(
+ 'name' => $name,
+ 'user' => $handle,
+ 'email' => $email,
+ 'active' => $active,
+ );
+ }
+ $this->_isValid = 0;
+ }
+
+ function updateMaintainer($newrole, $handle, $name, $email, $active = 'yes')
+ {
+ $found = false;
+ foreach (array('lead', 'developer', 'contributor', 'helper') as $role) {
+ if (!isset($this->_packageInfo[$role])) {
+ continue;
+ }
+ $info = $this->_packageInfo[$role];
+ if (!isset($info[0])) {
+ if ($info['user'] == $handle) {
+ $found = true;
+ break;
+ }
+ }
+ foreach ($info as $i => $maintainer) {
+ if (is_array($maintainer) && $maintainer['user'] == $handle) {
+ $found = $i;
+ break 2;
+ }
+ }
+ }
+ if ($found === false) {
+ return $this->addMaintainer($newrole, $handle, $name, $email, $active);
+ }
+ if ($found !== false) {
+ if ($found === true) {
+ unset($this->_packageInfo[$role]);
+ } else {
+ unset($this->_packageInfo[$role][$found]);
+ $this->_packageInfo[$role] = array_values($this->_packageInfo[$role]);
+ }
+ }
+ $this->addMaintainer($newrole, $handle, $name, $email, $active);
+ $this->_isValid = 0;
+ }
+
+ function deleteMaintainer($handle)
+ {
+ $found = false;
+ foreach (array('lead', 'developer', 'contributor', 'helper') as $role) {
+ if (!isset($this->_packageInfo[$role])) {
+ continue;
+ }
+ if (!isset($this->_packageInfo[$role][0])) {
+ $this->_packageInfo[$role] = array($this->_packageInfo[$role]);
+ }
+ foreach ($this->_packageInfo[$role] as $i => $maintainer) {
+ if ($maintainer['user'] == $handle) {
+ $found = $i;
+ break;
+ }
+ }
+ if ($found !== false) {
+ unset($this->_packageInfo[$role][$found]);
+ if (!count($this->_packageInfo[$role]) && $role == 'lead') {
+ $this->_isValid = 0;
+ }
+ if (!count($this->_packageInfo[$role])) {
+ unset($this->_packageInfo[$role]);
+ return true;
+ }
+ $this->_packageInfo[$role] =
+ array_values($this->_packageInfo[$role]);
+ if (count($this->_packageInfo[$role]) == 1) {
+ $this->_packageInfo[$role] = $this->_packageInfo[$role][0];
+ }
+ return true;
+ }
+ if (count($this->_packageInfo[$role]) == 1) {
+ $this->_packageInfo[$role] = $this->_packageInfo[$role][0];
+ }
+ }
+ return false;
+ }
+
+ function setReleaseVersion($version)
+ {
+ if (isset($this->_packageInfo['version']) &&
+ isset($this->_packageInfo['version']['release'])) {
+ unset($this->_packageInfo['version']['release']);
+ }
+ $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $version, array(
+ 'version' => array('stability', 'license', 'notes', 'contents', 'compatible',
+ 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
+ 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease',
+ 'extbinrelease', 'bundle', 'changelog'),
+ 'release' => array('api')));
+ $this->_isValid = 0;
+ }
+
+ function setAPIVersion($version)
+ {
+ if (isset($this->_packageInfo['version']) &&
+ isset($this->_packageInfo['version']['api'])) {
+ unset($this->_packageInfo['version']['api']);
+ }
+ $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $version, array(
+ 'version' => array('stability', 'license', 'notes', 'contents', 'compatible',
+ 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
+ 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease',
+ 'extbinrelease', 'bundle', 'changelog'),
+ 'api' => array()));
+ $this->_isValid = 0;
+ }
+
+ /**
+ * snapshot|devel|alpha|beta|stable
+ */
+ function setReleaseStability($state)
+ {
+ if (isset($this->_packageInfo['stability']) &&
+ isset($this->_packageInfo['stability']['release'])) {
+ unset($this->_packageInfo['stability']['release']);
+ }
+ $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $state, array(
+ 'stability' => array('license', 'notes', 'contents', 'compatible',
+ 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
+ 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease',
+ 'extbinrelease', 'bundle', 'changelog'),
+ 'release' => array('api')));
+ $this->_isValid = 0;
+ }
+
+ /**
+ * @param devel|alpha|beta|stable
+ */
+ function setAPIStability($state)
+ {
+ if (isset($this->_packageInfo['stability']) &&
+ isset($this->_packageInfo['stability']['api'])) {
+ unset($this->_packageInfo['stability']['api']);
+ }
+ $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $state, array(
+ 'stability' => array('license', 'notes', 'contents', 'compatible',
+ 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
+ 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease',
+ 'extbinrelease', 'bundle', 'changelog'),
+ 'api' => array()));
+ $this->_isValid = 0;
+ }
+
+ function setLicense($license, $uri = false, $filesource = false)
+ {
+ if (!isset($this->_packageInfo['license'])) {
+ // ensure that the license tag is set up in the right location
+ $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
+ array('notes', 'contents', 'compatible',
+ 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
+ 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease',
+ 'extbinrelease', 'bundle', 'changelog'), 0, 'license');
+ }
+ if ($uri || $filesource) {
+ $attribs = array();
+ if ($uri) {
+ $attribs['uri'] = $uri;
+ }
+ $uri = true; // for test below
+ if ($filesource) {
+ $attribs['filesource'] = $filesource;
+ }
+ }
+ $license = $uri ? array('attribs' => $attribs, '_content' => $license) : $license;
+ $this->_packageInfo['license'] = $license;
+ $this->_isValid = 0;
+ }
+
+ function setNotes($notes)
+ {
+ $this->_isValid = 0;
+ if (!isset($this->_packageInfo['notes'])) {
+ // ensure that the notes tag is set up in the right location
+ $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
+ array('contents', 'compatible',
+ 'dependencies', 'providesextension', 'usesrole', 'usestask', 'srcpackage', 'srcuri',
+ 'phprelease', 'extsrcrelease', 'zendextsrcrelease', 'zendextbinrelease',
+ 'extbinrelease', 'bundle', 'changelog'), $notes, 'notes');
+ }
+ $this->_packageInfo['notes'] = $notes;
+ }
+
+ /**
+ * This is only used at install-time, after all serialization
+ * is over.
+ * @param string file name
+ * @param string installed path
+ */
+ function setInstalledAs($file, $path)
+ {
+ if ($path) {
+ return $this->_packageInfo['filelist'][$file]['installed_as'] = $path;
+ }
+ unset($this->_packageInfo['filelist'][$file]['installed_as']);
+ }
+
+ /**
+ * This is only used at install-time, after all serialization
+ * is over.
+ */
+ function installedFile($file, $atts)
+ {
+ if (isset($this->_packageInfo['filelist'][$file])) {
+ $this->_packageInfo['filelist'][$file] =
+ array_merge($this->_packageInfo['filelist'][$file], $atts['attribs']);
+ } else {
+ $this->_packageInfo['filelist'][$file] = $atts['attribs'];
+ }
+ }
+
+ /**
+ * Reset the listing of package contents
+ * @param string base installation dir for the whole package, if any
+ */
+ function clearContents($baseinstall = false)
+ {
+ $this->_filesValid = false;
+ $this->_isValid = 0;
+ if (!isset($this->_packageInfo['contents'])) {
+ $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
+ array('compatible',
+ 'dependencies', 'providesextension', 'usesrole', 'usestask',
+ 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease',
+ 'extbinrelease', 'zendextsrcrelease', 'zendextbinrelease',
+ 'bundle', 'changelog'), array(), 'contents');
+ }
+ if ($this->getPackageType() != 'bundle') {
+ $this->_packageInfo['contents'] =
+ array('dir' => array('attribs' => array('name' => '/')));
+ if ($baseinstall) {
+ $this->_packageInfo['contents']['dir']['attribs']['baseinstalldir'] = $baseinstall;
+ }
+ } else {
+ $this->_packageInfo['contents'] = array('bundledpackage' => array());
+ }
+ }
+
+ /**
+ * @param string relative path of the bundled package.
+ */
+ function addBundledPackage($path)
+ {
+ if ($this->getPackageType() != 'bundle') {
+ return false;
+ }
+ $this->_filesValid = false;
+ $this->_isValid = 0;
+ $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $path, array(
+ 'contents' => array('compatible', 'dependencies', 'providesextension',
+ 'usesrole', 'usestask', 'srcpackage', 'srcuri', 'phprelease',
+ 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease', 'zendextbinrelease',
+ 'bundle', 'changelog'),
+ 'bundledpackage' => array()));
+ }
+
+ /**
+ * @param string file name
+ * @param PEAR_Task_Common a read/write task
+ */
+ function addTaskToFile($filename, $task)
+ {
+ if (!method_exists($task, 'getXml')) {
+ return false;
+ }
+ if (!method_exists($task, 'getName')) {
+ return false;
+ }
+ if (!method_exists($task, 'validate')) {
+ return false;
+ }
+ if (!$task->validate()) {
+ return false;
+ }
+ if (!isset($this->_packageInfo['contents']['dir']['file'])) {
+ return false;
+ }
+ $this->getTasksNs(); // discover the tasks namespace if not done already
+ $files = $this->_packageInfo['contents']['dir']['file'];
+ if (!isset($files[0])) {
+ $files = array($files);
+ $ind = false;
+ } else {
+ $ind = true;
+ }
+ foreach ($files as $i => $file) {
+ if (isset($file['attribs'])) {
+ if ($file['attribs']['name'] == $filename) {
+ if ($ind) {
+ $t = isset($this->_packageInfo['contents']['dir']['file'][$i]
+ ['attribs'][$this->_tasksNs .
+ ':' . $task->getName()]) ?
+ $this->_packageInfo['contents']['dir']['file'][$i]
+ ['attribs'][$this->_tasksNs .
+ ':' . $task->getName()] : false;
+ if ($t && !isset($t[0])) {
+ $this->_packageInfo['contents']['dir']['file'][$i]
+ [$this->_tasksNs . ':' . $task->getName()] = array($t);
+ }
+ $this->_packageInfo['contents']['dir']['file'][$i][$this->_tasksNs .
+ ':' . $task->getName()][] = $task->getXml();
+ } else {
+ $t = isset($this->_packageInfo['contents']['dir']['file']
+ ['attribs'][$this->_tasksNs .
+ ':' . $task->getName()]) ? $this->_packageInfo['contents']['dir']['file']
+ ['attribs'][$this->_tasksNs .
+ ':' . $task->getName()] : false;
+ if ($t && !isset($t[0])) {
+ $this->_packageInfo['contents']['dir']['file']
+ [$this->_tasksNs . ':' . $task->getName()] = array($t);
+ }
+ $this->_packageInfo['contents']['dir']['file'][$this->_tasksNs .
+ ':' . $task->getName()][] = $task->getXml();
+ }
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @param string path to the file
+ * @param string filename
+ * @param array extra attributes
+ */
+ function addFile($dir, $file, $attrs)
+ {
+ if ($this->getPackageType() == 'bundle') {
+ return false;
+ }
+ $this->_filesValid = false;
+ $this->_isValid = 0;
+ $dir = preg_replace(array('!\\\\+!', '!/+!'), array('/', '/'), $dir);
+ if ($dir == '/' || $dir == '') {
+ $dir = '';
+ } else {
+ $dir .= '/';
+ }
+ $attrs['name'] = $dir . $file;
+ if (!isset($this->_packageInfo['contents'])) {
+ // ensure that the contents tag is set up
+ $this->_packageInfo = $this->_insertBefore($this->_packageInfo,
+ array('compatible', 'dependencies', 'providesextension', 'usesrole', 'usestask',
+ 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease',
+ 'extbinrelease', 'zendextsrcrelease', 'zendextbinrelease',
+ 'bundle', 'changelog'), array(), 'contents');
+ }
+ if (isset($this->_packageInfo['contents']['dir']['file'])) {
+ if (!isset($this->_packageInfo['contents']['dir']['file'][0])) {
+ $this->_packageInfo['contents']['dir']['file'] =
+ array($this->_packageInfo['contents']['dir']['file']);
+ }
+ $this->_packageInfo['contents']['dir']['file'][]['attribs'] = $attrs;
+ } else {
+ $this->_packageInfo['contents']['dir']['file']['attribs'] = $attrs;
+ }
+ }
+
+ /**
+ * @param string Dependent package name
+ * @param string Dependent package's channel name
+ * @param string minimum version of specified package that this release is guaranteed to be
+ * compatible with
+ * @param string maximum version of specified package that this release is guaranteed to be
+ * compatible with
+ * @param string versions of specified package that this release is not compatible with
+ */
+ function addCompatiblePackage($name, $channel, $min, $max, $exclude = false)
+ {
+ $this->_isValid = 0;
+ $set = array(
+ 'name' => $name,
+ 'channel' => $channel,
+ 'min' => $min,
+ 'max' => $max,
+ );
+ if ($exclude) {
+ $set['exclude'] = $exclude;
+ }
+ $this->_isValid = 0;
+ $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $set, array(
+ 'compatible' => array('dependencies', 'providesextension', 'usesrole', 'usestask',
+ 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
+ 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog')
+ ));
+ }
+
+ /**
+ * Removes the tag entirely
+ */
+ function resetUsesrole()
+ {
+ if (isset($this->_packageInfo['usesrole'])) {
+ unset($this->_packageInfo['usesrole']);
+ }
+ }
+
+ /**
+ * @param string
+ * @param string package name or uri
+ * @param string channel name if non-uri
+ */
+ function addUsesrole($role, $packageOrUri, $channel = false) {
+ $set = array('role' => $role);
+ if ($channel) {
+ $set['package'] = $packageOrUri;
+ $set['channel'] = $channel;
+ } else {
+ $set['uri'] = $packageOrUri;
+ }
+ $this->_isValid = 0;
+ $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $set, array(
+ 'usesrole' => array('usestask', 'srcpackage', 'srcuri',
+ 'phprelease', 'extsrcrelease', 'extbinrelease',
+ 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog')
+ ));
+ }
+
+ /**
+ * Removes the tag entirely
+ */
+ function resetUsestask()
+ {
+ if (isset($this->_packageInfo['usestask'])) {
+ unset($this->_packageInfo['usestask']);
+ }
+ }
+
+
+ /**
+ * @param string
+ * @param string package name or uri
+ * @param string channel name if non-uri
+ */
+ function addUsestask($task, $packageOrUri, $channel = false) {
+ $set = array('task' => $task);
+ if ($channel) {
+ $set['package'] = $packageOrUri;
+ $set['channel'] = $channel;
+ } else {
+ $set['uri'] = $packageOrUri;
+ }
+ $this->_isValid = 0;
+ $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $set, array(
+ 'usestask' => array('srcpackage', 'srcuri',
+ 'phprelease', 'extsrcrelease', 'extbinrelease',
+ 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog')
+ ));
+ }
+
+ /**
+ * Remove all compatible tags
+ */
+ function clearCompatible()
+ {
+ unset($this->_packageInfo['compatible']);
+ }
+
+ /**
+ * Reset dependencies prior to adding new ones
+ */
+ function clearDeps()
+ {
+ if (!isset($this->_packageInfo['dependencies'])) {
+ $this->_packageInfo = $this->_mergeTag($this->_packageInfo, array(),
+ array(
+ 'dependencies' => array('providesextension', 'usesrole', 'usestask',
+ 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
+ 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog')));
+ }
+ $this->_packageInfo['dependencies'] = array();
+ }
+
+ /**
+ * @param string minimum PHP version allowed
+ * @param string maximum PHP version allowed
+ * @param array $exclude incompatible PHP versions
+ */
+ function setPhpDep($min, $max = false, $exclude = false)
+ {
+ $this->_isValid = 0;
+ $dep =
+ array(
+ 'min' => $min,
+ );
+ if ($max) {
+ $dep['max'] = $max;
+ }
+ if ($exclude) {
+ if (count($exclude) == 1) {
+ $exclude = $exclude[0];
+ }
+ $dep['exclude'] = $exclude;
+ }
+ if (isset($this->_packageInfo['dependencies']['required']['php'])) {
+ $this->_stack->push(__FUNCTION__, 'warning', array('dep' =>
+ $this->_packageInfo['dependencies']['required']['php']),
+ 'warning: PHP dependency already exists, overwriting');
+ unset($this->_packageInfo['dependencies']['required']['php']);
+ }
+ $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
+ array(
+ 'dependencies' => array('providesextension', 'usesrole', 'usestask',
+ 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
+ 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'),
+ 'required' => array('optional', 'group'),
+ 'php' => array('pearinstaller', 'package', 'subpackage', 'extension', 'os', 'arch')
+ ));
+ return true;
+ }
+
+ /**
+ * @param string minimum allowed PEAR installer version
+ * @param string maximum allowed PEAR installer version
+ * @param string recommended PEAR installer version
+ * @param array incompatible version of the PEAR installer
+ */
+ function setPearinstallerDep($min, $max = false, $recommended = false, $exclude = false)
+ {
+ $this->_isValid = 0;
+ $dep =
+ array(
+ 'min' => $min,
+ );
+ if ($max) {
+ $dep['max'] = $max;
+ }
+ if ($recommended) {
+ $dep['recommended'] = $recommended;
+ }
+ if ($exclude) {
+ if (count($exclude) == 1) {
+ $exclude = $exclude[0];
+ }
+ $dep['exclude'] = $exclude;
+ }
+ if (isset($this->_packageInfo['dependencies']['required']['pearinstaller'])) {
+ $this->_stack->push(__FUNCTION__, 'warning', array('dep' =>
+ $this->_packageInfo['dependencies']['required']['pearinstaller']),
+ 'warning: PEAR Installer dependency already exists, overwriting');
+ unset($this->_packageInfo['dependencies']['required']['pearinstaller']);
+ }
+ $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
+ array(
+ 'dependencies' => array('providesextension', 'usesrole', 'usestask',
+ 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
+ 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'),
+ 'required' => array('optional', 'group'),
+ 'pearinstaller' => array('package', 'subpackage', 'extension', 'os', 'arch')
+ ));
+ }
+
+ /**
+ * Mark a package as conflicting with this package
+ * @param string package name
+ * @param string package channel
+ * @param string extension this package provides, if any
+ * @param string|false minimum version required
+ * @param string|false maximum version allowed
+ * @param array|false versions to exclude from installation
+ */
+ function addConflictingPackageDepWithChannel($name, $channel,
+ $providesextension = false, $min = false, $max = false, $exclude = false)
+ {
+ $this->_isValid = 0;
+ $dep = $this->_constructDep($name, $channel, false, $min, $max, false,
+ $exclude, $providesextension, false, true);
+ $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
+ array(
+ 'dependencies' => array('providesextension', 'usesrole', 'usestask',
+ 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
+ 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'),
+ 'required' => array('optional', 'group'),
+ 'package' => array('subpackage', 'extension', 'os', 'arch')
+ ));
+ }
+
+ /**
+ * Mark a package as conflicting with this package
+ * @param string package name
+ * @param string package channel
+ * @param string extension this package provides, if any
+ */
+ function addConflictingPackageDepWithUri($name, $uri, $providesextension = false)
+ {
+ $this->_isValid = 0;
+ $dep =
+ array(
+ 'name' => $name,
+ 'uri' => $uri,
+ 'conflicts' => '',
+ );
+ if ($providesextension) {
+ $dep['providesextension'] = $providesextension;
+ }
+ $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
+ array(
+ 'dependencies' => array('providesextension', 'usesrole', 'usestask',
+ 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
+ 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'),
+ 'required' => array('optional', 'group'),
+ 'package' => array('subpackage', 'extension', 'os', 'arch')
+ ));
+ }
+
+ function addDependencyGroup($name, $hint)
+ {
+ $this->_isValid = 0;
+ $this->_packageInfo = $this->_mergeTag($this->_packageInfo,
+ array('attribs' => array('name' => $name, 'hint' => $hint)),
+ array(
+ 'dependencies' => array('providesextension', 'usesrole', 'usestask',
+ 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
+ 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'),
+ 'group' => array(),
+ ));
+ }
+
+ /**
+ * @param string package name
+ * @param string|false channel name, false if this is a uri
+ * @param string|false uri name, false if this is a channel
+ * @param string|false minimum version required
+ * @param string|false maximum version allowed
+ * @param string|false recommended installation version
+ * @param array|false versions to exclude from installation
+ * @param string extension this package provides, if any
+ * @param bool if true, tells the installer to ignore the default optional dependency group
+ * when installing this package
+ * @param bool if true, tells the installer to negate this dependency (conflicts)
+ * @return array
+ * @access private
+ */
+ function _constructDep($name, $channel, $uri, $min, $max, $recommended, $exclude,
+ $providesextension = false, $nodefault = false,
+ $conflicts = false)
+ {
+ $dep =
+ array(
+ 'name' => $name,
+ );
+ if ($channel) {
+ $dep['channel'] = $channel;
+ } elseif ($uri) {
+ $dep['uri'] = $uri;
+ }
+ if ($min) {
+ $dep['min'] = $min;
+ }
+ if ($max) {
+ $dep['max'] = $max;
+ }
+ if ($recommended) {
+ $dep['recommended'] = $recommended;
+ }
+ if ($exclude) {
+ if (is_array($exclude) && count($exclude) == 1) {
+ $exclude = $exclude[0];
+ }
+ $dep['exclude'] = $exclude;
+ }
+ if ($conflicts) {
+ $dep['conflicts'] = '';
+ }
+ if ($nodefault) {
+ $dep['nodefault'] = '';
+ }
+ if ($providesextension) {
+ $dep['providesextension'] = $providesextension;
+ }
+ return $dep;
+ }
+
+ /**
+ * @param package|subpackage
+ * @param string group name
+ * @param string package name
+ * @param string package channel
+ * @param string minimum version
+ * @param string maximum version
+ * @param string recommended version
+ * @param array|false optional excluded versions
+ * @param string extension this package provides, if any
+ * @param bool if true, tells the installer to ignore the default optional dependency group
+ * when installing this package
+ * @return bool false if the dependency group has not been initialized with
+ * {@link addDependencyGroup()}, or a subpackage is added with
+ * a providesextension
+ */
+ function addGroupPackageDepWithChannel($type, $groupname, $name, $channel, $min = false,
+ $max = false, $recommended = false, $exclude = false,
+ $providesextension = false, $nodefault = false)
+ {
+ if ($type == 'subpackage' && $providesextension) {
+ return false; // subpackages must be php packages
+ }
+ $dep = $this->_constructDep($name, $channel, false, $min, $max, $recommended, $exclude,
+ $providesextension, $nodefault);
+ return $this->_addGroupDependency($type, $dep, $groupname);
+ }
+
+ /**
+ * @param package|subpackage
+ * @param string group name
+ * @param string package name
+ * @param string package uri
+ * @param string extension this package provides, if any
+ * @param bool if true, tells the installer to ignore the default optional dependency group
+ * when installing this package
+ * @return bool false if the dependency group has not been initialized with
+ * {@link addDependencyGroup()}
+ */
+ function addGroupPackageDepWithURI($type, $groupname, $name, $uri, $providesextension = false,
+ $nodefault = false)
+ {
+ if ($type == 'subpackage' && $providesextension) {
+ return false; // subpackages must be php packages
+ }
+ $dep = $this->_constructDep($name, false, $uri, false, false, false, false,
+ $providesextension, $nodefault);
+ return $this->_addGroupDependency($type, $dep, $groupname);
+ }
+
+ /**
+ * @param string group name (must be pre-existing)
+ * @param string extension name
+ * @param string minimum version allowed
+ * @param string maximum version allowed
+ * @param string recommended version
+ * @param array incompatible versions
+ */
+ function addGroupExtensionDep($groupname, $name, $min = false, $max = false,
+ $recommended = false, $exclude = false)
+ {
+ $this->_isValid = 0;
+ $dep = $this->_constructDep($name, false, false, $min, $max, $recommended, $exclude);
+ return $this->_addGroupDependency('extension', $dep, $groupname);
+ }
+
+ /**
+ * @param package|subpackage|extension
+ * @param array dependency contents
+ * @param string name of the dependency group to add this to
+ * @return boolean
+ * @access private
+ */
+ function _addGroupDependency($type, $dep, $groupname)
+ {
+ $arr = array('subpackage', 'extension');
+ if ($type != 'package') {
+ array_shift($arr);
+ }
+ if ($type == 'extension') {
+ array_shift($arr);
+ }
+ if (!isset($this->_packageInfo['dependencies']['group'])) {
+ return false;
+ } else {
+ if (!isset($this->_packageInfo['dependencies']['group'][0])) {
+ if ($this->_packageInfo['dependencies']['group']['attribs']['name'] == $groupname) {
+ $this->_packageInfo['dependencies']['group'] = $this->_mergeTag(
+ $this->_packageInfo['dependencies']['group'], $dep,
+ array(
+ $type => $arr
+ ));
+ $this->_isValid = 0;
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ foreach ($this->_packageInfo['dependencies']['group'] as $i => $group) {
+ if ($group['attribs']['name'] == $groupname) {
+ $this->_packageInfo['dependencies']['group'][$i] = $this->_mergeTag(
+ $this->_packageInfo['dependencies']['group'][$i], $dep,
+ array(
+ $type => $arr
+ ));
+ $this->_isValid = 0;
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+ }
+
+ /**
+ * @param optional|required
+ * @param string package name
+ * @param string package channel
+ * @param string minimum version
+ * @param string maximum version
+ * @param string recommended version
+ * @param string extension this package provides, if any
+ * @param bool if true, tells the installer to ignore the default optional dependency group
+ * when installing this package
+ * @param array|false optional excluded versions
+ */
+ function addPackageDepWithChannel($type, $name, $channel, $min = false, $max = false,
+ $recommended = false, $exclude = false,
+ $providesextension = false, $nodefault = false)
+ {
+ if (!in_array($type, array('optional', 'required'), true)) {
+ $type = 'required';
+ }
+ $this->_isValid = 0;
+ $arr = array('optional', 'group');
+ if ($type != 'required') {
+ array_shift($arr);
+ }
+ $dep = $this->_constructDep($name, $channel, false, $min, $max, $recommended, $exclude,
+ $providesextension, $nodefault);
+ $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
+ array(
+ 'dependencies' => array('providesextension', 'usesrole', 'usestask',
+ 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
+ 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'),
+ $type => $arr,
+ 'package' => array('subpackage', 'extension', 'os', 'arch')
+ ));
+ }
+
+ /**
+ * @param optional|required
+ * @param string name of the package
+ * @param string uri of the package
+ * @param string extension this package provides, if any
+ * @param bool if true, tells the installer to ignore the default optional dependency group
+ * when installing this package
+ */
+ function addPackageDepWithUri($type, $name, $uri, $providesextension = false,
+ $nodefault = false)
+ {
+ $this->_isValid = 0;
+ $arr = array('optional', 'group');
+ if ($type != 'required') {
+ array_shift($arr);
+ }
+ $dep = $this->_constructDep($name, false, $uri, false, false, false, false,
+ $providesextension, $nodefault);
+ $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
+ array(
+ 'dependencies' => array('providesextension', 'usesrole', 'usestask',
+ 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
+ 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'),
+ $type => $arr,
+ 'package' => array('subpackage', 'extension', 'os', 'arch')
+ ));
+ }
+
+ /**
+ * @param optional|required optional, required
+ * @param string package name
+ * @param string package channel
+ * @param string minimum version
+ * @param string maximum version
+ * @param string recommended version
+ * @param array incompatible versions
+ * @param bool if true, tells the installer to ignore the default optional dependency group
+ * when installing this package
+ */
+ function addSubpackageDepWithChannel($type, $name, $channel, $min = false, $max = false,
+ $recommended = false, $exclude = false,
+ $nodefault = false)
+ {
+ $this->_isValid = 0;
+ $arr = array('optional', 'group');
+ if ($type != 'required') {
+ array_shift($arr);
+ }
+ $dep = $this->_constructDep($name, $channel, false, $min, $max, $recommended, $exclude,
+ $nodefault);
+ $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
+ array(
+ 'dependencies' => array('providesextension', 'usesrole', 'usestask',
+ 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
+ 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'),
+ $type => $arr,
+ 'subpackage' => array('extension', 'os', 'arch')
+ ));
+ }
+
+ /**
+ * @param optional|required optional, required
+ * @param string package name
+ * @param string package uri for download
+ * @param bool if true, tells the installer to ignore the default optional dependency group
+ * when installing this package
+ */
+ function addSubpackageDepWithUri($type, $name, $uri, $nodefault = false)
+ {
+ $this->_isValid = 0;
+ $arr = array('optional', 'group');
+ if ($type != 'required') {
+ array_shift($arr);
+ }
+ $dep = $this->_constructDep($name, false, $uri, false, false, false, false, $nodefault);
+ $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
+ array(
+ 'dependencies' => array('providesextension', 'usesrole', 'usestask',
+ 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
+ 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'),
+ $type => $arr,
+ 'subpackage' => array('extension', 'os', 'arch')
+ ));
+ }
+
+ /**
+ * @param optional|required optional, required
+ * @param string extension name
+ * @param string minimum version
+ * @param string maximum version
+ * @param string recommended version
+ * @param array incompatible versions
+ */
+ function addExtensionDep($type, $name, $min = false, $max = false, $recommended = false,
+ $exclude = false)
+ {
+ $this->_isValid = 0;
+ $arr = array('optional', 'group');
+ if ($type != 'required') {
+ array_shift($arr);
+ }
+ $dep = $this->_constructDep($name, false, false, $min, $max, $recommended, $exclude);
+ $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
+ array(
+ 'dependencies' => array('providesextension', 'usesrole', 'usestask',
+ 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
+ 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'),
+ $type => $arr,
+ 'extension' => array('os', 'arch')
+ ));
+ }
+
+ /**
+ * @param string Operating system name
+ * @param boolean true if this package cannot be installed on this OS
+ */
+ function addOsDep($name, $conflicts = false)
+ {
+ $this->_isValid = 0;
+ $dep = array('name' => $name);
+ if ($conflicts) {
+ $dep['conflicts'] = '';
+ }
+ $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
+ array(
+ 'dependencies' => array('providesextension', 'usesrole', 'usestask',
+ 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
+ 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'),
+ 'required' => array('optional', 'group'),
+ 'os' => array('arch')
+ ));
+ }
+
+ /**
+ * @param string Architecture matching pattern
+ * @param boolean true if this package cannot be installed on this architecture
+ */
+ function addArchDep($pattern, $conflicts = false)
+ {
+ $this->_isValid = 0;
+ $dep = array('pattern' => $pattern);
+ if ($conflicts) {
+ $dep['conflicts'] = '';
+ }
+ $this->_packageInfo = $this->_mergeTag($this->_packageInfo, $dep,
+ array(
+ 'dependencies' => array('providesextension', 'usesrole', 'usestask',
+ 'srcpackage', 'srcuri', 'phprelease', 'extsrcrelease', 'extbinrelease',
+ 'zendextsrcrelease', 'zendextbinrelease', 'bundle', 'changelog'),
+ 'required' => array('optional', 'group'),
+ 'arch' => array()
+ ));
+ }
+
+ /**
+ * Set the kind of package, and erase all release tags
+ *
+ * - a php package is a PEAR-style package
+ * - an extbin package is a PECL-style extension binary
+ * - an extsrc package is a PECL-style source for a binary
+ * - an zendextbin package is a PECL-style zend extension binary
+ * - an zendextsrc package is a PECL-style source for a zend extension binary
+ * - a bundle package is a collection of other pre-packaged packages
+ * @param php|extbin|extsrc|zendextsrc|zendextbin|bundle
+ * @return bool success
+ */
+ function setPackageType($type)
+ {
+ $this->_isValid = 0;
+ if (!in_array($type, array('php', 'extbin', 'extsrc', 'zendextsrc',
+ 'zendextbin', 'bundle'))) {
+ return false;
+ }
+
+ if (in_array($type, array('zendextsrc', 'zendextbin'))) {
+ $this->_setPackageVersion2_1();
+ }
+
+ if ($type != 'bundle') {
+ $type .= 'release';
+ }
+
+ foreach (array('phprelease', 'extbinrelease', 'extsrcrelease',
+ 'zendextsrcrelease', 'zendextbinrelease', 'bundle') as $test) {
+ unset($this->_packageInfo[$test]);
+ }
+
+ if (!isset($this->_packageInfo[$type])) {
+ // ensure that the release tag is set up
+ $this->_packageInfo = $this->_insertBefore($this->_packageInfo, array('changelog'),
+ array(), $type);
+ }
+
+ $this->_packageInfo[$type] = array();
+ return true;
+ }
+
+ /**
+ * @return bool true if package type is set up
+ */
+ function addRelease()
+ {
+ if ($type = $this->getPackageType()) {
+ if ($type != 'bundle') {
+ $type .= 'release';
+ }
+ $this->_packageInfo = $this->_mergeTag($this->_packageInfo, array(),
+ array($type => array('changelog')));
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Get the current release tag in order to add to it
+ * @param bool returns only releases that have installcondition if true
+ * @return array|null
+ */
+ function &_getCurrentRelease($strict = true)
+ {
+ if ($p = $this->getPackageType()) {
+ if ($strict) {
+ if ($p == 'extsrc' || $p == 'zendextsrc') {
+ $a = null;
+ return $a;
+ }
+ }
+ if ($p != 'bundle') {
+ $p .= 'release';
+ }
+ if (isset($this->_packageInfo[$p][0])) {
+ return $this->_packageInfo[$p][count($this->_packageInfo[$p]) - 1];
+ } else {
+ return $this->_packageInfo[$p];
+ }
+ } else {
+ $a = null;
+ return $a;
+ }
+ }
+
+ /**
+ * Add a file to the current release that should be installed under a different name
+ * @param string path to file
+ * @param string name the file should be installed as
+ */
+ function addInstallAs($path, $as)
+ {
+ $r = &$this->_getCurrentRelease();
+ if ($r === null) {
+ return false;
+ }
+ $this->_isValid = 0;
+ $r = $this->_mergeTag($r, array('attribs' => array('name' => $path, 'as' => $as)),
+ array(
+ 'filelist' => array(),
+ 'install' => array('ignore')
+ ));
+ }
+
+ /**
+ * Add a file to the current release that should be ignored
+ * @param string path to file
+ * @return bool success of operation
+ */
+ function addIgnore($path)
+ {
+ $r = &$this->_getCurrentRelease();
+ if ($r === null) {
+ return false;
+ }
+ $this->_isValid = 0;
+ $r = $this->_mergeTag($r, array('attribs' => array('name' => $path)),
+ array(
+ 'filelist' => array(),
+ 'ignore' => array()
+ ));
+ }
+
+ /**
+ * Add an extension binary package for this extension source code release
+ *
+ * Note that the package must be from the same channel as the extension source package
+ * @param string
+ */
+ function addBinarypackage($package)
+ {
+ if ($this->getPackageType() != 'extsrc' && $this->getPackageType() != 'zendextsrc') {
+ return false;
+ }
+ $r = &$this->_getCurrentRelease(false);
+ if ($r === null) {
+ return false;
+ }
+ $this->_isValid = 0;
+ $r = $this->_mergeTag($r, $package,
+ array(
+ 'binarypackage' => array('filelist'),
+ ));
+ }
+
+ /**
+ * Add a configureoption to an extension source package
+ * @param string
+ * @param string
+ * @param string
+ */
+ function addConfigureOption($name, $prompt, $default = null)
+ {
+ if ($this->getPackageType() != 'extsrc' && $this->getPackageType() != 'zendextsrc') {
+ return false;
+ }
+
+ $r = &$this->_getCurrentRelease(false);
+ if ($r === null) {
+ return false;
+ }
+
+ $opt = array('attribs' => array('name' => $name, 'prompt' => $prompt));
+ if ($default !== null) {
+ $opt['attribs']['default'] = $default;
+ }
+
+ $this->_isValid = 0;
+ $r = $this->_mergeTag($r, $opt,
+ array(
+ 'configureoption' => array('binarypackage', 'filelist'),
+ ));
+ }
+
+ /**
+ * Set an installation condition based on php version for the current release set
+ * @param string minimum version
+ * @param string maximum version
+ * @param false|array incompatible versions of PHP
+ */
+ function setPhpInstallCondition($min, $max, $exclude = false)
+ {
+ $r = &$this->_getCurrentRelease();
+ if ($r === null) {
+ return false;
+ }
+ $this->_isValid = 0;
+ if (isset($r['installconditions']['php'])) {
+ unset($r['installconditions']['php']);
+ }
+ $dep = array('min' => $min, 'max' => $max);
+ if ($exclude) {
+ if (is_array($exclude) && count($exclude) == 1) {
+ $exclude = $exclude[0];
+ }
+ $dep['exclude'] = $exclude;
+ }
+ if ($this->getPackageType() == 'extsrc' || $this->getPackageType() == 'zendextsrc') {
+ $r = $this->_mergeTag($r, $dep,
+ array(
+ 'installconditions' => array('configureoption', 'binarypackage',
+ 'filelist'),
+ 'php' => array('extension', 'os', 'arch')
+ ));
+ } else {
+ $r = $this->_mergeTag($r, $dep,
+ array(
+ 'installconditions' => array('filelist'),
+ 'php' => array('extension', 'os', 'arch')
+ ));
+ }
+ }
+
+ /**
+ * @param optional|required optional, required
+ * @param string extension name
+ * @param string minimum version
+ * @param string maximum version
+ * @param string recommended version
+ * @param array incompatible versions
+ */
+ function addExtensionInstallCondition($name, $min = false, $max = false, $recommended = false,
+ $exclude = false)
+ {
+ $r = &$this->_getCurrentRelease();
+ if ($r === null) {
+ return false;
+ }
+ $this->_isValid = 0;
+ $dep = $this->_constructDep($name, false, false, $min, $max, $recommended, $exclude);
+ if ($this->getPackageType() == 'extsrc' || $this->getPackageType() == 'zendextsrc') {
+ $r = $this->_mergeTag($r, $dep,
+ array(
+ 'installconditions' => array('configureoption', 'binarypackage',
+ 'filelist'),
+ 'extension' => array('os', 'arch')
+ ));
+ } else {
+ $r = $this->_mergeTag($r, $dep,
+ array(
+ 'installconditions' => array('filelist'),
+ 'extension' => array('os', 'arch')
+ ));
+ }
+ }
+
+ /**
+ * Set an installation condition based on operating system for the current release set
+ * @param string OS name
+ * @param bool whether this OS is incompatible with the current release
+ */
+ function setOsInstallCondition($name, $conflicts = false)
+ {
+ $r = &$this->_getCurrentRelease();
+ if ($r === null) {
+ return false;
+ }
+ $this->_isValid = 0;
+ if (isset($r['installconditions']['os'])) {
+ unset($r['installconditions']['os']);
+ }
+ $dep = array('name' => $name);
+ if ($conflicts) {
+ $dep['conflicts'] = '';
+ }
+ if ($this->getPackageType() == 'extsrc' || $this->getPackageType() == 'zendextsrc') {
+ $r = $this->_mergeTag($r, $dep,
+ array(
+ 'installconditions' => array('configureoption', 'binarypackage',
+ 'filelist'),
+ 'os' => array('arch')
+ ));
+ } else {
+ $r = $this->_mergeTag($r, $dep,
+ array(
+ 'installconditions' => array('filelist'),
+ 'os' => array('arch')
+ ));
+ }
+ }
+
+ /**
+ * Set an installation condition based on architecture for the current release set
+ * @param string architecture pattern
+ * @param bool whether this arch is incompatible with the current release
+ */
+ function setArchInstallCondition($pattern, $conflicts = false)
+ {
+ $r = &$this->_getCurrentRelease();
+ if ($r === null) {
+ return false;
+ }
+ $this->_isValid = 0;
+ if (isset($r['installconditions']['arch'])) {
+ unset($r['installconditions']['arch']);
+ }
+ $dep = array('pattern' => $pattern);
+ if ($conflicts) {
+ $dep['conflicts'] = '';
+ }
+ if ($this->getPackageType() == 'extsrc' || $this->getPackageType() == 'zendextsrc') {
+ $r = $this->_mergeTag($r, $dep,
+ array(
+ 'installconditions' => array('configureoption', 'binarypackage',
+ 'filelist'),
+ 'arch' => array()
+ ));
+ } else {
+ $r = $this->_mergeTag($r, $dep,
+ array(
+ 'installconditions' => array('filelist'),
+ 'arch' => array()
+ ));
+ }
+ }
+
+ /**
+ * For extension binary releases, this is used to specify either the
+ * static URI to a source package, or the package name and channel of the extsrc/zendextsrc
+ * package it is based on.
+ * @param string Package name, or full URI to source package (extsrc/zendextsrc type)
+ */
+ function setSourcePackage($packageOrUri)
+ {
+ $this->_isValid = 0;
+ if (isset($this->_packageInfo['channel'])) {
+ $this->_packageInfo = $this->_insertBefore($this->_packageInfo, array('phprelease',
+ 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease', 'zendextbinrelease',
+ 'bundle', 'changelog'),
+ $packageOrUri, 'srcpackage');
+ } else {
+ $this->_packageInfo = $this->_insertBefore($this->_packageInfo, array('phprelease',
+ 'extsrcrelease', 'extbinrelease', 'zendextsrcrelease', 'zendextbinrelease',
+ 'bundle', 'changelog'), $packageOrUri, 'srcuri');
+ }
+ }
+
+ /**
+ * Generate a valid change log entry from the current package.xml
+ * @param string|false
+ */
+ function generateChangeLogEntry($notes = false)
+ {
+ return array(
+ 'version' =>
+ array(
+ 'release' => $this->getVersion('release'),
+ 'api' => $this->getVersion('api'),
+ ),
+ 'stability' =>
+ $this->getStability(),
+ 'date' => $this->getDate(),
+ 'license' => $this->getLicense(true),
+ 'notes' => $notes ? $notes : $this->getNotes()
+ );
+ }
+
+ /**
+ * @param string release version to set change log notes for
+ * @param array output of {@link generateChangeLogEntry()}
+ */
+ function setChangelogEntry($releaseversion, $contents)
+ {
+ if (!isset($this->_packageInfo['changelog'])) {
+ $this->_packageInfo['changelog']['release'] = $contents;
+ return;
+ }
+ if (!isset($this->_packageInfo['changelog']['release'][0])) {
+ if ($this->_packageInfo['changelog']['release']['version']['release'] == $releaseversion) {
+ $this->_packageInfo['changelog']['release'] = array(
+ $this->_packageInfo['changelog']['release']);
+ } else {
+ $this->_packageInfo['changelog']['release'] = array(
+ $this->_packageInfo['changelog']['release']);
+ return $this->_packageInfo['changelog']['release'][] = $contents;
+ }
+ }
+ foreach($this->_packageInfo['changelog']['release'] as $index => $changelog) {
+ if (isset($changelog['version']) &&
+ strnatcasecmp($changelog['version']['release'], $releaseversion) == 0) {
+ $curlog = $index;
+ }
+ }
+ if (isset($curlog)) {
+ $this->_packageInfo['changelog']['release'][$curlog] = $contents;
+ } else {
+ $this->_packageInfo['changelog']['release'][] = $contents;
+ }
+ }
+
+ /**
+ * Remove the changelog entirely
+ */
+ function clearChangeLog()
+ {
+ unset($this->_packageInfo['changelog']);
+ }
+}
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Packager.php b/vendor/pear-pear.php.net/PEAR/PEAR/Packager.php
new file mode 100644
index 000000000..713bc708c
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Packager.php
@@ -0,0 +1,200 @@
+
+ * @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/Common.php';
+require_once 'PEAR/PackageFile.php';
+require_once 'System.php';
+
+/**
+ * Administration class used to make a PEAR release tarball.
+ *
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 0.1
+ */
+class PEAR_Packager extends PEAR_Common
+{
+ /**
+ * @var PEAR_Registry
+ */
+ var $_registry;
+
+ function package($pkgfile = null, $compress = true, $pkg2 = null)
+ {
+ // {{{ validate supplied package.xml file
+ if (empty($pkgfile)) {
+ $pkgfile = 'package.xml';
+ }
+
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $pkg = new PEAR_PackageFile($this->config, $this->debug);
+ $pf = &$pkg->fromPackageFile($pkgfile, PEAR_VALIDATE_NORMAL);
+ $main = &$pf;
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($pf)) {
+ if (is_array($pf->getUserInfo())) {
+ foreach ($pf->getUserInfo() as $error) {
+ $this->log(0, 'Error: ' . $error['message']);
+ }
+ }
+
+ $this->log(0, $pf->getMessage());
+ return $this->raiseError("Cannot package, errors in package file");
+ }
+
+ foreach ($pf->getValidationWarnings() as $warning) {
+ $this->log(1, 'Warning: ' . $warning['message']);
+ }
+
+ // }}}
+ if ($pkg2) {
+ $this->log(0, 'Attempting to process the second package file');
+ PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
+ $pf2 = &$pkg->fromPackageFile($pkg2, PEAR_VALIDATE_NORMAL);
+ PEAR::staticPopErrorHandling();
+ if (PEAR::isError($pf2)) {
+ if (is_array($pf2->getUserInfo())) {
+ foreach ($pf2->getUserInfo() as $error) {
+ $this->log(0, 'Error: ' . $error['message']);
+ }
+ }
+ $this->log(0, $pf2->getMessage());
+ return $this->raiseError("Cannot package, errors in second package file");
+ }
+
+ foreach ($pf2->getValidationWarnings() as $warning) {
+ $this->log(1, 'Warning: ' . $warning['message']);
+ }
+
+ if ($pf2->getPackagexmlVersion() == '2.0' ||
+ $pf2->getPackagexmlVersion() == '2.1'
+ ) {
+ $main = &$pf2;
+ $other = &$pf;
+ } else {
+ $main = &$pf;
+ $other = &$pf2;
+ }
+
+ if ($main->getPackagexmlVersion() != '2.0' &&
+ $main->getPackagexmlVersion() != '2.1') {
+ return PEAR::raiseError('Error: cannot package two package.xml version 1.0, can ' .
+ 'only package together a package.xml 1.0 and package.xml 2.0');
+ }
+
+ if ($other->getPackagexmlVersion() != '1.0') {
+ return PEAR::raiseError('Error: cannot package two package.xml version 2.0, can ' .
+ 'only package together a package.xml 1.0 and package.xml 2.0');
+ }
+ }
+
+ $main->setLogger($this);
+ if (!$main->validate(PEAR_VALIDATE_PACKAGING)) {
+ foreach ($main->getValidationWarnings() as $warning) {
+ $this->log(0, 'Error: ' . $warning['message']);
+ }
+ return $this->raiseError("Cannot package, errors in package");
+ }
+
+ foreach ($main->getValidationWarnings() as $warning) {
+ $this->log(1, 'Warning: ' . $warning['message']);
+ }
+
+ if ($pkg2) {
+ $other->setLogger($this);
+ $a = false;
+ if (!$other->validate(PEAR_VALIDATE_NORMAL) || $a = !$main->isEquivalent($other)) {
+ foreach ($other->getValidationWarnings() as $warning) {
+ $this->log(0, 'Error: ' . $warning['message']);
+ }
+
+ foreach ($main->getValidationWarnings() as $warning) {
+ $this->log(0, 'Error: ' . $warning['message']);
+ }
+
+ if ($a) {
+ return $this->raiseError('The two package.xml files are not equivalent!');
+ }
+
+ return $this->raiseError("Cannot package, errors in package");
+ }
+
+ foreach ($other->getValidationWarnings() as $warning) {
+ $this->log(1, 'Warning: ' . $warning['message']);
+ }
+
+ $gen = &$main->getDefaultGenerator();
+ $tgzfile = $gen->toTgz2($this, $other, $compress);
+ if (PEAR::isError($tgzfile)) {
+ return $tgzfile;
+ }
+
+ $dest_package = basename($tgzfile);
+ $pkgdir = dirname($pkgfile);
+
+ // TAR the Package -------------------------------------------
+ $this->log(1, "Package $dest_package done");
+ if (file_exists("$pkgdir/CVS/Root")) {
+ $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $pf->getVersion());
+ $cvstag = "RELEASE_$cvsversion";
+ $this->log(1, 'Tag the released code with "pear cvstag ' .
+ $main->getPackageFile() . '"');
+ $this->log(1, "(or set the CVS tag $cvstag by hand)");
+ } elseif (file_exists("$pkgdir/.svn")) {
+ $svnversion = preg_replace('/[^a-z0-9]/i', '.', $pf->getVersion());
+ $svntag = $pf->getName() . "-$svnversion";
+ $this->log(1, 'Tag the released code with "pear svntag ' .
+ $main->getPackageFile() . '"');
+ $this->log(1, "(or set the SVN tag $svntag by hand)");
+ }
+ } else { // this branch is executed for single packagefile packaging
+ $gen = &$pf->getDefaultGenerator();
+ $tgzfile = $gen->toTgz($this, $compress);
+ if (PEAR::isError($tgzfile)) {
+ $this->log(0, $tgzfile->getMessage());
+ return $this->raiseError("Cannot package, errors in package");
+ }
+
+ $dest_package = basename($tgzfile);
+ $pkgdir = dirname($pkgfile);
+
+ // TAR the Package -------------------------------------------
+ $this->log(1, "Package $dest_package done");
+ if (file_exists("$pkgdir/CVS/Root")) {
+ $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $pf->getVersion());
+ $cvstag = "RELEASE_$cvsversion";
+ $this->log(1, "Tag the released code with `pear cvstag $pkgfile'");
+ $this->log(1, "(or set the CVS tag $cvstag by hand)");
+ } elseif (file_exists("$pkgdir/.svn")) {
+ $svnversion = preg_replace('/[^a-z0-9]/i', '.', $pf->getVersion());
+ $svntag = $pf->getName() . "-$svnversion";
+ $this->log(1, "Tag the released code with `pear svntag $pkgfile'");
+ $this->log(1, "(or set the SVN tag $svntag by hand)");
+ }
+ }
+
+ return $dest_package;
+ }
+}
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Proxy.php b/vendor/pear-pear.php.net/PEAR/PEAR/Proxy.php
new file mode 100644
index 000000000..d350d5b9a
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Proxy.php
@@ -0,0 +1,187 @@
+config = $config;
+ $this->_parseProxyInfo();
+ }
+
+ /**
+ * @access private
+ */
+ function _parseProxyInfo()
+ {
+ $this->proxy_host = $this->proxy_port = $this->proxy_user = $this->proxy_pass = '';
+ if ($this->config->get('http_proxy')&&
+ $proxy = parse_url($this->config->get('http_proxy'))
+ ) {
+ $this->proxy_host = isset($proxy['host']) ? $proxy['host'] : null;
+
+ $this->proxy_port = isset($proxy['port']) ? $proxy['port'] : 8080;
+ $this->proxy_user = isset($proxy['user']) ? urldecode($proxy['user']) : null;
+ $this->proxy_pass = isset($proxy['pass']) ? urldecode($proxy['pass']) : null;
+ $this->proxy_schema = (isset($proxy['scheme']) && $proxy['scheme'] == 'https') ? 'https' : 'http';
+ }
+ }
+
+ /**
+ * @access private
+ */
+ function _httpConnect($fp, $host, $port)
+ {
+ fwrite($fp, "CONNECT $host:$port HTTP/1.1\r\n");
+ fwrite($fp, "Host: $host:$port\r\n\r\n");
+
+ while ($line = trim(fgets($fp, 1024))) {
+ if (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) {
+ $code = (int)$matches[1];
+
+ /* as per RFC 2817 */
+ if ($code < 200 || $code >= 300) {
+ return PEAR::raiseError("Establishing a CONNECT tunnel through proxy failed with response code $code");
+ }
+ }
+ }
+
+ // connection was successful -- establish SSL through
+ // the tunnel
+ $crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT;
+
+ if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) {
+ $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
+ $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
+ }
+
+ // set the correct hostname for working hostname
+ // verification
+ stream_context_set_option($fp, 'ssl', 'peer_name', $host);
+
+ // blocking socket needed for
+ // stream_socket_enable_crypto()
+ // see
+ //
+ stream_set_blocking ($fp, true);
+ $crypto_res = stream_socket_enable_crypto($fp, true, $crypto_method);
+ if (!$crypto_res) {
+ return PEAR::raiseError("Could not establish SSL connection through proxy $proxy_host:$proxy_port: $crypto_res");
+ }
+
+ return true;
+ }
+
+ /**
+ * get the authorization information for the proxy, encoded to be
+ * passed in the Proxy-Authentication HTTP header.
+ * @return null|string the encoded authentication information if a
+ * proxy and authentication is configured, null
+ * otherwise.
+ */
+ function getProxyAuth()
+ {
+ if ($this->isProxyConfigured() && $this->proxy_user != '') {
+ return base64_encode($this->proxy_user . ':' . $this->proxy_pass);
+ }
+ return null;
+ }
+
+ function getProxyUser()
+ {
+ return $this->proxy_user;
+ }
+
+ /**
+ * Check if we are configured to use a proxy.
+ *
+ * @return boolean true if we are configured to use a proxy, false
+ * otherwise.
+ * @access public
+ */
+ function isProxyConfigured()
+ {
+ return $this->proxy_host != '';
+ }
+
+ /**
+ * Open a socket to a remote server, possibly involving a HTTP
+ * proxy.
+ *
+ * If an HTTP proxy has been configured (http_proxy PEAR_Config
+ * setting), the proxy will be used.
+ *
+ * @param string $host the host to connect to
+ * @param string $port the port to connect to
+ * @param boolean $secure if true, establish a secure connection
+ * using TLS.
+ * @access public
+ */
+ function openSocket($host, $port, $secure = false)
+ {
+ if ($this->isProxyConfigured()) {
+ $fp = @fsockopen(
+ $this->proxy_host, $this->proxy_port,
+ $errno, $errstr, 15
+ );
+
+ if (!$fp) {
+ return PEAR::raiseError("Connection to `$proxy_host:$proxy_port' failed: $errstr", -9276);
+ }
+
+ /* HTTPS is to be used and we have a proxy, use CONNECT verb */
+ if ($secure) {
+ $res = $this->_httpConnect($fp, $host, $port);
+
+ if (PEAR::isError($res)) {
+ return $res;
+ }
+ }
+ } else {
+ if ($secure) {
+ $host = 'ssl://' . $host;
+ }
+
+ $fp = @fsockopen($host, $port, $errno, $errstr);
+ if (!$fp) {
+ return PEAR::raiseError("Connection to `$host:$port' failed: $errstr", $errno);
+ }
+ }
+
+ return $fp;
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/REST.php b/vendor/pear-pear.php.net/PEAR/PEAR/REST.php
new file mode 100644
index 000000000..aec7cf234
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/REST.php
@@ -0,0 +1,475 @@
+
+ * @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 downloading xml files
+ */
+require_once 'PEAR.php';
+require_once 'PEAR/XMLParser.php';
+require_once 'PEAR/Proxy.php';
+
+/**
+ * Intelligently retrieve data, following hyperlinks if necessary, and re-directing
+ * as well
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_REST
+{
+ var $config;
+ var $_options;
+
+ function __construct(&$config, $options = array())
+ {
+ $this->config = &$config;
+ $this->_options = $options;
+ }
+
+ /**
+ * Retrieve REST data, but always retrieve the local cache if it is available.
+ *
+ * This is useful for elements that should never change, such as information on a particular
+ * release
+ * @param string full URL to this resource
+ * @param array|false contents of the accept-encoding header
+ * @param boolean if true, xml will be returned as a string, otherwise, xml will be
+ * parsed using PEAR_XMLParser
+ * @return string|array
+ */
+ function retrieveCacheFirst($url, $accept = false, $forcestring = false, $channel = false)
+ {
+ $cachefile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR .
+ md5($url) . 'rest.cachefile';
+
+ if (file_exists($cachefile)) {
+ return unserialize(implode('', file($cachefile)));
+ }
+
+ return $this->retrieveData($url, $accept, $forcestring, $channel);
+ }
+
+ /**
+ * Retrieve a remote REST resource
+ * @param string full URL to this resource
+ * @param array|false contents of the accept-encoding header
+ * @param boolean if true, xml will be returned as a string, otherwise, xml will be
+ * parsed using PEAR_XMLParser
+ * @return string|array
+ */
+ function retrieveData($url, $accept = false, $forcestring = false, $channel = false)
+ {
+ $cacheId = $this->getCacheId($url);
+ if ($ret = $this->useLocalCache($url, $cacheId)) {
+ return $ret;
+ }
+
+ $file = $trieddownload = false;
+ if (!isset($this->_options['offline'])) {
+ $trieddownload = true;
+ $file = $this->downloadHttp($url, $cacheId ? $cacheId['lastChange'] : false, $accept, $channel);
+ }
+
+ if (PEAR::isError($file)) {
+ if ($file->getCode() !== -9276) {
+ return $file;
+ }
+
+ $trieddownload = false;
+ $file = false; // use local copy if available on socket connect error
+ }
+
+ if (!$file) {
+ $ret = $this->getCache($url);
+ if (!PEAR::isError($ret) && $trieddownload) {
+ // reset the age of the cache if the server says it was unmodified
+ $result = $this->saveCache($url, $ret, null, true, $cacheId);
+ if (PEAR::isError($result)) {
+ return PEAR::raiseError($result->getMessage());
+ }
+ }
+
+ return $ret;
+ }
+
+ if (is_array($file)) {
+ $headers = $file[2];
+ $lastmodified = $file[1];
+ $content = $file[0];
+ } else {
+ $headers = array();
+ $lastmodified = false;
+ $content = $file;
+ }
+
+ if ($forcestring) {
+ $result = $this->saveCache($url, $content, $lastmodified, false, $cacheId);
+ if (PEAR::isError($result)) {
+ return PEAR::raiseError($result->getMessage());
+ }
+
+ return $content;
+ }
+
+ if (isset($headers['content-type'])) {
+ $content_type = explode(";", $headers['content-type']);
+ $content_type = $content_type[0];
+ switch ($content_type) {
+ case 'text/xml' :
+ case 'application/xml' :
+ case 'text/plain' :
+ if ($content_type === 'text/plain') {
+ $check = substr($content, 0, 5);
+ if ($check !== 'parse($content);
+ PEAR::popErrorHandling();
+ if (PEAR::isError($err)) {
+ return PEAR::raiseError('Invalid xml downloaded from "' . $url . '": ' .
+ $err->getMessage());
+ }
+ $content = $parser->getData();
+ case 'text/html' :
+ default :
+ // use it as a string
+ }
+ } else {
+ // assume XML
+ $parser = new PEAR_XMLParser;
+ $parser->parse($content);
+ $content = $parser->getData();
+ }
+
+ $result = $this->saveCache($url, $content, $lastmodified, false, $cacheId);
+ if (PEAR::isError($result)) {
+ return PEAR::raiseError($result->getMessage());
+ }
+
+ return $content;
+ }
+
+ function useLocalCache($url, $cacheid = null)
+ {
+ if ($cacheid === null) {
+ $cacheidfile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR .
+ md5($url) . 'rest.cacheid';
+ if (!file_exists($cacheidfile)) {
+ return false;
+ }
+
+ $cacheid = unserialize(implode('', file($cacheidfile)));
+ }
+
+ $cachettl = $this->config->get('cache_ttl');
+ // If cache is newer than $cachettl seconds, we use the cache!
+ if (time() - $cacheid['age'] < $cachettl) {
+ return $this->getCache($url);
+ }
+
+ return false;
+ }
+
+ function getCacheId($url)
+ {
+ $cacheidfile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR .
+ md5($url) . 'rest.cacheid';
+
+ if (!file_exists($cacheidfile)) {
+ return false;
+ }
+
+ $ret = unserialize(implode('', file($cacheidfile)));
+ return $ret;
+ }
+
+ function getCache($url)
+ {
+ $cachefile = $this->config->get('cache_dir') . DIRECTORY_SEPARATOR .
+ md5($url) . 'rest.cachefile';
+
+ if (!file_exists($cachefile)) {
+ return PEAR::raiseError('No cached content available for "' . $url . '"');
+ }
+
+ return unserialize(implode('', file($cachefile)));
+ }
+
+ /**
+ * @param string full URL to REST resource
+ * @param string original contents of the REST resource
+ * @param array HTTP Last-Modified and ETag headers
+ * @param bool if true, then the cache id file should be regenerated to
+ * trigger a new time-to-live value
+ */
+ function saveCache($url, $contents, $lastmodified, $nochange = false, $cacheid = null)
+ {
+ $cache_dir = $this->config->get('cache_dir');
+ $d = $cache_dir . DIRECTORY_SEPARATOR . md5($url);
+ $cacheidfile = $d . 'rest.cacheid';
+ $cachefile = $d . 'rest.cachefile';
+
+ if (!is_dir($cache_dir)) {
+ if (System::mkdir(array('-p', $cache_dir)) === false) {
+ return PEAR::raiseError("The value of config option cache_dir ($cache_dir) is not a directory and attempts to create the directory failed.");
+ }
+ }
+
+ if (!is_writeable($cache_dir)) {
+ // If writing to the cache dir is not going to work, silently do nothing.
+ // An ugly hack, but retains compat with PEAR 1.9.1 where many commands
+ // work fine as non-root user (w/out write access to default cache dir).
+ return true;
+ }
+
+ if ($cacheid === null && $nochange) {
+ $cacheid = unserialize(implode('', file($cacheidfile)));
+ }
+
+ $idData = serialize(array(
+ 'age' => time(),
+ 'lastChange' => ($nochange ? $cacheid['lastChange'] : $lastmodified),
+ ));
+
+ $result = $this->saveCacheFile($cacheidfile, $idData);
+ if (PEAR::isError($result)) {
+ return $result;
+ } elseif ($nochange) {
+ return true;
+ }
+
+ $result = $this->saveCacheFile($cachefile, serialize($contents));
+ if (PEAR::isError($result)) {
+ if (file_exists($cacheidfile)) {
+ @unlink($cacheidfile);
+ }
+
+ return $result;
+ }
+
+ return true;
+ }
+
+ function saveCacheFile($file, $contents)
+ {
+ $len = strlen($contents);
+
+ $cachefile_fp = @fopen($file, 'xb'); // x is the O_CREAT|O_EXCL mode
+ if ($cachefile_fp !== false) { // create file
+ if (fwrite($cachefile_fp, $contents, $len) < $len) {
+ fclose($cachefile_fp);
+ return PEAR::raiseError("Could not write $file.");
+ }
+ } else { // update file
+ $cachefile_fp = @fopen($file, 'r+b'); // do not truncate file
+ if (!$cachefile_fp) {
+ return PEAR::raiseError("Could not open $file for writing.");
+ }
+
+ if (OS_WINDOWS) {
+ $not_symlink = !is_link($file); // see bug #18834
+ } else {
+ $cachefile_lstat = lstat($file);
+ $cachefile_fstat = fstat($cachefile_fp);
+ $not_symlink = $cachefile_lstat['mode'] == $cachefile_fstat['mode']
+ && $cachefile_lstat['ino'] == $cachefile_fstat['ino']
+ && $cachefile_lstat['dev'] == $cachefile_fstat['dev']
+ && $cachefile_fstat['nlink'] === 1;
+ }
+
+ if ($not_symlink) {
+ ftruncate($cachefile_fp, 0); // NOW truncate
+ if (fwrite($cachefile_fp, $contents, $len) < $len) {
+ fclose($cachefile_fp);
+ return PEAR::raiseError("Could not write $file.");
+ }
+ } else {
+ fclose($cachefile_fp);
+ $link = function_exists('readlink') ? readlink($file) : $file;
+ return PEAR::raiseError('SECURITY ERROR: Will not write to ' . $file . ' as it is symlinked to ' . $link . ' - Possible symlink attack');
+ }
+ }
+
+ fclose($cachefile_fp);
+ return true;
+ }
+
+ /**
+ * Efficiently Download a file through HTTP. Returns downloaded file as a string in-memory
+ * This is best used for small files
+ *
+ * If an HTTP proxy has been configured (http_proxy PEAR_Config
+ * setting), the proxy will be used.
+ *
+ * @param string $url the URL to download
+ * @param string $save_dir directory to save file in
+ * @param false|string|array $lastmodified header values to check against for caching
+ * use false to return the header values from this download
+ * @param false|array $accept Accept headers to send
+ * @return string|array Returns the contents of the downloaded file or a PEAR
+ * error on failure. If the error is caused by
+ * socket-related errors, the error object will
+ * have the fsockopen error code available through
+ * getCode(). If caching is requested, then return the header
+ * values.
+ *
+ * @access public
+ */
+ function downloadHttp($url, $lastmodified = null, $accept = false, $channel = false)
+ {
+ static $redirect = 0;
+ // always reset , so we are clean case of error
+ $wasredirect = $redirect;
+ $redirect = 0;
+
+ $info = parse_url($url);
+ if (!isset($info['scheme']) || !in_array($info['scheme'], array('http', 'https'))) {
+ return PEAR::raiseError('Cannot download non-http URL "' . $url . '"');
+ }
+
+ if (!isset($info['host'])) {
+ return PEAR::raiseError('Cannot download from non-URL "' . $url . '"');
+ }
+
+ $host = isset($info['host']) ? $info['host'] : null;
+ $port = isset($info['port']) ? $info['port'] : null;
+ $path = isset($info['path']) ? $info['path'] : null;
+ $schema = (isset($info['scheme']) && $info['scheme'] == 'https') ? 'https' : 'http';
+
+ $proxy = new PEAR_Proxy($this->config);
+
+ if (empty($port)) {
+ $port = (isset($info['scheme']) && $info['scheme'] == 'https') ? 443 : 80;
+ }
+
+ if ($proxy->isProxyConfigured() && $schema === 'http') {
+ $request = "GET $url HTTP/1.1\r\n";
+ } else {
+ $request = "GET $path HTTP/1.1\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";
+
+ $username = $this->config->get('username', null, $channel);
+ $password = $this->config->get('password', null, $channel);
+
+ if ($username && $password) {
+ $tmp = base64_encode("$username:$password");
+ $request .= "Authorization: Basic $tmp\r\n";
+ }
+
+ $proxyAuth = $proxy->getProxyAuth();
+ if ($proxyAuth) {
+ $request .= 'Proxy-Authorization: Basic ' .
+ $proxyAuth . "\r\n";
+ }
+
+ if ($accept) {
+ $request .= 'Accept: ' . implode(', ', $accept) . "\r\n";
+ }
+
+ $request .= "Accept-Encoding:\r\n";
+ $request .= "Connection: close\r\n";
+ $request .= "\r\n";
+
+ $secure = ($schema == 'https');
+ $fp = $proxy->openSocket($host, $port, $secure);
+ if (PEAR::isError($fp)) {
+ return $fp;
+ }
+
+ fwrite($fp, $request);
+
+ $headers = array();
+ $reply = 0;
+ while ($line = trim(fgets($fp, 1024))) {
+ if (preg_match('/^([^:]+):\s+(.*)\s*\\z/', $line, $matches)) {
+ $headers[strtolower($matches[1])] = trim($matches[2]);
+ } elseif (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) {
+ $reply = (int)$matches[1];
+ if ($reply == 304 && ($lastmodified || ($lastmodified === false))) {
+ return false;
+ }
+
+ if (!in_array($reply, array(200, 301, 302, 303, 305, 307))) {
+ return PEAR::raiseError("File $schema://$host:$port$path not valid (received: $line)");
+ }
+ }
+ }
+
+ if ($reply != 200) {
+ if (!isset($headers['location'])) {
+ return PEAR::raiseError("File $schema://$host:$port$path not valid (redirected but no location)");
+ }
+
+ if ($wasredirect > 4) {
+ return PEAR::raiseError("File $schema://$host:$port$path not valid (redirection looped more than 5 times)");
+ }
+
+ $redirect = $wasredirect + 1;
+ return $this->downloadHttp($headers['location'], $lastmodified, $accept, $channel);
+ }
+
+ $length = isset($headers['content-length']) ? $headers['content-length'] : -1;
+
+ $data = '';
+ while ($chunk = @fread($fp, 8192)) {
+ $data .= $chunk;
+ }
+ fclose($fp);
+
+ if ($lastmodified === false || $lastmodified) {
+ if (isset($headers['etag'])) {
+ $lastmodified = array('ETag' => $headers['etag']);
+ }
+
+ if (isset($headers['last-modified'])) {
+ if (is_array($lastmodified)) {
+ $lastmodified['Last-Modified'] = $headers['last-modified'];
+ } else {
+ $lastmodified = $headers['last-modified'];
+ }
+ }
+
+ return array($data, $lastmodified, $headers);
+ }
+
+ return $data;
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/REST/10.php b/vendor/pear-pear.php.net/PEAR/PEAR/REST/10.php
new file mode 100644
index 000000000..ac0aeab3a
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/REST/10.php
@@ -0,0 +1,870 @@
+
+ * @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.0a12
+ */
+
+/**
+ * For downloading REST xml/txt files
+ */
+require_once 'PEAR/REST.php';
+
+/**
+ * Implement REST 1.0
+ *
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a12
+ */
+class PEAR_REST_10
+{
+ /**
+ * @var PEAR_REST
+ */
+ var $_rest;
+ function __construct($config, $options = array())
+ {
+ $this->_rest = new PEAR_REST($config, $options);
+ }
+
+ /**
+ * Retrieve information about a remote package to be downloaded from a REST server
+ *
+ * @param string $base The uri to prepend to all REST calls
+ * @param array $packageinfo an array of format:
+ *
+ * array(
+ * 'package' => 'packagename',
+ * 'channel' => 'channelname',
+ * ['state' => 'alpha' (or valid state),]
+ * -or-
+ * ['version' => '1.whatever']
+ *
+ * @param string $prefstate Current preferred_state config variable value
+ * @param bool $installed the installed version of this package to compare against
+ * @return array|false|PEAR_Error see {@link _returnDownloadURL()}
+ */
+ function getDownloadURL($base, $packageinfo, $prefstate, $installed, $channel = false)
+ {
+ $states = $this->betterStates($prefstate, true);
+ if (!$states) {
+ return PEAR::raiseError('"' . $prefstate . '" is not a valid state');
+ }
+
+ $channel = $packageinfo['channel'];
+ $package = $packageinfo['package'];
+ $state = isset($packageinfo['state']) ? $packageinfo['state'] : null;
+ $version = isset($packageinfo['version']) ? $packageinfo['version'] : null;
+ $restFile = $base . 'r/' . strtolower($package) . '/allreleases.xml';
+
+ $info = $this->_rest->retrieveData($restFile, false, false, $channel);
+ if (PEAR::isError($info)) {
+ return PEAR::raiseError('No releases available for package "' .
+ $channel . '/' . $package . '"');
+ }
+
+ if (!isset($info['r'])) {
+ return false;
+ }
+
+ $release = $found = false;
+ if (!is_array($info['r']) || !isset($info['r'][0])) {
+ $info['r'] = array($info['r']);
+ }
+
+ foreach ($info['r'] as $release) {
+ if (!isset($this->_rest->_options['force']) && ($installed &&
+ version_compare($release['v'], $installed, '<'))) {
+ continue;
+ }
+
+ if (isset($state)) {
+ // try our preferred state first
+ if ($release['s'] == $state) {
+ $found = true;
+ break;
+ }
+ // see if there is something newer and more stable
+ // bug #7221
+ if (in_array($release['s'], $this->betterStates($state), true)) {
+ $found = true;
+ break;
+ }
+ } elseif (isset($version)) {
+ if ($release['v'] == $version) {
+ $found = true;
+ break;
+ }
+ } else {
+ if (in_array($release['s'], $states)) {
+ $found = true;
+ break;
+ }
+ }
+ }
+
+ return $this->_returnDownloadURL($base, $package, $release, $info, $found, false, $channel);
+ }
+
+ function getDepDownloadURL($base, $xsdversion, $dependency, $deppackage,
+ $prefstate = 'stable', $installed = false, $channel = false)
+ {
+ $states = $this->betterStates($prefstate, true);
+ if (!$states) {
+ return PEAR::raiseError('"' . $prefstate . '" is not a valid state');
+ }
+
+ $channel = $dependency['channel'];
+ $package = $dependency['name'];
+ $state = isset($dependency['state']) ? $dependency['state'] : null;
+ $version = isset($dependency['version']) ? $dependency['version'] : null;
+ $restFile = $base . 'r/' . strtolower($package) . '/allreleases.xml';
+
+ $info = $this->_rest->retrieveData($restFile, false, false, $channel);
+ if (PEAR::isError($info)) {
+ return PEAR::raiseError('Package "' . $deppackage['channel'] . '/' . $deppackage['package']
+ . '" dependency "' . $channel . '/' . $package . '" has no releases');
+ }
+
+ if (!is_array($info) || !isset($info['r'])) {
+ return false;
+ }
+
+ $exclude = array();
+ $min = $max = $recommended = false;
+ if ($xsdversion == '1.0') {
+ switch ($dependency['rel']) {
+ case 'ge' :
+ $min = $dependency['version'];
+ break;
+ case 'gt' :
+ $min = $dependency['version'];
+ $exclude = array($dependency['version']);
+ break;
+ case 'eq' :
+ $recommended = $dependency['version'];
+ break;
+ case 'lt' :
+ $max = $dependency['version'];
+ $exclude = array($dependency['version']);
+ break;
+ case 'le' :
+ $max = $dependency['version'];
+ break;
+ case 'ne' :
+ $exclude = array($dependency['version']);
+ break;
+ }
+ } else {
+ $min = isset($dependency['min']) ? $dependency['min'] : false;
+ $max = isset($dependency['max']) ? $dependency['max'] : false;
+ $recommended = isset($dependency['recommended']) ?
+ $dependency['recommended'] : false;
+ if (isset($dependency['exclude'])) {
+ if (!isset($dependency['exclude'][0])) {
+ $exclude = array($dependency['exclude']);
+ }
+ }
+ }
+ $release = $found = false;
+ if (!is_array($info['r']) || !isset($info['r'][0])) {
+ $info['r'] = array($info['r']);
+ }
+ foreach ($info['r'] as $release) {
+ if (!isset($this->_rest->_options['force']) && ($installed &&
+ version_compare($release['v'], $installed, '<'))) {
+ continue;
+ }
+ if (in_array($release['v'], $exclude)) { // skip excluded versions
+ continue;
+ }
+ // allow newer releases to say "I'm OK with the dependent package"
+ if ($xsdversion == '2.0' && isset($release['co'])) {
+ if (!is_array($release['co']) || !isset($release['co'][0])) {
+ $release['co'] = array($release['co']);
+ }
+ foreach ($release['co'] as $entry) {
+ if (isset($entry['x']) && !is_array($entry['x'])) {
+ $entry['x'] = array($entry['x']);
+ } elseif (!isset($entry['x'])) {
+ $entry['x'] = array();
+ }
+ if ($entry['c'] == $deppackage['channel'] &&
+ strtolower($entry['p']) == strtolower($deppackage['package']) &&
+ version_compare($deppackage['version'], $entry['min'], '>=') &&
+ version_compare($deppackage['version'], $entry['max'], '<=') &&
+ !in_array($release['v'], $entry['x'])) {
+ $recommended = $release['v'];
+ break;
+ }
+ }
+ }
+ if ($recommended) {
+ if ($release['v'] != $recommended) { // if we want a specific
+ // version, then skip all others
+ continue;
+ } else {
+ if (!in_array($release['s'], $states)) {
+ // the stability is too low, but we must return the
+ // recommended version if possible
+ return $this->_returnDownloadURL($base, $package, $release, $info, true, false, $channel);
+ }
+ }
+ }
+ if ($min && version_compare($release['v'], $min, 'lt')) { // skip too old versions
+ continue;
+ }
+ if ($max && version_compare($release['v'], $max, 'gt')) { // skip too new versions
+ continue;
+ }
+ if ($installed && version_compare($release['v'], $installed, '<')) {
+ continue;
+ }
+ if (in_array($release['s'], $states)) { // if in the preferred state...
+ $found = true; // ... then use it
+ break;
+ }
+ }
+ return $this->_returnDownloadURL($base, $package, $release, $info, $found, false, $channel);
+ }
+
+ /**
+ * Take raw data and return the array needed for processing a download URL
+ *
+ * @param string $base REST base uri
+ * @param string $package Package name
+ * @param array $release an array of format array('v' => version, 's' => state)
+ * describing the release to download
+ * @param array $info list of all releases as defined by allreleases.xml
+ * @param bool|null $found determines whether the release was found or this is the next
+ * best alternative. If null, then versions were skipped because
+ * of PHP dependency
+ * @return array|PEAR_Error
+ * @access private
+ */
+ function _returnDownloadURL($base, $package, $release, $info, $found, $phpversion = false, $channel = false)
+ {
+ if (!$found) {
+ $release = $info['r'][0];
+ }
+
+ $packageLower = strtolower($package);
+ $pinfo = $this->_rest->retrieveCacheFirst($base . 'p/' . $packageLower . '/' .
+ 'info.xml', false, false, $channel);
+ if (PEAR::isError($pinfo)) {
+ return PEAR::raiseError('Package "' . $package .
+ '" does not have REST info xml available');
+ }
+
+ $releaseinfo = $this->_rest->retrieveCacheFirst($base . 'r/' . $packageLower . '/' .
+ $release['v'] . '.xml', false, false, $channel);
+ if (PEAR::isError($releaseinfo)) {
+ return PEAR::raiseError('Package "' . $package . '" Version "' . $release['v'] .
+ '" does not have REST xml available');
+ }
+
+ $packagexml = $this->_rest->retrieveCacheFirst($base . 'r/' . $packageLower . '/' .
+ 'deps.' . $release['v'] . '.txt', false, true, $channel);
+ if (PEAR::isError($packagexml)) {
+ return PEAR::raiseError('Package "' . $package . '" Version "' . $release['v'] .
+ '" does not have REST dependency information available');
+ }
+
+ $packagexml = unserialize($packagexml);
+ if (!$packagexml) {
+ $packagexml = array();
+ }
+
+ $allinfo = $this->_rest->retrieveData($base . 'r/' . $packageLower .
+ '/allreleases.xml', false, false, $channel);
+ if (PEAR::isError($allinfo)) {
+ return $allinfo;
+ }
+
+ if (!is_array($allinfo['r']) || !isset($allinfo['r'][0])) {
+ $allinfo['r'] = array($allinfo['r']);
+ }
+
+ $compatible = false;
+ foreach ($allinfo['r'] as $release) {
+ if ($release['v'] != $releaseinfo['v']) {
+ continue;
+ }
+
+ if (!isset($release['co'])) {
+ break;
+ }
+
+ $compatible = array();
+ if (!is_array($release['co']) || !isset($release['co'][0])) {
+ $release['co'] = array($release['co']);
+ }
+
+ foreach ($release['co'] as $entry) {
+ $comp = array();
+ $comp['name'] = $entry['p'];
+ $comp['channel'] = $entry['c'];
+ $comp['min'] = $entry['min'];
+ $comp['max'] = $entry['max'];
+ if (isset($entry['x']) && !is_array($entry['x'])) {
+ $comp['exclude'] = $entry['x'];
+ }
+
+ $compatible[] = $comp;
+ }
+
+ if (count($compatible) == 1) {
+ $compatible = $compatible[0];
+ }
+
+ break;
+ }
+
+ $deprecated = false;
+ if (isset($pinfo['dc']) && isset($pinfo['dp'])) {
+ if (is_array($pinfo['dp'])) {
+ $deprecated = array('channel' => (string) $pinfo['dc'],
+ 'package' => trim($pinfo['dp']['_content']));
+ } else {
+ $deprecated = array('channel' => (string) $pinfo['dc'],
+ 'package' => trim($pinfo['dp']));
+ }
+ }
+
+ $return = array(
+ 'version' => $releaseinfo['v'],
+ 'info' => $packagexml,
+ 'package' => $releaseinfo['p']['_content'],
+ 'stability' => $releaseinfo['st'],
+ 'compatible' => $compatible,
+ 'deprecated' => $deprecated,
+ );
+
+ if ($found) {
+ $return['url'] = $releaseinfo['g'];
+ return $return;
+ }
+
+ $return['php'] = $phpversion;
+ return $return;
+ }
+
+ function listPackages($base, $channel = false)
+ {
+ $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel);
+ if (PEAR::isError($packagelist)) {
+ return $packagelist;
+ }
+
+ if (!is_array($packagelist) || !isset($packagelist['p'])) {
+ return array();
+ }
+
+ if (!is_array($packagelist['p'])) {
+ $packagelist['p'] = array($packagelist['p']);
+ }
+
+ return $packagelist['p'];
+ }
+
+ /**
+ * List all categories of a REST server
+ *
+ * @param string $base base URL of the server
+ * @return array of categorynames
+ */
+ function listCategories($base, $channel = false)
+ {
+ $categories = array();
+
+ // c/categories.xml does not exist;
+ // check for every package its category manually
+ // This is SLOOOWWWW : ///
+ $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel);
+ if (PEAR::isError($packagelist)) {
+ return $packagelist;
+ }
+
+ if (!is_array($packagelist) || !isset($packagelist['p'])) {
+ $ret = array();
+ return $ret;
+ }
+
+ if (!is_array($packagelist['p'])) {
+ $packagelist['p'] = array($packagelist['p']);
+ }
+
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ foreach ($packagelist['p'] as $package) {
+ $inf = $this->_rest->retrieveData($base . 'p/' . strtolower($package) . '/info.xml', false, false, $channel);
+ if (PEAR::isError($inf)) {
+ PEAR::popErrorHandling();
+ return $inf;
+ }
+ $cat = $inf['ca']['_content'];
+ if (!isset($categories[$cat])) {
+ $categories[$cat] = $inf['ca'];
+ }
+ }
+
+ return array_values($categories);
+ }
+
+ /**
+ * List a category of a REST server
+ *
+ * @param string $base base URL of the server
+ * @param string $category name of the category
+ * @param boolean $info also download full package info
+ * @return array of packagenames
+ */
+ function listCategory($base, $category, $info = false, $channel = false)
+ {
+ // gives '404 Not Found' error when category doesn't exist
+ $packagelist = $this->_rest->retrieveData($base.'c/'.urlencode($category).'/packages.xml', false, false, $channel);
+ if (PEAR::isError($packagelist)) {
+ return $packagelist;
+ }
+
+ if (!is_array($packagelist) || !isset($packagelist['p'])) {
+ return array();
+ }
+
+ if (!is_array($packagelist['p']) ||
+ !isset($packagelist['p'][0])) { // only 1 pkg
+ $packagelist = array($packagelist['p']);
+ } else {
+ $packagelist = $packagelist['p'];
+ }
+
+ if ($info == true) {
+ // get individual package info
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ foreach ($packagelist as $i => $packageitem) {
+ $url = sprintf('%s'.'r/%s/latest.txt',
+ $base,
+ strtolower($packageitem['_content']));
+ $version = $this->_rest->retrieveData($url, false, false, $channel);
+ if (PEAR::isError($version)) {
+ break; // skipit
+ }
+ $url = sprintf('%s'.'r/%s/%s.xml',
+ $base,
+ strtolower($packageitem['_content']),
+ $version);
+ $info = $this->_rest->retrieveData($url, false, false, $channel);
+ if (PEAR::isError($info)) {
+ break; // skipit
+ }
+ $packagelist[$i]['info'] = $info;
+ }
+ PEAR::popErrorHandling();
+ }
+
+ return $packagelist;
+ }
+
+
+ function listAll($base, $dostable, $basic = true, $searchpackage = false, $searchsummary = false, $channel = false)
+ {
+ $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel);
+ if (PEAR::isError($packagelist)) {
+ return $packagelist;
+ }
+ if ($this->_rest->config->get('verbose') > 0) {
+ $ui = &PEAR_Frontend::singleton();
+ $ui->log('Retrieving data...0%', true);
+ }
+ $ret = array();
+ if (!is_array($packagelist) || !isset($packagelist['p'])) {
+ return $ret;
+ }
+ if (!is_array($packagelist['p'])) {
+ $packagelist['p'] = array($packagelist['p']);
+ }
+
+ // only search-packagename = quicksearch !
+ if ($searchpackage && (!$searchsummary || empty($searchpackage))) {
+ $newpackagelist = array();
+ foreach ($packagelist['p'] as $package) {
+ if (!empty($searchpackage) && stristr($package, $searchpackage) !== false) {
+ $newpackagelist[] = $package;
+ }
+ }
+ $packagelist['p'] = $newpackagelist;
+ }
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ $next = .1;
+ foreach ($packagelist['p'] as $progress => $package) {
+ if ($this->_rest->config->get('verbose') > 0) {
+ if ($progress / count($packagelist['p']) >= $next) {
+ if ($next == .5) {
+ $ui->log('50%', false);
+ } else {
+ $ui->log('.', false);
+ }
+ $next += .1;
+ }
+ }
+
+ if ($basic) { // remote-list command
+ if ($dostable) {
+ $latest = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
+ '/stable.txt', false, false, $channel);
+ } else {
+ $latest = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
+ '/latest.txt', false, false, $channel);
+ }
+ if (PEAR::isError($latest)) {
+ $latest = false;
+ }
+ $info = array('stable' => $latest);
+ } else { // list-all command
+ $inf = $this->_rest->retrieveData($base . 'p/' . strtolower($package) . '/info.xml', false, false, $channel);
+ if (PEAR::isError($inf)) {
+ PEAR::popErrorHandling();
+ return $inf;
+ }
+ if ($searchpackage) {
+ $found = (!empty($searchpackage) && stristr($package, $searchpackage) !== false);
+ if (!$found && !(isset($searchsummary) && !empty($searchsummary)
+ && (stristr($inf['s'], $searchsummary) !== false
+ || stristr($inf['d'], $searchsummary) !== false)))
+ {
+ continue;
+ };
+ }
+ $releases = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
+ '/allreleases.xml', false, false, $channel);
+ if (PEAR::isError($releases)) {
+ continue;
+ }
+ if (!isset($releases['r'][0])) {
+ $releases['r'] = array($releases['r']);
+ }
+ unset($latest);
+ unset($unstable);
+ unset($stable);
+ unset($state);
+ foreach ($releases['r'] as $release) {
+ if (!isset($latest)) {
+ if ($dostable && $release['s'] == 'stable') {
+ $latest = $release['v'];
+ $state = 'stable';
+ }
+ if (!$dostable) {
+ $latest = $release['v'];
+ $state = $release['s'];
+ }
+ }
+ if (!isset($stable) && $release['s'] == 'stable') {
+ $stable = $release['v'];
+ if (!isset($unstable)) {
+ $unstable = $stable;
+ }
+ }
+ if (!isset($unstable) && $release['s'] != 'stable') {
+ $latest = $unstable = $release['v'];
+ $state = $release['s'];
+ }
+ if (isset($latest) && !isset($state)) {
+ $state = $release['s'];
+ }
+ if (isset($latest) && isset($stable) && isset($unstable)) {
+ break;
+ }
+ }
+ $deps = array();
+ if (!isset($unstable)) {
+ $unstable = false;
+ $state = 'stable';
+ if (isset($stable)) {
+ $latest = $unstable = $stable;
+ }
+ } else {
+ $latest = $unstable;
+ }
+ if (!isset($latest)) {
+ $latest = false;
+ }
+ if ($latest) {
+ $d = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/deps.' .
+ $latest . '.txt', false, false, $channel);
+ if (!PEAR::isError($d)) {
+ $d = unserialize($d);
+ if ($d) {
+ if (isset($d['required'])) {
+ if (!class_exists('PEAR_PackageFile_v2')) {
+ require_once 'PEAR/PackageFile/v2.php';
+ }
+ if (!isset($pf)) {
+ $pf = new PEAR_PackageFile_v2;
+ }
+ $pf->setDeps($d);
+ $tdeps = $pf->getDeps();
+ } else {
+ $tdeps = $d;
+ }
+ foreach ($tdeps as $dep) {
+ if ($dep['type'] !== 'pkg') {
+ continue;
+ }
+ $deps[] = $dep;
+ }
+ }
+ }
+ }
+ if (!isset($stable)) {
+ $stable = '-n/a-';
+ }
+ if (!$searchpackage) {
+ $info = array('stable' => $latest, 'summary' => $inf['s'], 'description' =>
+ $inf['d'], 'deps' => $deps, 'category' => $inf['ca']['_content'],
+ 'unstable' => $unstable, 'state' => $state);
+ } else {
+ $info = array('stable' => $stable, 'summary' => $inf['s'], 'description' =>
+ $inf['d'], 'deps' => $deps, 'category' => $inf['ca']['_content'],
+ 'unstable' => $unstable, 'state' => $state);
+ }
+ }
+ $ret[$package] = $info;
+ }
+ PEAR::popErrorHandling();
+ return $ret;
+ }
+
+ function listLatestUpgrades($base, $pref_state, $installed, $channel, &$reg)
+ {
+ $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel);
+ if (PEAR::isError($packagelist)) {
+ return $packagelist;
+ }
+
+ $ret = array();
+ if (!is_array($packagelist) || !isset($packagelist['p'])) {
+ return $ret;
+ }
+
+ if (!is_array($packagelist['p'])) {
+ $packagelist['p'] = array($packagelist['p']);
+ }
+
+ foreach ($packagelist['p'] as $package) {
+ if (!isset($installed[strtolower($package)])) {
+ continue;
+ }
+
+ $inst_version = $reg->packageInfo($package, 'version', $channel);
+ $inst_state = $reg->packageInfo($package, 'release_state', $channel);
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ $info = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
+ '/allreleases.xml', false, false, $channel);
+ PEAR::popErrorHandling();
+ if (PEAR::isError($info)) {
+ continue; // no remote releases
+ }
+
+ if (!isset($info['r'])) {
+ continue;
+ }
+
+ $release = $found = false;
+ if (!is_array($info['r']) || !isset($info['r'][0])) {
+ $info['r'] = array($info['r']);
+ }
+
+ // $info['r'] is sorted by version number
+ usort($info['r'], array($this, '_sortReleasesByVersionNumber'));
+ foreach ($info['r'] as $release) {
+ if ($inst_version && version_compare($release['v'], $inst_version, '<=')) {
+ // not newer than the one installed
+ break;
+ }
+
+ // new version > installed version
+ if (!$pref_state) {
+ // every state is a good state
+ $found = true;
+ break;
+ } else {
+ $new_state = $release['s'];
+ // if new state >= installed state: go
+ if (in_array($new_state, $this->betterStates($inst_state, true))) {
+ $found = true;
+ break;
+ } else {
+ // only allow to lower the state of package,
+ // if new state >= preferred state: go
+ if (in_array($new_state, $this->betterStates($pref_state, true))) {
+ $found = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!$found) {
+ continue;
+ }
+
+ $relinfo = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/' .
+ $release['v'] . '.xml', false, false, $channel);
+ if (PEAR::isError($relinfo)) {
+ return $relinfo;
+ }
+
+ $ret[$package] = array(
+ 'version' => $release['v'],
+ 'state' => $release['s'],
+ 'filesize' => $relinfo['f'],
+ );
+ }
+
+ return $ret;
+ }
+
+ function packageInfo($base, $package, $channel = false)
+ {
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ $pinfo = $this->_rest->retrieveData($base . 'p/' . strtolower($package) . '/info.xml', false, false, $channel);
+ if (PEAR::isError($pinfo)) {
+ PEAR::popErrorHandling();
+ return PEAR::raiseError('Unknown package: "' . $package . '" in channel "' . $channel . '"' . "\n". 'Debug: ' .
+ $pinfo->getMessage());
+ }
+
+ $releases = array();
+ $allreleases = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
+ '/allreleases.xml', false, false, $channel);
+ if (!PEAR::isError($allreleases)) {
+ if (!class_exists('PEAR_PackageFile_v2')) {
+ require_once 'PEAR/PackageFile/v2.php';
+ }
+
+ if (!is_array($allreleases['r']) || !isset($allreleases['r'][0])) {
+ $allreleases['r'] = array($allreleases['r']);
+ }
+
+ $pf = new PEAR_PackageFile_v2;
+ foreach ($allreleases['r'] as $release) {
+ $ds = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/deps.' .
+ $release['v'] . '.txt', false, false, $channel);
+ if (PEAR::isError($ds)) {
+ continue;
+ }
+
+ if (!isset($latest)) {
+ $latest = $release['v'];
+ }
+
+ $pf->setDeps(unserialize($ds));
+ $ds = $pf->getDeps();
+ $info = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package)
+ . '/' . $release['v'] . '.xml', false, false, $channel);
+
+ if (PEAR::isError($info)) {
+ continue;
+ }
+
+ $releases[$release['v']] = array(
+ 'doneby' => $info['m'],
+ 'license' => $info['l'],
+ 'summary' => $info['s'],
+ 'description' => $info['d'],
+ 'releasedate' => $info['da'],
+ 'releasenotes' => $info['n'],
+ 'state' => $release['s'],
+ 'deps' => $ds ? $ds : array(),
+ );
+ }
+ } else {
+ $latest = '';
+ }
+
+ PEAR::popErrorHandling();
+ if (isset($pinfo['dc']) && isset($pinfo['dp'])) {
+ if (is_array($pinfo['dp'])) {
+ $deprecated = array('channel' => (string) $pinfo['dc'],
+ 'package' => trim($pinfo['dp']['_content']));
+ } else {
+ $deprecated = array('channel' => (string) $pinfo['dc'],
+ 'package' => trim($pinfo['dp']));
+ }
+ } else {
+ $deprecated = false;
+ }
+
+ if (!isset($latest)) {
+ $latest = '';
+ }
+
+ return array(
+ 'name' => $pinfo['n'],
+ 'channel' => $pinfo['c'],
+ 'category' => $pinfo['ca']['_content'],
+ 'stable' => $latest,
+ 'license' => $pinfo['l'],
+ 'summary' => $pinfo['s'],
+ 'description' => $pinfo['d'],
+ 'releases' => $releases,
+ 'deprecated' => $deprecated,
+ );
+ }
+
+ /**
+ * Return 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);
+ }
+
+ /**
+ * Sort releases by version number
+ *
+ * @access private
+ */
+ function _sortReleasesByVersionNumber($a, $b)
+ {
+ if (version_compare($a['v'], $b['v'], '=')) {
+ return 0;
+ }
+
+ if (version_compare($a['v'], $b['v'], '>')) {
+ return -1;
+ }
+
+ if (version_compare($a['v'], $b['v'], '<')) {
+ return 1;
+ }
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/REST/11.php b/vendor/pear-pear.php.net/PEAR/PEAR/REST/11.php
new file mode 100644
index 000000000..a7e713ac4
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/REST/11.php
@@ -0,0 +1,340 @@
+
+ * @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.3
+ */
+
+/**
+ * For downloading REST xml/txt files
+ */
+require_once 'PEAR/REST.php';
+
+/**
+ * Implement REST 1.1
+ *
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.3
+ */
+class PEAR_REST_11
+{
+ /**
+ * @var PEAR_REST
+ */
+ var $_rest;
+
+ function __construct($config, $options = array())
+ {
+ $this->_rest = new PEAR_REST($config, $options);
+ }
+
+ function listAll($base, $dostable, $basic = true, $searchpackage = false, $searchsummary = false, $channel = false)
+ {
+ $categorylist = $this->_rest->retrieveData($base . 'c/categories.xml', false, false, $channel);
+ if (PEAR::isError($categorylist)) {
+ return $categorylist;
+ }
+
+ $ret = array();
+ if (!is_array($categorylist['c']) || !isset($categorylist['c'][0])) {
+ $categorylist['c'] = array($categorylist['c']);
+ }
+
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+
+ foreach ($categorylist['c'] as $progress => $category) {
+ $category = $category['_content'];
+ $packagesinfo = $this->_rest->retrieveData($base .
+ 'c/' . urlencode($category) . '/packagesinfo.xml', false, false, $channel);
+
+ if (PEAR::isError($packagesinfo)) {
+ continue;
+ }
+
+ if (!is_array($packagesinfo) || !isset($packagesinfo['pi'])) {
+ continue;
+ }
+
+ if (!is_array($packagesinfo['pi']) || !isset($packagesinfo['pi'][0])) {
+ $packagesinfo['pi'] = array($packagesinfo['pi']);
+ }
+
+ foreach ($packagesinfo['pi'] as $packageinfo) {
+ if (empty($packageinfo)) {
+ continue;
+ }
+
+ $info = $packageinfo['p'];
+ $package = $info['n'];
+ $releases = isset($packageinfo['a']) ? $packageinfo['a'] : false;
+ unset($latest);
+ unset($unstable);
+ unset($stable);
+ unset($state);
+
+ if ($releases) {
+ if (!isset($releases['r'][0])) {
+ $releases['r'] = array($releases['r']);
+ }
+
+ foreach ($releases['r'] as $release) {
+ if (!isset($latest)) {
+ if ($dostable && $release['s'] == 'stable') {
+ $latest = $release['v'];
+ $state = 'stable';
+ }
+ if (!$dostable) {
+ $latest = $release['v'];
+ $state = $release['s'];
+ }
+ }
+
+ if (!isset($stable) && $release['s'] == 'stable') {
+ $stable = $release['v'];
+ if (!isset($unstable)) {
+ $unstable = $stable;
+ }
+ }
+
+ if (!isset($unstable) && $release['s'] != 'stable') {
+ $unstable = $release['v'];
+ $state = $release['s'];
+ }
+
+ if (isset($latest) && !isset($state)) {
+ $state = $release['s'];
+ }
+
+ if (isset($latest) && isset($stable) && isset($unstable)) {
+ break;
+ }
+ }
+ }
+
+ if ($basic) { // remote-list command
+ if (!isset($latest)) {
+ $latest = false;
+ }
+
+ if ($dostable) {
+ // $state is not set if there are no releases
+ if (isset($state) && $state == 'stable') {
+ $ret[$package] = array('stable' => $latest);
+ } else {
+ $ret[$package] = array('stable' => '-n/a-');
+ }
+ } else {
+ $ret[$package] = array('stable' => $latest);
+ }
+
+ continue;
+ }
+
+ // list-all command
+ if (!isset($unstable)) {
+ $unstable = false;
+ $state = 'stable';
+ if (isset($stable)) {
+ $latest = $unstable = $stable;
+ }
+ } else {
+ $latest = $unstable;
+ }
+
+ if (!isset($latest)) {
+ $latest = false;
+ }
+
+ $deps = array();
+ if ($latest && isset($packageinfo['deps'])) {
+ if (!is_array($packageinfo['deps']) ||
+ !isset($packageinfo['deps'][0])
+ ) {
+ $packageinfo['deps'] = array($packageinfo['deps']);
+ }
+
+ $d = false;
+ foreach ($packageinfo['deps'] as $dep) {
+ if ($dep['v'] == $latest) {
+ $d = unserialize($dep['d']);
+ }
+ }
+
+ if ($d) {
+ if (isset($d['required'])) {
+ if (!class_exists('PEAR_PackageFile_v2')) {
+ require_once 'PEAR/PackageFile/v2.php';
+ }
+
+ if (!isset($pf)) {
+ $pf = new PEAR_PackageFile_v2;
+ }
+
+ $pf->setDeps($d);
+ $tdeps = $pf->getDeps();
+ } else {
+ $tdeps = $d;
+ }
+
+ foreach ($tdeps as $dep) {
+ if ($dep['type'] !== 'pkg') {
+ continue;
+ }
+
+ $deps[] = $dep;
+ }
+ }
+ }
+
+ $info = array(
+ 'stable' => $latest,
+ 'summary' => $info['s'],
+ 'description' => $info['d'],
+ 'deps' => $deps,
+ 'category' => $info['ca']['_content'],
+ 'unstable' => $unstable,
+ 'state' => $state
+ );
+ $ret[$package] = $info;
+ }
+ }
+
+ PEAR::popErrorHandling();
+ return $ret;
+ }
+
+ /**
+ * List all categories of a REST server
+ *
+ * @param string $base base URL of the server
+ * @return array of categorynames
+ */
+ function listCategories($base, $channel = false)
+ {
+ $categorylist = $this->_rest->retrieveData($base . 'c/categories.xml', false, false, $channel);
+ if (PEAR::isError($categorylist)) {
+ return $categorylist;
+ }
+
+ if (!is_array($categorylist) || !isset($categorylist['c'])) {
+ return array();
+ }
+
+ if (isset($categorylist['c']['_content'])) {
+ // only 1 category
+ $categorylist['c'] = array($categorylist['c']);
+ }
+
+ return $categorylist['c'];
+ }
+
+ /**
+ * List packages in a category of a REST server
+ *
+ * @param string $base base URL of the server
+ * @param string $category name of the category
+ * @param boolean $info also download full package info
+ * @return array of packagenames
+ */
+ function listCategory($base, $category, $info = false, $channel = false)
+ {
+ if ($info == false) {
+ $url = '%s'.'c/%s/packages.xml';
+ } else {
+ $url = '%s'.'c/%s/packagesinfo.xml';
+ }
+ $url = sprintf($url,
+ $base,
+ urlencode($category));
+
+ // gives '404 Not Found' error when category doesn't exist
+ $packagelist = $this->_rest->retrieveData($url, false, false, $channel);
+ if (PEAR::isError($packagelist)) {
+ return $packagelist;
+ }
+ if (!is_array($packagelist)) {
+ return array();
+ }
+
+ if ($info == false) {
+ if (!isset($packagelist['p'])) {
+ return array();
+ }
+ if (!is_array($packagelist['p']) ||
+ !isset($packagelist['p'][0])) { // only 1 pkg
+ $packagelist = array($packagelist['p']);
+ } else {
+ $packagelist = $packagelist['p'];
+ }
+ return $packagelist;
+ }
+
+ // info == true
+ if (!isset($packagelist['pi'])) {
+ return array();
+ }
+
+ if (!is_array($packagelist['pi']) ||
+ !isset($packagelist['pi'][0])) { // only 1 pkg
+ $packagelist_pre = array($packagelist['pi']);
+ } else {
+ $packagelist_pre = $packagelist['pi'];
+ }
+
+ $packagelist = array();
+ foreach ($packagelist_pre as $i => $item) {
+ // compatibility with r/.xml
+ if (isset($item['a']['r'][0])) {
+ // multiple releases
+ $item['p']['v'] = $item['a']['r'][0]['v'];
+ $item['p']['st'] = $item['a']['r'][0]['s'];
+ } elseif (isset($item['a'])) {
+ // first and only release
+ $item['p']['v'] = $item['a']['r']['v'];
+ $item['p']['st'] = $item['a']['r']['s'];
+ }
+
+ $packagelist[$i] = array('attribs' => $item['p']['r'],
+ '_content' => $item['p']['n'],
+ 'info' => $item['p']);
+ }
+
+ return $packagelist;
+ }
+
+ /**
+ * Return an array containing all of the states that are more stable than
+ * or equal to the passed in state
+ *
+ * @param string Release state
+ * @param boolean Determines whether to include $state in the list
+ * @return false|array False if $state is not a valid release state
+ */
+ function betterStates($state, $include = false)
+ {
+ static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable');
+ $i = array_search($state, $states);
+ if ($i === false) {
+ return false;
+ }
+ if ($include) {
+ $i--;
+ }
+ return array_slice($states, $i + 1);
+ }
+}
+?>
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/REST/13.php b/vendor/pear-pear.php.net/PEAR/PEAR/REST/13.php
new file mode 100644
index 000000000..6469fd30d
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/REST/13.php
@@ -0,0 +1,396 @@
+
+ * @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.0a12
+ */
+
+/**
+ * For downloading REST xml/txt files
+ */
+require_once 'PEAR/REST.php';
+require_once 'PEAR/REST/10.php';
+
+/**
+ * Implement REST 1.3
+ *
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a12
+ */
+class PEAR_REST_13 extends PEAR_REST_10
+{
+ /**
+ * Retrieve information about a remote package to be downloaded from a REST server
+ *
+ * This is smart enough to resolve the minimum PHP version dependency prior to download
+ * @param string $base The uri to prepend to all REST calls
+ * @param array $packageinfo an array of format:
+ *
+ * array(
+ * 'package' => 'packagename',
+ * 'channel' => 'channelname',
+ * ['state' => 'alpha' (or valid state),]
+ * -or-
+ * ['version' => '1.whatever']
+ *
+ * @param string $prefstate Current preferred_state config variable value
+ * @param bool $installed the installed version of this package to compare against
+ * @return array|false|PEAR_Error see {@link _returnDownloadURL()}
+ */
+ function getDownloadURL($base, $packageinfo, $prefstate, $installed, $channel = false)
+ {
+ $states = $this->betterStates($prefstate, true);
+ if (!$states) {
+ return PEAR::raiseError('"' . $prefstate . '" is not a valid state');
+ }
+
+ $channel = $packageinfo['channel'];
+ $package = $packageinfo['package'];
+ $state = isset($packageinfo['state']) ? $packageinfo['state'] : null;
+ $version = isset($packageinfo['version']) ? $packageinfo['version'] : null;
+ $restFile = $base . 'r/' . strtolower($package) . '/allreleases2.xml';
+
+ $info = $this->_rest->retrieveData($restFile, false, false, $channel);
+ if (PEAR::isError($info)) {
+ return PEAR::raiseError('No releases available for package "' .
+ $channel . '/' . $package . '"');
+ }
+
+ if (!isset($info['r'])) {
+ return false;
+ }
+
+ $release = $found = false;
+ if (!is_array($info['r']) || !isset($info['r'][0])) {
+ $info['r'] = array($info['r']);
+ }
+
+ $skippedphp = false;
+ foreach ($info['r'] as $release) {
+ if (!isset($this->_rest->_options['force']) && ($installed &&
+ version_compare($release['v'], $installed, '<'))) {
+ continue;
+ }
+
+ if (isset($state)) {
+ // try our preferred state first
+ if ($release['s'] == $state) {
+ if (!isset($version) && version_compare($release['m'], phpversion(), '>')) {
+ // skip releases that require a PHP version newer than our PHP version
+ $skippedphp = $release;
+ continue;
+ }
+ $found = true;
+ break;
+ }
+
+ // see if there is something newer and more stable
+ // bug #7221
+ if (in_array($release['s'], $this->betterStates($state), true)) {
+ if (!isset($version) && version_compare($release['m'], phpversion(), '>')) {
+ // skip releases that require a PHP version newer than our PHP version
+ $skippedphp = $release;
+ continue;
+ }
+ $found = true;
+ break;
+ }
+ } elseif (isset($version)) {
+ if ($release['v'] == $version) {
+ if (!isset($this->_rest->_options['force']) &&
+ !isset($version) &&
+ version_compare($release['m'], phpversion(), '>')) {
+ // skip releases that require a PHP version newer than our PHP version
+ $skippedphp = $release;
+ continue;
+ }
+ $found = true;
+ break;
+ }
+ } else {
+ if (in_array($release['s'], $states)) {
+ if (version_compare($release['m'], phpversion(), '>')) {
+ // skip releases that require a PHP version newer than our PHP version
+ $skippedphp = $release;
+ continue;
+ }
+ $found = true;
+ break;
+ }
+ }
+ }
+
+ if (!$found && $skippedphp) {
+ $found = null;
+ }
+
+ return $this->_returnDownloadURL($base, $package, $release, $info, $found, $skippedphp, $channel);
+ }
+
+ function getDepDownloadURL($base, $xsdversion, $dependency, $deppackage,
+ $prefstate = 'stable', $installed = false, $channel = false)
+ {
+ $states = $this->betterStates($prefstate, true);
+ if (!$states) {
+ return PEAR::raiseError('"' . $prefstate . '" is not a valid state');
+ }
+
+ $channel = $dependency['channel'];
+ $package = $dependency['name'];
+ $state = isset($dependency['state']) ? $dependency['state'] : null;
+ $version = isset($dependency['version']) ? $dependency['version'] : null;
+ $restFile = $base . 'r/' . strtolower($package) .'/allreleases2.xml';
+
+ $info = $this->_rest->retrieveData($restFile, false, false, $channel);
+ if (PEAR::isError($info)) {
+ return PEAR::raiseError('Package "' . $deppackage['channel'] . '/' . $deppackage['package']
+ . '" dependency "' . $channel . '/' . $package . '" has no releases');
+ }
+
+ if (!is_array($info) || !isset($info['r'])) {
+ return false;
+ }
+
+ $exclude = array();
+ $min = $max = $recommended = false;
+ if ($xsdversion == '1.0') {
+ $pinfo['package'] = $dependency['name'];
+ $pinfo['channel'] = 'pear.php.net'; // this is always true - don't change this
+ switch ($dependency['rel']) {
+ case 'ge' :
+ $min = $dependency['version'];
+ break;
+ case 'gt' :
+ $min = $dependency['version'];
+ $exclude = array($dependency['version']);
+ break;
+ case 'eq' :
+ $recommended = $dependency['version'];
+ break;
+ case 'lt' :
+ $max = $dependency['version'];
+ $exclude = array($dependency['version']);
+ break;
+ case 'le' :
+ $max = $dependency['version'];
+ break;
+ case 'ne' :
+ $exclude = array($dependency['version']);
+ break;
+ }
+ } else {
+ $pinfo['package'] = $dependency['name'];
+ $min = isset($dependency['min']) ? $dependency['min'] : false;
+ $max = isset($dependency['max']) ? $dependency['max'] : false;
+ $recommended = isset($dependency['recommended']) ?
+ $dependency['recommended'] : false;
+ if (isset($dependency['exclude'])) {
+ if (!isset($dependency['exclude'][0])) {
+ $exclude = array($dependency['exclude']);
+ }
+ }
+ }
+
+ $skippedphp = $found = $release = false;
+ if (!is_array($info['r']) || !isset($info['r'][0])) {
+ $info['r'] = array($info['r']);
+ }
+
+ foreach ($info['r'] as $release) {
+ if (!isset($this->_rest->_options['force']) && ($installed &&
+ version_compare($release['v'], $installed, '<'))) {
+ continue;
+ }
+
+ if (in_array($release['v'], $exclude)) { // skip excluded versions
+ continue;
+ }
+
+ // allow newer releases to say "I'm OK with the dependent package"
+ if ($xsdversion == '2.0' && isset($release['co'])) {
+ if (!is_array($release['co']) || !isset($release['co'][0])) {
+ $release['co'] = array($release['co']);
+ }
+
+ foreach ($release['co'] as $entry) {
+ if (isset($entry['x']) && !is_array($entry['x'])) {
+ $entry['x'] = array($entry['x']);
+ } elseif (!isset($entry['x'])) {
+ $entry['x'] = array();
+ }
+
+ if ($entry['c'] == $deppackage['channel'] &&
+ strtolower($entry['p']) == strtolower($deppackage['package']) &&
+ version_compare($deppackage['version'], $entry['min'], '>=') &&
+ version_compare($deppackage['version'], $entry['max'], '<=') &&
+ !in_array($release['v'], $entry['x'])) {
+ if (version_compare($release['m'], phpversion(), '>')) {
+ // skip dependency releases that require a PHP version
+ // newer than our PHP version
+ $skippedphp = $release;
+ continue;
+ }
+
+ $recommended = $release['v'];
+ break;
+ }
+ }
+ }
+
+ if ($recommended) {
+ if ($release['v'] != $recommended) { // if we want a specific
+ // version, then skip all others
+ continue;
+ }
+
+ if (!in_array($release['s'], $states)) {
+ // the stability is too low, but we must return the
+ // recommended version if possible
+ return $this->_returnDownloadURL($base, $package, $release, $info, true, false, $channel);
+ }
+ }
+
+ if ($min && version_compare($release['v'], $min, 'lt')) { // skip too old versions
+ continue;
+ }
+
+ if ($max && version_compare($release['v'], $max, 'gt')) { // skip too new versions
+ continue;
+ }
+
+ if ($installed && version_compare($release['v'], $installed, '<')) {
+ continue;
+ }
+
+ if (in_array($release['s'], $states)) { // if in the preferred state...
+ if (version_compare($release['m'], phpversion(), '>')) {
+ // skip dependency releases that require a PHP version
+ // newer than our PHP version
+ $skippedphp = $release;
+ continue;
+ }
+
+ $found = true; // ... then use it
+ break;
+ }
+ }
+
+ if (!$found && $skippedphp) {
+ $found = null;
+ }
+
+ return $this->_returnDownloadURL($base, $package, $release, $info, $found, $skippedphp, $channel);
+ }
+
+ /**
+ * List package upgrades but take the PHP version into account.
+ */
+ function listLatestUpgrades($base, $pref_state, $installed, $channel, &$reg)
+ {
+ $packagelist = $this->_rest->retrieveData($base . 'p/packages.xml', false, false, $channel);
+ if (PEAR::isError($packagelist)) {
+ return $packagelist;
+ }
+
+ $ret = array();
+ if (!is_array($packagelist) || !isset($packagelist['p'])) {
+ return $ret;
+ }
+
+ if (!is_array($packagelist['p'])) {
+ $packagelist['p'] = array($packagelist['p']);
+ }
+
+ foreach ($packagelist['p'] as $package) {
+ if (!isset($installed[strtolower($package)])) {
+ continue;
+ }
+
+ $inst_version = $reg->packageInfo($package, 'version', $channel);
+ $inst_state = $reg->packageInfo($package, 'release_state', $channel);
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ $info = $this->_rest->retrieveData($base . 'r/' . strtolower($package) .
+ '/allreleases2.xml', false, false, $channel);
+ PEAR::popErrorHandling();
+ if (PEAR::isError($info)) {
+ continue; // no remote releases
+ }
+
+ if (!isset($info['r'])) {
+ continue;
+ }
+
+ $release = $found = false;
+ if (!is_array($info['r']) || !isset($info['r'][0])) {
+ $info['r'] = array($info['r']);
+ }
+
+ // $info['r'] is sorted by version number
+ usort($info['r'], array($this, '_sortReleasesByVersionNumber'));
+ foreach ($info['r'] as $release) {
+ if ($inst_version && version_compare($release['v'], $inst_version, '<=')) {
+ // not newer than the one installed
+ break;
+ }
+ if (version_compare($release['m'], phpversion(), '>')) {
+ // skip dependency releases that require a PHP version
+ // newer than our PHP version
+ continue;
+ }
+
+ // new version > installed version
+ if (!$pref_state) {
+ // every state is a good state
+ $found = true;
+ break;
+ } else {
+ $new_state = $release['s'];
+ // if new state >= installed state: go
+ if (in_array($new_state, $this->betterStates($inst_state, true))) {
+ $found = true;
+ break;
+ } else {
+ // only allow to lower the state of package,
+ // if new state >= preferred state: go
+ if (in_array($new_state, $this->betterStates($pref_state, true))) {
+ $found = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!$found) {
+ continue;
+ }
+
+ $relinfo = $this->_rest->retrieveCacheFirst($base . 'r/' . strtolower($package) . '/' .
+ $release['v'] . '.xml', false, false, $channel);
+ if (PEAR::isError($relinfo)) {
+ return $relinfo;
+ }
+
+ $ret[$package] = array(
+ 'version' => $release['v'],
+ 'state' => $release['s'],
+ 'filesize' => $relinfo['f'],
+ );
+ }
+
+ return $ret;
+ }
+}
\ No newline at end of file
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Registry.php b/vendor/pear-pear.php.net/PEAR/PEAR/Registry.php
new file mode 100644
index 000000000..c599c61ee
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Registry.php
@@ -0,0 +1,2388 @@
+
+ * @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
+ */
+
+/**
+ * for PEAR_Error
+ */
+require_once 'PEAR.php';
+require_once 'PEAR/DependencyDB.php';
+
+define('PEAR_REGISTRY_ERROR_LOCK', -2);
+define('PEAR_REGISTRY_ERROR_FORMAT', -3);
+define('PEAR_REGISTRY_ERROR_FILE', -4);
+define('PEAR_REGISTRY_ERROR_CONFLICT', -5);
+define('PEAR_REGISTRY_ERROR_CHANNEL_FILE', -6);
+
+/**
+ * Administration class used to maintain the installed package database.
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken
+ * @author Tomas V. V. Cox
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_Registry extends PEAR
+{
+ /**
+ * File containing all channel information.
+ * @var string
+ */
+ var $channels = '';
+
+ /** Directory where registry files are stored.
+ * @var string
+ */
+ var $statedir = '';
+
+ /** File where the file map is stored
+ * @var string
+ */
+ var $filemap = '';
+
+ /** Directory where registry files for channels are stored.
+ * @var string
+ */
+ var $channelsdir = '';
+
+ /** Name of file used for locking the registry
+ * @var string
+ */
+ var $lockfile = '';
+
+ /** File descriptor used during locking
+ * @var resource
+ */
+ var $lock_fp = null;
+
+ /** Mode used during locking
+ * @var int
+ */
+ var $lock_mode = 0; // XXX UNUSED
+
+ /** Cache of package information. Structure:
+ * array(
+ * 'package' => array('id' => ... ),
+ * ... )
+ * @var array
+ */
+ var $pkginfo_cache = array();
+
+ /** Cache of file map. Structure:
+ * array( '/path/to/file' => 'package', ... )
+ * @var array
+ */
+ var $filemap_cache = array();
+
+ /**
+ * @var false|PEAR_ChannelFile
+ */
+ var $_pearChannel;
+
+ /**
+ * @var false|PEAR_ChannelFile
+ */
+ var $_peclChannel;
+
+ /**
+ * @var false|PEAR_ChannelFile
+ */
+ var $_docChannel;
+
+ /**
+ * @var PEAR_DependencyDB
+ */
+ var $_dependencyDB;
+
+ /**
+ * @var PEAR_Config
+ */
+ var $_config;
+
+ /**
+ * PEAR_Registry constructor.
+ *
+ * @param string (optional) PEAR install directory (for .php files)
+ * @param PEAR_ChannelFile PEAR_ChannelFile object representing the PEAR channel, if
+ * default values are not desired. Only used the very first time a PEAR
+ * repository is initialized
+ * @param PEAR_ChannelFile PEAR_ChannelFile object representing the PECL channel, if
+ * default values are not desired. Only used the very first time a PEAR
+ * repository is initialized
+ *
+ * @access public
+ */
+ function __construct($pear_install_dir = PEAR_INSTALL_DIR, $pear_channel = false,
+ $pecl_channel = false, $pear_metadata_dir = '')
+ {
+ parent::__construct();
+ $this->setInstallDir($pear_install_dir, $pear_metadata_dir);
+ $this->_pearChannel = $pear_channel;
+ $this->_peclChannel = $pecl_channel;
+ $this->_config = false;
+ }
+
+ function setInstallDir($pear_install_dir = PEAR_INSTALL_DIR, $pear_metadata_dir = '')
+ {
+ $ds = DIRECTORY_SEPARATOR;
+ $this->install_dir = $pear_install_dir;
+ if (!$pear_metadata_dir) {
+ $pear_metadata_dir = $pear_install_dir;
+ }
+ $this->channelsdir = $pear_metadata_dir.$ds.'.channels';
+ $this->statedir = $pear_metadata_dir.$ds.'.registry';
+ $this->filemap = $pear_metadata_dir.$ds.'.filemap';
+ $this->lockfile = $pear_metadata_dir.$ds.'.lock';
+ }
+
+ function hasWriteAccess()
+ {
+ if (!file_exists($this->install_dir)) {
+ $dir = $this->install_dir;
+ while ($dir && $dir != '.') {
+ $olddir = $dir;
+ $dir = dirname($dir);
+ if ($dir != '.' && file_exists($dir)) {
+ if (is_writeable($dir)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ if ($dir == $olddir) { // this can happen in safe mode
+ return @is_writable($dir);
+ }
+ }
+
+ return false;
+ }
+
+ return is_writeable($this->install_dir);
+ }
+
+ function setConfig(&$config, $resetInstallDir = true)
+ {
+ $this->_config = &$config;
+ if ($resetInstallDir) {
+ $this->setInstallDir($config->get('php_dir'), $config->get('metadata_dir'));
+ }
+ }
+
+ function _initializeChannelDirs()
+ {
+ static $running = false;
+ if (!$running) {
+ $running = true;
+ $ds = DIRECTORY_SEPARATOR;
+ if (!is_dir($this->channelsdir) ||
+ !file_exists($this->channelsdir . $ds . 'pear.php.net.reg') ||
+ !file_exists($this->channelsdir . $ds . 'pecl.php.net.reg') ||
+ !file_exists($this->channelsdir . $ds . 'doc.php.net.reg') ||
+ !file_exists($this->channelsdir . $ds . '__uri.reg')) {
+ if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) {
+ $pear_channel = $this->_pearChannel;
+ if (!is_a($pear_channel, 'PEAR_ChannelFile') || !$pear_channel->validate()) {
+ if (!class_exists('PEAR_ChannelFile')) {
+ require_once 'PEAR/ChannelFile.php';
+ }
+
+ $pear_channel = new PEAR_ChannelFile;
+ $pear_channel->setAlias('pear');
+ $pear_channel->setServer('pear.php.net');
+ $pear_channel->setSummary('PHP Extension and Application Repository');
+ $pear_channel->setDefaultPEARProtocols();
+ $pear_channel->setBaseURL('REST1.0', 'http://pear.php.net/rest/');
+ $pear_channel->setBaseURL('REST1.1', 'http://pear.php.net/rest/');
+ $pear_channel->setBaseURL('REST1.3', 'http://pear.php.net/rest/');
+ //$pear_channel->setBaseURL('REST1.4', 'http://pear.php.net/rest/');
+ } else {
+ $pear_channel->setServer('pear.php.net');
+ $pear_channel->setAlias('pear');
+ }
+
+ $pear_channel->validate();
+ $this->_addChannel($pear_channel);
+ }
+
+ if (!file_exists($this->channelsdir . $ds . 'pecl.php.net.reg')) {
+ $pecl_channel = $this->_peclChannel;
+ if (!is_a($pecl_channel, 'PEAR_ChannelFile') || !$pecl_channel->validate()) {
+ if (!class_exists('PEAR_ChannelFile')) {
+ require_once 'PEAR/ChannelFile.php';
+ }
+
+ $pecl_channel = new PEAR_ChannelFile;
+ $pecl_channel->setAlias('pecl');
+ $pecl_channel->setServer('pecl.php.net');
+ $pecl_channel->setSummary('PHP Extension Community Library');
+ $pecl_channel->setDefaultPEARProtocols();
+ $pecl_channel->setBaseURL('REST1.0', 'http://pecl.php.net/rest/');
+ $pecl_channel->setBaseURL('REST1.1', 'http://pecl.php.net/rest/');
+ $pecl_channel->setValidationPackage('PEAR_Validator_PECL', '1.0');
+ } else {
+ $pecl_channel->setServer('pecl.php.net');
+ $pecl_channel->setAlias('pecl');
+ }
+
+ $pecl_channel->validate();
+ $this->_addChannel($pecl_channel);
+ }
+
+ if (!file_exists($this->channelsdir . $ds . 'doc.php.net.reg')) {
+ $doc_channel = $this->_docChannel;
+ if (!is_a($doc_channel, 'PEAR_ChannelFile') || !$doc_channel->validate()) {
+ if (!class_exists('PEAR_ChannelFile')) {
+ require_once 'PEAR/ChannelFile.php';
+ }
+
+ $doc_channel = new PEAR_ChannelFile;
+ $doc_channel->setAlias('phpdocs');
+ $doc_channel->setServer('doc.php.net');
+ $doc_channel->setSummary('PHP Documentation Team');
+ $doc_channel->setDefaultPEARProtocols();
+ $doc_channel->setBaseURL('REST1.0', 'http://doc.php.net/rest/');
+ $doc_channel->setBaseURL('REST1.1', 'http://doc.php.net/rest/');
+ $doc_channel->setBaseURL('REST1.3', 'http://doc.php.net/rest/');
+ } else {
+ $doc_channel->setServer('doc.php.net');
+ $doc_channel->setAlias('doc');
+ }
+
+ $doc_channel->validate();
+ $this->_addChannel($doc_channel);
+ }
+
+ if (!file_exists($this->channelsdir . $ds . '__uri.reg')) {
+ if (!class_exists('PEAR_ChannelFile')) {
+ require_once 'PEAR/ChannelFile.php';
+ }
+
+ $private = new PEAR_ChannelFile;
+ $private->setName('__uri');
+ $private->setDefaultPEARProtocols();
+ $private->setBaseURL('REST1.0', '****');
+ $private->setSummary('Pseudo-channel for static packages');
+ $this->_addChannel($private);
+ }
+ $this->_rebuildFileMap();
+ }
+
+ $running = false;
+ }
+ }
+
+ function _initializeDirs()
+ {
+ $ds = DIRECTORY_SEPARATOR;
+ // XXX Compatibility code should be removed in the future
+ // rename all registry files if any to lowercase
+ if (!OS_WINDOWS && file_exists($this->statedir) && is_dir($this->statedir) &&
+ $handle = opendir($this->statedir)) {
+ $dest = $this->statedir . $ds;
+ while (false !== ($file = readdir($handle))) {
+ if (preg_match('/^.*[A-Z].*\.reg\\z/', $file)) {
+ rename($dest . $file, $dest . strtolower($file));
+ }
+ }
+ closedir($handle);
+ }
+
+ $this->_initializeChannelDirs();
+ if (!file_exists($this->filemap)) {
+ $this->_rebuildFileMap();
+ }
+ $this->_initializeDepDB();
+ }
+
+ function _initializeDepDB()
+ {
+ if (!isset($this->_dependencyDB)) {
+ static $initializing = false;
+ if (!$initializing) {
+ $initializing = true;
+ if (!$this->_config) { // never used?
+ $file = OS_WINDOWS ? 'pear.ini' : '.pearrc';
+ $this->_config = new PEAR_Config($this->statedir . DIRECTORY_SEPARATOR .
+ $file);
+ $this->_config->setRegistry($this);
+ $this->_config->set('php_dir', $this->install_dir);
+ }
+
+ $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->_config);
+ if (PEAR::isError($this->_dependencyDB)) {
+ // attempt to recover by removing the dep db
+ if (file_exists($this->_config->get('metadata_dir', null, 'pear.php.net') .
+ DIRECTORY_SEPARATOR . '.depdb')) {
+ @unlink($this->_config->get('metadata_dir', null, 'pear.php.net') .
+ DIRECTORY_SEPARATOR . '.depdb');
+ }
+
+ $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->_config);
+ if (PEAR::isError($this->_dependencyDB)) {
+ echo $this->_dependencyDB->getMessage();
+ echo 'Unrecoverable error';
+ exit(1);
+ }
+ }
+
+ $initializing = false;
+ }
+ }
+ }
+
+ /**
+ * PEAR_Registry destructor. Makes sure no locks are forgotten.
+ *
+ * @access private
+ */
+ function _PEAR_Registry()
+ {
+ parent::_PEAR();
+ if (is_resource($this->lock_fp)) {
+ $this->_unlock();
+ }
+ }
+
+ /**
+ * Make sure the directory where we keep registry files exists.
+ *
+ * @return bool TRUE if directory exists, FALSE if it could not be
+ * created
+ *
+ * @access private
+ */
+ function _assertStateDir($channel = false)
+ {
+ if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') {
+ return $this->_assertChannelStateDir($channel);
+ }
+
+ static $init = false;
+ if (!file_exists($this->statedir)) {
+ if (!$this->hasWriteAccess()) {
+ return false;
+ }
+
+ require_once 'System.php';
+ if (!System::mkdir(array('-p', $this->statedir))) {
+ return $this->raiseError("could not create directory '{$this->statedir}'");
+ }
+ $init = true;
+ } elseif (!is_dir($this->statedir)) {
+ return $this->raiseError('Cannot create directory ' . $this->statedir . ', ' .
+ 'it already exists and is not a directory');
+ }
+
+ $ds = DIRECTORY_SEPARATOR;
+ if (!file_exists($this->channelsdir)) {
+ if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg') ||
+ !file_exists($this->channelsdir . $ds . 'pecl.php.net.reg') ||
+ !file_exists($this->channelsdir . $ds . 'doc.php.net.reg') ||
+ !file_exists($this->channelsdir . $ds . '__uri.reg')) {
+ $init = true;
+ }
+ } elseif (!is_dir($this->channelsdir)) {
+ return $this->raiseError('Cannot create directory ' . $this->channelsdir . ', ' .
+ 'it already exists and is not a directory');
+ }
+
+ if ($init) {
+ static $running = false;
+ if (!$running) {
+ $running = true;
+ $this->_initializeDirs();
+ $running = false;
+ $init = false;
+ }
+ } else {
+ $this->_initializeDepDB();
+ }
+
+ return true;
+ }
+
+ /**
+ * Make sure the directory where we keep registry files exists for a non-standard channel.
+ *
+ * @param string channel name
+ * @return bool TRUE if directory exists, FALSE if it could not be
+ * created
+ *
+ * @access private
+ */
+ function _assertChannelStateDir($channel)
+ {
+ $ds = DIRECTORY_SEPARATOR;
+ if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') {
+ if (!file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) {
+ $this->_initializeChannelDirs();
+ }
+ return $this->_assertStateDir($channel);
+ }
+
+ $channelDir = $this->_channelDirectoryName($channel);
+ if (!is_dir($this->channelsdir) ||
+ !file_exists($this->channelsdir . $ds . 'pear.php.net.reg')) {
+ $this->_initializeChannelDirs();
+ }
+
+ if (!file_exists($channelDir)) {
+ if (!$this->hasWriteAccess()) {
+ return false;
+ }
+
+ require_once 'System.php';
+ if (!System::mkdir(array('-p', $channelDir))) {
+ return $this->raiseError("could not create directory '" . $channelDir .
+ "'");
+ }
+ } elseif (!is_dir($channelDir)) {
+ return $this->raiseError("could not create directory '" . $channelDir .
+ "', already exists and is not a directory");
+ }
+
+ return true;
+ }
+
+ /**
+ * Make sure the directory where we keep registry files for channels exists
+ *
+ * @return bool TRUE if directory exists, FALSE if it could not be
+ * created
+ *
+ * @access private
+ */
+ function _assertChannelDir()
+ {
+ if (!file_exists($this->channelsdir)) {
+ if (!$this->hasWriteAccess()) {
+ return false;
+ }
+
+ require_once 'System.php';
+ if (!System::mkdir(array('-p', $this->channelsdir))) {
+ return $this->raiseError("could not create directory '{$this->channelsdir}'");
+ }
+ } elseif (!is_dir($this->channelsdir)) {
+ return $this->raiseError("could not create directory '{$this->channelsdir}" .
+ "', it already exists and is not a directory");
+ }
+
+ if (!file_exists($this->channelsdir . DIRECTORY_SEPARATOR . '.alias')) {
+ if (!$this->hasWriteAccess()) {
+ return false;
+ }
+
+ require_once 'System.php';
+ if (!System::mkdir(array('-p', $this->channelsdir . DIRECTORY_SEPARATOR . '.alias'))) {
+ return $this->raiseError("could not create directory '{$this->channelsdir}/.alias'");
+ }
+ } elseif (!is_dir($this->channelsdir . DIRECTORY_SEPARATOR . '.alias')) {
+ return $this->raiseError("could not create directory '{$this->channelsdir}" .
+ "/.alias', it already exists and is not a directory");
+ }
+
+ return true;
+ }
+
+ /**
+ * Get the name of the file where data for a given package is stored.
+ *
+ * @param string channel name, or false if this is a PEAR package
+ * @param string package name
+ *
+ * @return string registry file name
+ *
+ * @access public
+ */
+ function _packageFileName($package, $channel = false)
+ {
+ if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') {
+ return $this->_channelDirectoryName($channel) . DIRECTORY_SEPARATOR .
+ strtolower($package) . '.reg';
+ }
+
+ return $this->statedir . DIRECTORY_SEPARATOR . strtolower($package) . '.reg';
+ }
+
+ /**
+ * Get the name of the file where data for a given channel is stored.
+ * @param string channel name
+ * @return string registry file name
+ */
+ function _channelFileName($channel, $noaliases = false)
+ {
+ if (!$noaliases) {
+ if (file_exists($this->_getChannelAliasFileName($channel))) {
+ $channel = implode('', file($this->_getChannelAliasFileName($channel)));
+ }
+ }
+ return $this->channelsdir . DIRECTORY_SEPARATOR . str_replace('/', '_',
+ strtolower($channel)) . '.reg';
+ }
+
+ /**
+ * @param string
+ * @return string
+ */
+ function _getChannelAliasFileName($alias)
+ {
+ return $this->channelsdir . DIRECTORY_SEPARATOR . '.alias' .
+ DIRECTORY_SEPARATOR . str_replace('/', '_', strtolower($alias)) . '.txt';
+ }
+
+ /**
+ * Get the name of a channel from its alias
+ */
+ function _getChannelFromAlias($channel)
+ {
+ if (!$this->_channelExists($channel)) {
+ if ($channel == 'pear.php.net') {
+ return 'pear.php.net';
+ }
+
+ if ($channel == 'pecl.php.net') {
+ return 'pecl.php.net';
+ }
+
+ if ($channel == 'doc.php.net') {
+ return 'doc.php.net';
+ }
+
+ if ($channel == '__uri') {
+ return '__uri';
+ }
+
+ return false;
+ }
+
+ $channel = strtolower($channel);
+ if (file_exists($this->_getChannelAliasFileName($channel))) {
+ // translate an alias to an actual channel
+ return implode('', file($this->_getChannelAliasFileName($channel)));
+ }
+
+ return $channel;
+ }
+
+ /**
+ * Get the alias of a channel from its alias or its name
+ */
+ function _getAlias($channel)
+ {
+ if (!$this->_channelExists($channel)) {
+ if ($channel == 'pear.php.net') {
+ return 'pear';
+ }
+
+ if ($channel == 'pecl.php.net') {
+ return 'pecl';
+ }
+
+ if ($channel == 'doc.php.net') {
+ return 'phpdocs';
+ }
+
+ return false;
+ }
+
+ $channel = $this->_getChannel($channel);
+ if (PEAR::isError($channel)) {
+ return $channel;
+ }
+
+ return $channel->getAlias();
+ }
+
+ /**
+ * Get the name of the file where data for a given package is stored.
+ *
+ * @param string channel name, or false if this is a PEAR package
+ * @param string package name
+ *
+ * @return string registry file name
+ *
+ * @access public
+ */
+ function _channelDirectoryName($channel)
+ {
+ if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') {
+ return $this->statedir;
+ }
+
+ $ch = $this->_getChannelFromAlias($channel);
+ if (!$ch) {
+ $ch = $channel;
+ }
+
+ return $this->statedir . DIRECTORY_SEPARATOR . strtolower('.channel.' .
+ str_replace('/', '_', $ch));
+ }
+
+ function _openPackageFile($package, $mode, $channel = false)
+ {
+ if (!$this->_assertStateDir($channel)) {
+ return null;
+ }
+
+ if (!in_array($mode, array('r', 'rb')) && !$this->hasWriteAccess()) {
+ return null;
+ }
+
+ $file = $this->_packageFileName($package, $channel);
+ if (!file_exists($file) && $mode == 'r' || $mode == 'rb') {
+ return null;
+ }
+
+ $fp = @fopen($file, $mode);
+ if (!$fp) {
+ return null;
+ }
+
+ return $fp;
+ }
+
+ function _closePackageFile($fp)
+ {
+ fclose($fp);
+ }
+
+ function _openChannelFile($channel, $mode)
+ {
+ if (!$this->_assertChannelDir()) {
+ return null;
+ }
+
+ if (!in_array($mode, array('r', 'rb')) && !$this->hasWriteAccess()) {
+ return null;
+ }
+
+ $file = $this->_channelFileName($channel);
+ if (!file_exists($file) && $mode == 'r' || $mode == 'rb') {
+ return null;
+ }
+
+ $fp = @fopen($file, $mode);
+ if (!$fp) {
+ return null;
+ }
+
+ return $fp;
+ }
+
+ function _closeChannelFile($fp)
+ {
+ fclose($fp);
+ }
+
+ function _rebuildFileMap()
+ {
+ if (!class_exists('PEAR_Installer_Role')) {
+ require_once 'PEAR/Installer/Role.php';
+ }
+
+ $channels = $this->_listAllPackages();
+ $files = array();
+ foreach ($channels as $channel => $packages) {
+ foreach ($packages as $package) {
+ $version = $this->_packageInfo($package, 'version', $channel);
+ $filelist = $this->_packageInfo($package, 'filelist', $channel);
+ if (!is_array($filelist)) {
+ continue;
+ }
+
+ foreach ($filelist as $name => $attrs) {
+ if (isset($attrs['attribs'])) {
+ $attrs = $attrs['attribs'];
+ }
+
+ // it is possible for conflicting packages in different channels to
+ // conflict with data files/doc files
+ if ($name == 'dirtree') {
+ continue;
+ }
+
+ if (isset($attrs['role']) && !in_array($attrs['role'],
+ PEAR_Installer_Role::getInstallableRoles())) {
+ // these are not installed
+ continue;
+ }
+
+ if (isset($attrs['role']) && !in_array($attrs['role'],
+ PEAR_Installer_Role::getBaseinstallRoles())) {
+ $attrs['baseinstalldir'] = $package;
+ }
+
+ if (isset($attrs['baseinstalldir'])) {
+ $file = $attrs['baseinstalldir'].DIRECTORY_SEPARATOR.$name;
+ } else {
+ $file = $name;
+ }
+
+ $file = preg_replace(',^/+,', '', $file);
+ if ($channel != 'pear.php.net') {
+ if (!isset($files[$attrs['role']])) {
+ $files[$attrs['role']] = array();
+ }
+ $files[$attrs['role']][$file] = array(strtolower($channel),
+ strtolower($package));
+ } else {
+ if (!isset($files[$attrs['role']])) {
+ $files[$attrs['role']] = array();
+ }
+ $files[$attrs['role']][$file] = strtolower($package);
+ }
+ }
+ }
+ }
+
+
+ $this->_assertStateDir();
+ if (!$this->hasWriteAccess()) {
+ return false;
+ }
+
+ $fp = @fopen($this->filemap, 'wb');
+ if (!$fp) {
+ return false;
+ }
+
+ $this->filemap_cache = $files;
+ fwrite($fp, serialize($files));
+ fclose($fp);
+ return true;
+ }
+
+ function _readFileMap()
+ {
+ if (!file_exists($this->filemap)) {
+ return array();
+ }
+
+ $fp = @fopen($this->filemap, 'r');
+ if (!$fp) {
+ return $this->raiseError('PEAR_Registry: could not open filemap "' . $this->filemap . '"', PEAR_REGISTRY_ERROR_FILE, null, null, $php_errormsg);
+ }
+
+ clearstatcache();
+ $fsize = filesize($this->filemap);
+ fclose($fp);
+ $data = file_get_contents($this->filemap);
+ $tmp = unserialize($data);
+ if (!$tmp && $fsize > 7) {
+ return $this->raiseError('PEAR_Registry: invalid filemap data', PEAR_REGISTRY_ERROR_FORMAT, null, null, $data);
+ }
+
+ $this->filemap_cache = $tmp;
+ return true;
+ }
+
+ /**
+ * Lock the registry.
+ *
+ * @param integer lock mode, one of LOCK_EX, LOCK_SH or LOCK_UN.
+ * See flock manual for more information.
+ *
+ * @return bool TRUE on success, FALSE if locking failed, or a
+ * PEAR error if some other error occurs (such as the
+ * lock file not being writable).
+ *
+ * @access private
+ */
+ function _lock($mode = LOCK_EX)
+ {
+ if (stristr(php_uname(), 'Windows 9')) {
+ return true;
+ }
+
+ if ($mode != LOCK_UN && is_resource($this->lock_fp)) {
+ // XXX does not check type of lock (LOCK_SH/LOCK_EX)
+ return true;
+ }
+
+ if (!$this->_assertStateDir()) {
+ if ($mode == LOCK_EX) {
+ return $this->raiseError('Registry directory is not writeable by the current user');
+ }
+
+ return true;
+ }
+
+ $open_mode = 'w';
+ // XXX People reported problems with LOCK_SH and 'w'
+ if ($mode === LOCK_SH || $mode === LOCK_UN) {
+ if (!file_exists($this->lockfile)) {
+ touch($this->lockfile);
+ }
+ $open_mode = 'r';
+ }
+
+ if (!is_resource($this->lock_fp)) {
+ $this->lock_fp = @fopen($this->lockfile, $open_mode);
+ }
+
+ if (!is_resource($this->lock_fp)) {
+ $this->lock_fp = null;
+ return $this->raiseError("could not create lock file" .
+ (isset($php_errormsg) ? ": " . $php_errormsg : ""));
+ }
+
+ if (!(int)flock($this->lock_fp, $mode)) {
+ switch ($mode) {
+ case LOCK_SH: $str = 'shared'; break;
+ case LOCK_EX: $str = 'exclusive'; break;
+ case LOCK_UN: $str = 'unlock'; break;
+ default: $str = 'unknown'; break;
+ }
+
+ //is resource at this point, close it on error.
+ fclose($this->lock_fp);
+ $this->lock_fp = null;
+ return $this->raiseError("could not acquire $str lock ($this->lockfile)",
+ PEAR_REGISTRY_ERROR_LOCK);
+ }
+
+ return true;
+ }
+
+ function _unlock()
+ {
+ $ret = $this->_lock(LOCK_UN);
+ if (is_resource($this->lock_fp)) {
+ fclose($this->lock_fp);
+ }
+
+ $this->lock_fp = null;
+ return $ret;
+ }
+
+ function _packageExists($package, $channel = false)
+ {
+ return file_exists($this->_packageFileName($package, $channel));
+ }
+
+ /**
+ * Determine whether a channel exists in the registry
+ *
+ * @param string Channel name
+ * @param bool if true, then aliases will be ignored
+ * @return boolean
+ */
+ function _channelExists($channel, $noaliases = false)
+ {
+ $a = file_exists($this->_channelFileName($channel, $noaliases));
+ if (!$a && $channel == 'pear.php.net') {
+ return true;
+ }
+
+ if (!$a && $channel == 'pecl.php.net') {
+ return true;
+ }
+
+ if (!$a && $channel == 'doc.php.net') {
+ return true;
+ }
+
+ return $a;
+ }
+
+ /**
+ * Determine whether a mirror exists within the default channel in the registry
+ *
+ * @param string Channel name
+ * @param string Mirror name
+ *
+ * @return boolean
+ */
+ function _mirrorExists($channel, $mirror)
+ {
+ $data = $this->_channelInfo($channel);
+ if (!isset($data['servers']['mirror'])) {
+ return false;
+ }
+
+ foreach ($data['servers']['mirror'] as $m) {
+ if ($m['attribs']['host'] == $mirror) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * @param PEAR_ChannelFile Channel object
+ * @param donotuse
+ * @param string Last-Modified HTTP tag from remote request
+ * @return boolean|PEAR_Error True on creation, false if it already exists
+ */
+ function _addChannel($channel, $update = false, $lastmodified = false)
+ {
+ if (!is_a($channel, 'PEAR_ChannelFile')) {
+ return false;
+ }
+
+ if (!$channel->validate()) {
+ return false;
+ }
+
+ if (file_exists($this->_channelFileName($channel->getName()))) {
+ if (!$update) {
+ return false;
+ }
+
+ $checker = $this->_getChannel($channel->getName());
+ if (PEAR::isError($checker)) {
+ return $checker;
+ }
+
+ if ($channel->getAlias() != $checker->getAlias()) {
+ if (file_exists($this->_getChannelAliasFileName($checker->getAlias()))) {
+ @unlink($this->_getChannelAliasFileName($checker->getAlias()));
+ }
+ }
+ } else {
+ if ($update && !in_array($channel->getName(), array('pear.php.net', 'pecl.php.net', 'doc.php.net'))) {
+ return false;
+ }
+ }
+
+ $ret = $this->_assertChannelDir();
+ if (PEAR::isError($ret)) {
+ return $ret;
+ }
+
+ $ret = $this->_assertChannelStateDir($channel->getName());
+ if (PEAR::isError($ret)) {
+ return $ret;
+ }
+
+ if ($channel->getAlias() != $channel->getName()) {
+ if (file_exists($this->_getChannelAliasFileName($channel->getAlias())) &&
+ $this->_getChannelFromAlias($channel->getAlias()) != $channel->getName()) {
+ $channel->setAlias($channel->getName());
+ }
+
+ if (!$this->hasWriteAccess()) {
+ return false;
+ }
+
+ $fp = @fopen($this->_getChannelAliasFileName($channel->getAlias()), 'w');
+ if (!$fp) {
+ return false;
+ }
+
+ fwrite($fp, $channel->getName());
+ fclose($fp);
+ }
+
+ if (!$this->hasWriteAccess()) {
+ return false;
+ }
+
+ $fp = @fopen($this->_channelFileName($channel->getName()), 'wb');
+ if (!$fp) {
+ return false;
+ }
+
+ $info = $channel->toArray();
+ if ($lastmodified) {
+ $info['_lastmodified'] = $lastmodified;
+ } else {
+ $info['_lastmodified'] = time();
+ }
+
+ fwrite($fp, serialize($info));
+ fclose($fp);
+ return true;
+ }
+
+ /**
+ * Deletion fails if there are any packages installed from the channel
+ * @param string|PEAR_ChannelFile channel name
+ * @return boolean|PEAR_Error True on deletion, false if it doesn't exist
+ */
+ function _deleteChannel($channel)
+ {
+ if (!is_string($channel)) {
+ if (!is_a($channel, 'PEAR_ChannelFile')) {
+ return false;
+ }
+
+ if (!$channel->validate()) {
+ return false;
+ }
+ $channel = $channel->getName();
+ }
+
+ if ($this->_getChannelFromAlias($channel) == '__uri') {
+ return false;
+ }
+
+ if ($this->_getChannelFromAlias($channel) == 'pecl.php.net') {
+ return false;
+ }
+
+ if ($this->_getChannelFromAlias($channel) == 'doc.php.net') {
+ return false;
+ }
+
+ if (!$this->_channelExists($channel)) {
+ return false;
+ }
+
+ if (!$channel || $this->_getChannelFromAlias($channel) == 'pear.php.net') {
+ return false;
+ }
+
+ $channel = $this->_getChannelFromAlias($channel);
+ if ($channel == 'pear.php.net') {
+ return false;
+ }
+
+ $test = $this->_listChannelPackages($channel);
+ if (count($test)) {
+ return false;
+ }
+
+ $test = @rmdir($this->_channelDirectoryName($channel));
+ if (!$test) {
+ return false;
+ }
+
+ $file = $this->_getChannelAliasFileName($this->_getAlias($channel));
+ if (file_exists($file)) {
+ $test = @unlink($file);
+ if (!$test) {
+ return false;
+ }
+ }
+
+ $file = $this->_channelFileName($channel);
+ $ret = true;
+ if (file_exists($file)) {
+ $ret = @unlink($file);
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Determine whether a channel exists in the registry
+ * @param string Channel Alias
+ * @return boolean
+ */
+ function _isChannelAlias($alias)
+ {
+ return file_exists($this->_getChannelAliasFileName($alias));
+ }
+
+ /**
+ * @param string|null
+ * @param string|null
+ * @param string|null
+ * @return array|null
+ * @access private
+ */
+ function _packageInfo($package = null, $key = null, $channel = 'pear.php.net')
+ {
+ if ($package === null) {
+ if ($channel === null) {
+ $channels = $this->_listChannels();
+ $ret = array();
+ foreach ($channels as $channel) {
+ $channel = strtolower($channel);
+ $ret[$channel] = array();
+ $packages = $this->_listPackages($channel);
+ foreach ($packages as $package) {
+ $ret[$channel][] = $this->_packageInfo($package, null, $channel);
+ }
+ }
+
+ return $ret;
+ }
+
+ $ps = $this->_listPackages($channel);
+ if (!count($ps)) {
+ return array();
+ }
+ return array_map(array(&$this, '_packageInfo'),
+ $ps, array_fill(0, count($ps), null),
+ array_fill(0, count($ps), $channel));
+ }
+
+ $fp = $this->_openPackageFile($package, 'r', $channel);
+ if ($fp === null) {
+ return null;
+ }
+
+ clearstatcache();
+ $this->_closePackageFile($fp);
+ $data = file_get_contents($this->_packageFileName($package, $channel));
+ $data = unserialize($data);
+ if ($key === null) {
+ return $data;
+ }
+
+ // compatibility for package.xml version 2.0
+ if (isset($data['old'][$key])) {
+ return $data['old'][$key];
+ }
+
+ if (isset($data[$key])) {
+ return $data[$key];
+ }
+
+ return null;
+ }
+
+ /**
+ * @param string Channel name
+ * @param bool whether to strictly retrieve info of channels, not just aliases
+ * @return array|null
+ */
+ function _channelInfo($channel, $noaliases = false)
+ {
+ if (!$this->_channelExists($channel, $noaliases)) {
+ return null;
+ }
+
+ $fp = $this->_openChannelFile($channel, 'r');
+ if ($fp === null) {
+ return null;
+ }
+
+ clearstatcache();
+ $this->_closeChannelFile($fp);
+ $data = file_get_contents($this->_channelFileName($channel));
+ $data = unserialize($data);
+ return $data;
+ }
+
+ function _listChannels()
+ {
+ $channellist = array();
+ if (!file_exists($this->channelsdir) || !is_dir($this->channelsdir)) {
+ return array('pear.php.net', 'pecl.php.net', 'doc.php.net', '__uri');
+ }
+
+ $dp = opendir($this->channelsdir);
+ while ($ent = readdir($dp)) {
+ if ($ent{0} == '.' || substr($ent, -4) != '.reg') {
+ continue;
+ }
+
+ if ($ent == '__uri.reg') {
+ $channellist[] = '__uri';
+ continue;
+ }
+
+ $channellist[] = str_replace('_', '/', substr($ent, 0, -4));
+ }
+
+ closedir($dp);
+ if (!in_array('pear.php.net', $channellist)) {
+ $channellist[] = 'pear.php.net';
+ }
+
+ if (!in_array('pecl.php.net', $channellist)) {
+ $channellist[] = 'pecl.php.net';
+ }
+
+ if (!in_array('doc.php.net', $channellist)) {
+ $channellist[] = 'doc.php.net';
+ }
+
+
+ if (!in_array('__uri', $channellist)) {
+ $channellist[] = '__uri';
+ }
+
+ natsort($channellist);
+ return $channellist;
+ }
+
+ function _listPackages($channel = false)
+ {
+ if ($channel && $this->_getChannelFromAlias($channel) != 'pear.php.net') {
+ return $this->_listChannelPackages($channel);
+ }
+
+ if (!file_exists($this->statedir) || !is_dir($this->statedir)) {
+ return array();
+ }
+
+ $pkglist = array();
+ $dp = opendir($this->statedir);
+ if (!$dp) {
+ return $pkglist;
+ }
+
+ while ($ent = readdir($dp)) {
+ if ($ent{0} == '.' || substr($ent, -4) != '.reg') {
+ continue;
+ }
+
+ $pkglist[] = substr($ent, 0, -4);
+ }
+ closedir($dp);
+ return $pkglist;
+ }
+
+ function _listChannelPackages($channel)
+ {
+ $pkglist = array();
+ if (!file_exists($this->_channelDirectoryName($channel)) ||
+ !is_dir($this->_channelDirectoryName($channel))) {
+ return array();
+ }
+
+ $dp = opendir($this->_channelDirectoryName($channel));
+ if (!$dp) {
+ return $pkglist;
+ }
+
+ while ($ent = readdir($dp)) {
+ if ($ent{0} == '.' || substr($ent, -4) != '.reg') {
+ continue;
+ }
+ $pkglist[] = substr($ent, 0, -4);
+ }
+
+ closedir($dp);
+ return $pkglist;
+ }
+
+ function _listAllPackages()
+ {
+ $ret = array();
+ foreach ($this->_listChannels() as $channel) {
+ $ret[$channel] = $this->_listPackages($channel);
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Add an installed package to the registry
+ * @param string package name
+ * @param array package info (parsed by PEAR_Common::infoFrom*() methods)
+ * @return bool success of saving
+ * @access private
+ */
+ function _addPackage($package, $info)
+ {
+ if ($this->_packageExists($package)) {
+ return false;
+ }
+
+ $fp = $this->_openPackageFile($package, 'wb');
+ if ($fp === null) {
+ return false;
+ }
+
+ $info['_lastmodified'] = time();
+ fwrite($fp, serialize($info));
+ $this->_closePackageFile($fp);
+ if (isset($info['filelist'])) {
+ $this->_rebuildFileMap();
+ }
+
+ return true;
+ }
+
+ /**
+ * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+ * @return bool
+ * @access private
+ */
+ function _addPackage2($info)
+ {
+ if (!is_a($info, 'PEAR_PackageFile_v1') && !is_a($info, 'PEAR_PackageFile_v2')) {
+ return false;
+ }
+
+ if (!$info->validate()) {
+ if (class_exists('PEAR_Common')) {
+ $ui = PEAR_Frontend::singleton();
+ if ($ui) {
+ foreach ($info->getValidationWarnings() as $err) {
+ $ui->log($err['message'], true);
+ }
+ }
+ }
+ return false;
+ }
+
+ $channel = $info->getChannel();
+ $package = $info->getPackage();
+ $save = $info;
+ if ($this->_packageExists($package, $channel)) {
+ return false;
+ }
+
+ if (!$this->_channelExists($channel, true)) {
+ return false;
+ }
+
+ $info = $info->toArray(true);
+ if (!$info) {
+ return false;
+ }
+
+ $fp = $this->_openPackageFile($package, 'wb', $channel);
+ if ($fp === null) {
+ return false;
+ }
+
+ $info['_lastmodified'] = time();
+ fwrite($fp, serialize($info));
+ $this->_closePackageFile($fp);
+ $this->_rebuildFileMap();
+ return true;
+ }
+
+ /**
+ * @param string Package name
+ * @param array parsed package.xml 1.0
+ * @param bool this parameter is only here for BC. Don't use it.
+ * @access private
+ */
+ function _updatePackage($package, $info, $merge = true)
+ {
+ $oldinfo = $this->_packageInfo($package);
+ if (empty($oldinfo)) {
+ return false;
+ }
+
+ $fp = $this->_openPackageFile($package, 'w');
+ if ($fp === null) {
+ return false;
+ }
+
+ if (is_object($info)) {
+ $info = $info->toArray();
+ }
+ $info['_lastmodified'] = time();
+
+ $newinfo = $info;
+ if ($merge) {
+ $info = array_merge($oldinfo, $info);
+ } else {
+ $diff = $info;
+ }
+
+ fwrite($fp, serialize($info));
+ $this->_closePackageFile($fp);
+ if (isset($newinfo['filelist'])) {
+ $this->_rebuildFileMap();
+ }
+
+ return true;
+ }
+
+ /**
+ * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+ * @return bool
+ * @access private
+ */
+ function _updatePackage2($info)
+ {
+ if (!$this->_packageExists($info->getPackage(), $info->getChannel())) {
+ return false;
+ }
+
+ $fp = $this->_openPackageFile($info->getPackage(), 'w', $info->getChannel());
+ if ($fp === null) {
+ return false;
+ }
+
+ $save = $info;
+ $info = $save->getArray(true);
+ $info['_lastmodified'] = time();
+ fwrite($fp, serialize($info));
+ $this->_closePackageFile($fp);
+ $this->_rebuildFileMap();
+ return true;
+ }
+
+ /**
+ * @param string Package name
+ * @param string Channel name
+ * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|null
+ * @access private
+ */
+ function &_getPackage($package, $channel = 'pear.php.net')
+ {
+ $info = $this->_packageInfo($package, null, $channel);
+ if ($info === null) {
+ return $info;
+ }
+
+ $a = $this->_config;
+ if (!$a) {
+ $this->_config = new PEAR_Config;
+ $this->_config->set('php_dir', $this->statedir);
+ }
+
+ if (!class_exists('PEAR_PackageFile')) {
+ require_once 'PEAR/PackageFile.php';
+ }
+
+ $pkg = new PEAR_PackageFile($this->_config);
+ $pf = &$pkg->fromArray($info);
+ return $pf;
+ }
+
+ /**
+ * @param string channel name
+ * @param bool whether to strictly retrieve channel names
+ * @return PEAR_ChannelFile|PEAR_Error
+ * @access private
+ */
+ function &_getChannel($channel, $noaliases = false)
+ {
+ $ch = false;
+ if ($this->_channelExists($channel, $noaliases)) {
+ $chinfo = $this->_channelInfo($channel, $noaliases);
+ if ($chinfo) {
+ if (!class_exists('PEAR_ChannelFile')) {
+ require_once 'PEAR/ChannelFile.php';
+ }
+
+ $ch = &PEAR_ChannelFile::fromArrayWithErrors($chinfo);
+ }
+ }
+
+ if ($ch) {
+ if ($ch->validate()) {
+ return $ch;
+ }
+
+ foreach ($ch->getErrors(true) as $err) {
+ $message = $err['message'] . "\n";
+ }
+
+ $ch = PEAR::raiseError($message);
+ return $ch;
+ }
+
+ if ($this->_getChannelFromAlias($channel) == 'pear.php.net') {
+ // the registry is not properly set up, so use defaults
+ if (!class_exists('PEAR_ChannelFile')) {
+ require_once 'PEAR/ChannelFile.php';
+ }
+
+ $pear_channel = new PEAR_ChannelFile;
+ $pear_channel->setServer('pear.php.net');
+ $pear_channel->setAlias('pear');
+ $pear_channel->setSummary('PHP Extension and Application Repository');
+ $pear_channel->setDefaultPEARProtocols();
+ $pear_channel->setBaseURL('REST1.0', 'http://pear.php.net/rest/');
+ $pear_channel->setBaseURL('REST1.1', 'http://pear.php.net/rest/');
+ $pear_channel->setBaseURL('REST1.3', 'http://pear.php.net/rest/');
+ return $pear_channel;
+ }
+
+ if ($this->_getChannelFromAlias($channel) == 'pecl.php.net') {
+ // the registry is not properly set up, so use defaults
+ if (!class_exists('PEAR_ChannelFile')) {
+ require_once 'PEAR/ChannelFile.php';
+ }
+ $pear_channel = new PEAR_ChannelFile;
+ $pear_channel->setServer('pecl.php.net');
+ $pear_channel->setAlias('pecl');
+ $pear_channel->setSummary('PHP Extension Community Library');
+ $pear_channel->setDefaultPEARProtocols();
+ $pear_channel->setBaseURL('REST1.0', 'http://pecl.php.net/rest/');
+ $pear_channel->setBaseURL('REST1.1', 'http://pecl.php.net/rest/');
+ $pear_channel->setValidationPackage('PEAR_Validator_PECL', '1.0');
+ return $pear_channel;
+ }
+
+ if ($this->_getChannelFromAlias($channel) == 'doc.php.net') {
+ // the registry is not properly set up, so use defaults
+ if (!class_exists('PEAR_ChannelFile')) {
+ require_once 'PEAR/ChannelFile.php';
+ }
+
+ $doc_channel = new PEAR_ChannelFile;
+ $doc_channel->setServer('doc.php.net');
+ $doc_channel->setAlias('phpdocs');
+ $doc_channel->setSummary('PHP Documentation Team');
+ $doc_channel->setDefaultPEARProtocols();
+ $doc_channel->setBaseURL('REST1.0', 'http://doc.php.net/rest/');
+ $doc_channel->setBaseURL('REST1.1', 'http://doc.php.net/rest/');
+ $doc_channel->setBaseURL('REST1.3', 'http://doc.php.net/rest/');
+ return $doc_channel;
+ }
+
+
+ if ($this->_getChannelFromAlias($channel) == '__uri') {
+ // the registry is not properly set up, so use defaults
+ if (!class_exists('PEAR_ChannelFile')) {
+ require_once 'PEAR/ChannelFile.php';
+ }
+
+ $private = new PEAR_ChannelFile;
+ $private->setName('__uri');
+ $private->setDefaultPEARProtocols();
+ $private->setBaseURL('REST1.0', '****');
+ $private->setSummary('Pseudo-channel for static packages');
+ return $private;
+ }
+
+ return $ch;
+ }
+
+ /**
+ * @param string Package name
+ * @param string Channel name
+ * @return bool
+ */
+ function packageExists($package, $channel = 'pear.php.net')
+ {
+ if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
+ return $e;
+ }
+ $ret = $this->_packageExists($package, $channel);
+ $this->_unlock();
+ return $ret;
+ }
+
+ // }}}
+
+ // {{{ channelExists()
+
+ /**
+ * @param string channel name
+ * @param bool if true, then aliases will be ignored
+ * @return bool
+ */
+ function channelExists($channel, $noaliases = false)
+ {
+ if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
+ return $e;
+ }
+ $ret = $this->_channelExists($channel, $noaliases);
+ $this->_unlock();
+ return $ret;
+ }
+
+ // }}}
+
+ /**
+ * @param string channel name mirror is in
+ * @param string mirror name
+ *
+ * @return bool
+ */
+ function mirrorExists($channel, $mirror)
+ {
+ if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
+ return $e;
+ }
+
+ $ret = $this->_mirrorExists($channel, $mirror);
+ $this->_unlock();
+ return $ret;
+ }
+
+ // {{{ isAlias()
+
+ /**
+ * Determines whether the parameter is an alias of a channel
+ * @param string
+ * @return bool
+ */
+ function isAlias($alias)
+ {
+ if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
+ return $e;
+ }
+ $ret = $this->_isChannelAlias($alias);
+ $this->_unlock();
+ return $ret;
+ }
+
+ // }}}
+ // {{{ packageInfo()
+
+ /**
+ * @param string|null
+ * @param string|null
+ * @param string
+ * @return array|null
+ */
+ function packageInfo($package = null, $key = null, $channel = 'pear.php.net')
+ {
+ if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
+ return $e;
+ }
+ $ret = $this->_packageInfo($package, $key, $channel);
+ $this->_unlock();
+ return $ret;
+ }
+
+ // }}}
+ // {{{ channelInfo()
+
+ /**
+ * Retrieve a raw array of channel data.
+ *
+ * Do not use this, instead use {@link getChannel()} for normal
+ * operations. Array structure is undefined in this method
+ * @param string channel name
+ * @param bool whether to strictly retrieve information only on non-aliases
+ * @return array|null|PEAR_Error
+ */
+ function channelInfo($channel = null, $noaliases = false)
+ {
+ if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
+ return $e;
+ }
+ $ret = $this->_channelInfo($channel, $noaliases);
+ $this->_unlock();
+ return $ret;
+ }
+
+ // }}}
+
+ /**
+ * @param string
+ */
+ function channelName($channel)
+ {
+ if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
+ return $e;
+ }
+ $ret = $this->_getChannelFromAlias($channel);
+ $this->_unlock();
+ return $ret;
+ }
+
+ /**
+ * @param string
+ */
+ function channelAlias($channel)
+ {
+ if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
+ return $e;
+ }
+ $ret = $this->_getAlias($channel);
+ $this->_unlock();
+ return $ret;
+ }
+ // {{{ listPackages()
+
+ function listPackages($channel = false)
+ {
+ if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
+ return $e;
+ }
+ $ret = $this->_listPackages($channel);
+ $this->_unlock();
+ return $ret;
+ }
+
+ // }}}
+ // {{{ listAllPackages()
+
+ function listAllPackages()
+ {
+ if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
+ return $e;
+ }
+ $ret = $this->_listAllPackages();
+ $this->_unlock();
+ return $ret;
+ }
+
+ // }}}
+ // {{{ listChannel()
+
+ function listChannels()
+ {
+ if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
+ return $e;
+ }
+ $ret = $this->_listChannels();
+ $this->_unlock();
+ return $ret;
+ }
+
+ // }}}
+ // {{{ addPackage()
+
+ /**
+ * Add an installed package to the registry
+ * @param string|PEAR_PackageFile_v1|PEAR_PackageFile_v2 package name or object
+ * that will be passed to {@link addPackage2()}
+ * @param array package info (parsed by PEAR_Common::infoFrom*() methods)
+ * @return bool success of saving
+ */
+ function addPackage($package, $info)
+ {
+ if (is_object($info)) {
+ return $this->addPackage2($info);
+ }
+ if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
+ return $e;
+ }
+ $ret = $this->_addPackage($package, $info);
+ $this->_unlock();
+ if ($ret) {
+ if (!class_exists('PEAR_PackageFile_v1')) {
+ require_once 'PEAR/PackageFile/v1.php';
+ }
+ $pf = new PEAR_PackageFile_v1;
+ $pf->setConfig($this->_config);
+ $pf->fromArray($info);
+ $this->_dependencyDB->uninstallPackage($pf);
+ $this->_dependencyDB->installPackage($pf);
+ }
+ return $ret;
+ }
+
+ // }}}
+ // {{{ addPackage2()
+
+ function addPackage2($info)
+ {
+ if (!is_object($info)) {
+ return $this->addPackage($info['package'], $info);
+ }
+ if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
+ return $e;
+ }
+ $ret = $this->_addPackage2($info);
+ $this->_unlock();
+ if ($ret) {
+ $this->_dependencyDB->uninstallPackage($info);
+ $this->_dependencyDB->installPackage($info);
+ }
+ return $ret;
+ }
+
+ // }}}
+ // {{{ updateChannel()
+
+ /**
+ * For future expandibility purposes, separate this
+ * @param PEAR_ChannelFile
+ */
+ function updateChannel($channel, $lastmodified = null)
+ {
+ if ($channel->getName() == '__uri') {
+ return false;
+ }
+ return $this->addChannel($channel, $lastmodified, true);
+ }
+
+ // }}}
+ // {{{ deleteChannel()
+
+ /**
+ * Deletion fails if there are any packages installed from the channel
+ * @param string|PEAR_ChannelFile channel name
+ * @return boolean|PEAR_Error True on deletion, false if it doesn't exist
+ */
+ function deleteChannel($channel)
+ {
+ if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
+ return $e;
+ }
+
+ $ret = $this->_deleteChannel($channel);
+ $this->_unlock();
+ if ($ret && is_a($this->_config, 'PEAR_Config')) {
+ $this->_config->setChannels($this->listChannels());
+ }
+
+ return $ret;
+ }
+
+ // }}}
+ // {{{ addChannel()
+
+ /**
+ * @param PEAR_ChannelFile Channel object
+ * @param string Last-Modified header from HTTP for caching
+ * @return boolean|PEAR_Error True on creation, false if it already exists
+ */
+ function addChannel($channel, $lastmodified = false, $update = false)
+ {
+ if (!is_a($channel, 'PEAR_ChannelFile') || !$channel->validate()) {
+ return false;
+ }
+
+ if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
+ return $e;
+ }
+
+ $ret = $this->_addChannel($channel, $update, $lastmodified);
+ $this->_unlock();
+ if (!$update && $ret && is_a($this->_config, 'PEAR_Config')) {
+ $this->_config->setChannels($this->listChannels());
+ }
+
+ return $ret;
+ }
+
+ // }}}
+ // {{{ deletePackage()
+
+ function deletePackage($package, $channel = 'pear.php.net')
+ {
+ if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
+ return $e;
+ }
+
+ $file = $this->_packageFileName($package, $channel);
+ $ret = file_exists($file) ? @unlink($file) : false;
+ $this->_rebuildFileMap();
+ $this->_unlock();
+ $p = array('channel' => $channel, 'package' => $package);
+ $this->_dependencyDB->uninstallPackage($p);
+ return $ret;
+ }
+
+ // }}}
+ // {{{ updatePackage()
+
+ function updatePackage($package, $info, $merge = true)
+ {
+ if (is_object($info)) {
+ return $this->updatePackage2($info, $merge);
+ }
+ if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
+ return $e;
+ }
+ $ret = $this->_updatePackage($package, $info, $merge);
+ $this->_unlock();
+ if ($ret) {
+ if (!class_exists('PEAR_PackageFile_v1')) {
+ require_once 'PEAR/PackageFile/v1.php';
+ }
+ $pf = new PEAR_PackageFile_v1;
+ $pf->setConfig($this->_config);
+ $pf->fromArray($this->packageInfo($package));
+ $this->_dependencyDB->uninstallPackage($pf);
+ $this->_dependencyDB->installPackage($pf);
+ }
+ return $ret;
+ }
+
+ // }}}
+ // {{{ updatePackage2()
+
+ function updatePackage2($info)
+ {
+
+ if (!is_object($info)) {
+ return $this->updatePackage($info['package'], $info, $merge);
+ }
+
+ if (!$info->validate(PEAR_VALIDATE_DOWNLOADING)) {
+ return false;
+ }
+
+ if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
+ return $e;
+ }
+
+ $ret = $this->_updatePackage2($info);
+ $this->_unlock();
+ if ($ret) {
+ $this->_dependencyDB->uninstallPackage($info);
+ $this->_dependencyDB->installPackage($info);
+ }
+
+ return $ret;
+ }
+
+ // }}}
+ // {{{ getChannel()
+ /**
+ * @param string channel name
+ * @param bool whether to strictly return raw channels (no aliases)
+ * @return PEAR_ChannelFile|PEAR_Error
+ */
+ function getChannel($channel, $noaliases = false)
+ {
+ if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
+ return $e;
+ }
+ $ret = $this->_getChannel($channel, $noaliases);
+ $this->_unlock();
+ if (!$ret) {
+ return PEAR::raiseError('Unknown channel: ' . $channel);
+ }
+ return $ret;
+ }
+
+ // }}}
+ // {{{ getPackage()
+ /**
+ * @param string package name
+ * @param string channel name
+ * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|null
+ */
+ function &getPackage($package, $channel = 'pear.php.net')
+ {
+ if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
+ return $e;
+ }
+ $pf = &$this->_getPackage($package, $channel);
+ $this->_unlock();
+ return $pf;
+ }
+
+ // }}}
+
+ /**
+ * Get PEAR_PackageFile_v[1/2] objects representing the contents of
+ * a dependency group that are installed.
+ *
+ * This is used at uninstall-time
+ * @param array
+ * @return array|false
+ */
+ function getInstalledGroup($group)
+ {
+ $ret = array();
+ if (isset($group['package'])) {
+ if (!isset($group['package'][0])) {
+ $group['package'] = array($group['package']);
+ }
+ foreach ($group['package'] as $package) {
+ $depchannel = isset($package['channel']) ? $package['channel'] : '__uri';
+ $p = &$this->getPackage($package['name'], $depchannel);
+ if ($p) {
+ $save = &$p;
+ $ret[] = &$save;
+ }
+ }
+ }
+ if (isset($group['subpackage'])) {
+ if (!isset($group['subpackage'][0])) {
+ $group['subpackage'] = array($group['subpackage']);
+ }
+ foreach ($group['subpackage'] as $package) {
+ $depchannel = isset($package['channel']) ? $package['channel'] : '__uri';
+ $p = &$this->getPackage($package['name'], $depchannel);
+ if ($p) {
+ $save = &$p;
+ $ret[] = &$save;
+ }
+ }
+ }
+ if (!count($ret)) {
+ return false;
+ }
+ return $ret;
+ }
+
+ // {{{ getChannelValidator()
+ /**
+ * @param string channel name
+ * @return PEAR_Validate|false
+ */
+ function &getChannelValidator($channel)
+ {
+ $chan = $this->getChannel($channel);
+ if (PEAR::isError($chan)) {
+ return $chan;
+ }
+ $val = $chan->getValidationObject();
+ return $val;
+ }
+ // }}}
+ // {{{ getChannels()
+ /**
+ * @param string channel name
+ * @return array an array of PEAR_ChannelFile objects representing every installed channel
+ */
+ function &getChannels()
+ {
+ $ret = array();
+ if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
+ return $e;
+ }
+ foreach ($this->_listChannels() as $channel) {
+ $e = &$this->_getChannel($channel);
+ if (!$e || PEAR::isError($e)) {
+ continue;
+ }
+ $ret[] = $e;
+ }
+ $this->_unlock();
+ return $ret;
+ }
+
+ // }}}
+ // {{{ checkFileMap()
+
+ /**
+ * Test whether a file or set of files belongs to a package.
+ *
+ * If an array is passed in
+ * @param string|array file path, absolute or relative to the pear
+ * install dir
+ * @param string|array name of PEAR package or array('package' => name, 'channel' =>
+ * channel) of a package that will be ignored
+ * @param string API version - 1.1 will exclude any files belonging to a package
+ * @param array private recursion variable
+ * @return array|false which package and channel the file belongs to, or an empty
+ * string if the file does not belong to an installed package,
+ * or belongs to the second parameter's package
+ */
+ function checkFileMap($path, $package = false, $api = '1.0', $attrs = false)
+ {
+ if (is_array($path)) {
+ static $notempty;
+ if (empty($notempty)) {
+ if (!class_exists('PEAR_Installer_Role')) {
+ require_once 'PEAR/Installer/Role.php';
+ }
+ $notempty = create_function('$a','return !empty($a);');
+ }
+ $package = is_array($package) ? array(strtolower($package[0]), strtolower($package[1]))
+ : strtolower($package);
+ $pkgs = array();
+ foreach ($path as $name => $attrs) {
+ if (is_array($attrs)) {
+ if (isset($attrs['install-as'])) {
+ $name = $attrs['install-as'];
+ }
+ if (!in_array($attrs['role'], PEAR_Installer_Role::getInstallableRoles())) {
+ // these are not installed
+ continue;
+ }
+ if (!in_array($attrs['role'], PEAR_Installer_Role::getBaseinstallRoles())) {
+ $attrs['baseinstalldir'] = is_array($package) ? $package[1] : $package;
+ }
+ if (isset($attrs['baseinstalldir'])) {
+ $name = $attrs['baseinstalldir'] . DIRECTORY_SEPARATOR . $name;
+ }
+ }
+ $pkgs[$name] = $this->checkFileMap($name, $package, $api, $attrs);
+ if (PEAR::isError($pkgs[$name])) {
+ return $pkgs[$name];
+ }
+ }
+ return array_filter($pkgs, $notempty);
+ }
+ if (empty($this->filemap_cache)) {
+ if (PEAR::isError($e = $this->_lock(LOCK_SH))) {
+ return $e;
+ }
+ $err = $this->_readFileMap();
+ $this->_unlock();
+ if (PEAR::isError($err)) {
+ return $err;
+ }
+ }
+ if (!$attrs) {
+ $attrs = array('role' => 'php'); // any old call would be for PHP role only
+ }
+ if (isset($this->filemap_cache[$attrs['role']][$path])) {
+ if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path] == $package) {
+ return false;
+ }
+ return $this->filemap_cache[$attrs['role']][$path];
+ }
+ $l = strlen($this->install_dir);
+ if (substr($path, 0, $l) == $this->install_dir) {
+ $path = preg_replace('!^'.DIRECTORY_SEPARATOR.'+!', '', substr($path, $l));
+ }
+ if (isset($this->filemap_cache[$attrs['role']][$path])) {
+ if ($api >= '1.1' && $this->filemap_cache[$attrs['role']][$path] == $package) {
+ return false;
+ }
+ return $this->filemap_cache[$attrs['role']][$path];
+ }
+ return false;
+ }
+
+ // }}}
+ // {{{ flush()
+ /**
+ * Force a reload of the filemap
+ * @since 1.5.0RC3
+ */
+ function flushFileMap()
+ {
+ $this->filemap_cache = null;
+ clearstatcache(); // ensure that the next read gets the full, current filemap
+ }
+
+ // }}}
+ // {{{ apiVersion()
+ /**
+ * Get the expected API version. Channels API is version 1.1, as it is backwards
+ * compatible with 1.0
+ * @return string
+ */
+ function apiVersion()
+ {
+ return '1.1';
+ }
+ // }}}
+
+
+ /**
+ * Parse a package name, or validate a parsed package name array
+ * @param string|array pass in an array of format
+ * array(
+ * 'package' => 'pname',
+ * ['channel' => 'channame',]
+ * ['version' => 'version',]
+ * ['state' => 'state',]
+ * ['group' => 'groupname'])
+ * or a string of format
+ * [channel://][channame/]pname[-version|-state][/group=groupname]
+ * @return array|PEAR_Error
+ */
+ function parsePackageName($param, $defaultchannel = 'pear.php.net')
+ {
+ $saveparam = $param;
+ if (is_array($param)) {
+ // convert to string for error messages
+ $saveparam = $this->parsedPackageNameToString($param);
+ // process the array
+ if (!isset($param['package'])) {
+ return PEAR::raiseError('parsePackageName(): array $param ' .
+ 'must contain a valid package name in index "param"',
+ 'package', null, null, $param);
+ }
+ if (!isset($param['uri'])) {
+ if (!isset($param['channel'])) {
+ $param['channel'] = $defaultchannel;
+ }
+ } else {
+ $param['channel'] = '__uri';
+ }
+ } else {
+ $components = @parse_url((string) $param);
+ if (isset($components['scheme'])) {
+ if ($components['scheme'] == 'http') {
+ // uri package
+ $param = array('uri' => $param, 'channel' => '__uri');
+ } elseif($components['scheme'] != 'channel') {
+ return PEAR::raiseError('parsePackageName(): only channel:// uris may ' .
+ 'be downloaded, not "' . $param . '"', 'invalid', null, null, $param);
+ }
+ }
+ if (!isset($components['path'])) {
+ return PEAR::raiseError('parsePackageName(): array $param ' .
+ 'must contain a valid package name in "' . $param . '"',
+ 'package', null, null, $param);
+ }
+ if (isset($components['host'])) {
+ // remove the leading "/"
+ $components['path'] = substr($components['path'], 1);
+ }
+ if (!isset($components['scheme'])) {
+ if (strpos($components['path'], '/') !== false) {
+ if ($components['path']{0} == '/') {
+ return PEAR::raiseError('parsePackageName(): this is not ' .
+ 'a package name, it begins with "/" in "' . $param . '"',
+ 'invalid', null, null, $param);
+ }
+ $parts = explode('/', $components['path']);
+ $components['host'] = array_shift($parts);
+ if (count($parts) > 1) {
+ $components['path'] = array_pop($parts);
+ $components['host'] .= '/' . implode('/', $parts);
+ } else {
+ $components['path'] = implode('/', $parts);
+ }
+ } else {
+ $components['host'] = $defaultchannel;
+ }
+ } else {
+ if (strpos($components['path'], '/')) {
+ $parts = explode('/', $components['path']);
+ $components['path'] = array_pop($parts);
+ $components['host'] .= '/' . implode('/', $parts);
+ }
+ }
+
+ if (is_array($param)) {
+ $param['package'] = $components['path'];
+ } else {
+ $param = array(
+ 'package' => $components['path']
+ );
+ if (isset($components['host'])) {
+ $param['channel'] = $components['host'];
+ }
+ }
+ if (isset($components['fragment'])) {
+ $param['group'] = $components['fragment'];
+ }
+ if (isset($components['user'])) {
+ $param['user'] = $components['user'];
+ }
+ if (isset($components['pass'])) {
+ $param['pass'] = $components['pass'];
+ }
+ if (isset($components['query'])) {
+ parse_str($components['query'], $param['opts']);
+ }
+ // check for extension
+ $pathinfo = pathinfo($param['package']);
+ if (isset($pathinfo['extension']) &&
+ in_array(strtolower($pathinfo['extension']), array('tgz', 'tar'))) {
+ $param['extension'] = $pathinfo['extension'];
+ $param['package'] = substr($pathinfo['basename'], 0,
+ strlen($pathinfo['basename']) - 4);
+ }
+ // check for version
+ if (strpos($param['package'], '-')) {
+ $test = explode('-', $param['package']);
+ if (count($test) != 2) {
+ return PEAR::raiseError('parsePackageName(): only one version/state ' .
+ 'delimiter "-" is allowed in "' . $saveparam . '"',
+ 'version', null, null, $param);
+ }
+ list($param['package'], $param['version']) = $test;
+ }
+ }
+ // validation
+ $info = $this->channelExists($param['channel']);
+ if (PEAR::isError($info)) {
+ return $info;
+ }
+ if (!$info) {
+ return PEAR::raiseError('unknown channel "' . $param['channel'] .
+ '" in "' . $saveparam . '"', 'channel', null, null, $param);
+ }
+ $chan = $this->getChannel($param['channel']);
+ if (PEAR::isError($chan)) {
+ return $chan;
+ }
+ if (!$chan) {
+ return PEAR::raiseError("Exception: corrupt registry, could not " .
+ "retrieve channel " . $param['channel'] . " information",
+ 'registry', null, null, $param);
+ }
+ $param['channel'] = $chan->getName();
+ $validate = $chan->getValidationObject();
+ $vpackage = $chan->getValidationPackage();
+ // validate package name
+ if (!$validate->validPackageName($param['package'], $vpackage['_content'])) {
+ return PEAR::raiseError('parsePackageName(): invalid package name "' .
+ $param['package'] . '" in "' . $saveparam . '"',
+ 'package', null, null, $param);
+ }
+ if (isset($param['group'])) {
+ if (!PEAR_Validate::validGroupName($param['group'])) {
+ return PEAR::raiseError('parsePackageName(): dependency group "' . $param['group'] .
+ '" is not a valid group name in "' . $saveparam . '"', 'group', null, null,
+ $param);
+ }
+ }
+ if (isset($param['state'])) {
+ if (!in_array(strtolower($param['state']), $validate->getValidStates())) {
+ return PEAR::raiseError('parsePackageName(): state "' . $param['state']
+ . '" is not a valid state in "' . $saveparam . '"',
+ 'state', null, null, $param);
+ }
+ }
+ if (isset($param['version'])) {
+ if (isset($param['state'])) {
+ return PEAR::raiseError('parsePackageName(): cannot contain both ' .
+ 'a version and a stability (state) in "' . $saveparam . '"',
+ 'version/state', null, null, $param);
+ }
+ // check whether version is actually a state
+ if (in_array(strtolower($param['version']), $validate->getValidStates())) {
+ $param['state'] = strtolower($param['version']);
+ unset($param['version']);
+ } else {
+ if (!$validate->validVersion($param['version'])) {
+ return PEAR::raiseError('parsePackageName(): "' . $param['version'] .
+ '" is neither a valid version nor a valid state in "' .
+ $saveparam . '"', 'version/state', null, null, $param);
+ }
+ }
+ }
+ return $param;
+ }
+
+ /**
+ * @param array
+ * @return string
+ */
+ function parsedPackageNameToString($parsed, $brief = false)
+ {
+ if (is_string($parsed)) {
+ return $parsed;
+ }
+ if (is_object($parsed)) {
+ $p = $parsed;
+ $parsed = array(
+ 'package' => $p->getPackage(),
+ 'channel' => $p->getChannel(),
+ 'version' => $p->getVersion(),
+ );
+ }
+ if (isset($parsed['uri'])) {
+ return $parsed['uri'];
+ }
+ if ($brief) {
+ if ($channel = $this->channelAlias($parsed['channel'])) {
+ return $channel . '/' . $parsed['package'];
+ }
+ }
+ $upass = '';
+ if (isset($parsed['user'])) {
+ $upass = $parsed['user'];
+ if (isset($parsed['pass'])) {
+ $upass .= ':' . $parsed['pass'];
+ }
+ $upass = "$upass@";
+ }
+ $ret = 'channel://' . $upass . $parsed['channel'] . '/' . $parsed['package'];
+ if (isset($parsed['version']) || isset($parsed['state'])) {
+ $ver = isset($parsed['version']) ? $parsed['version'] : '';
+ $ver .= isset($parsed['state']) ? $parsed['state'] : '';
+ $ret .= '-' . $ver;
+ }
+ if (isset($parsed['extension'])) {
+ $ret .= '.' . $parsed['extension'];
+ }
+ if (isset($parsed['opts'])) {
+ $ret .= '?';
+ foreach ($parsed['opts'] as $name => $value) {
+ $parsed['opts'][$name] = "$name=$value";
+ }
+ $ret .= implode('&', $parsed['opts']);
+ }
+ if (isset($parsed['group'])) {
+ $ret .= '#' . $parsed['group'];
+ }
+ return $ret;
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/RunTest.php b/vendor/pear-pear.php.net/PEAR/PEAR/RunTest.php
new file mode 100644
index 000000000..271ef86bd
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/RunTest.php
@@ -0,0 +1,972 @@
+
+ * @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
+ */
+
+/**
+ * for error handling
+ */
+require_once 'PEAR.php';
+require_once 'PEAR/Config.php';
+
+define('DETAILED', 1);
+putenv("PHP_PEAR_RUNTESTS=1");
+
+/**
+ * Simplified version of PHP's test suite
+ *
+ * Try it with:
+ *
+ * $ php -r 'include "../PEAR/RunTest.php"; $t=new PEAR_RunTest; $o=$t->run("./pear_system.phpt");print_r($o);'
+ *
+ *
+ * @category pear
+ * @package PEAR
+ * @author Tomas V.V.Cox
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.3.3
+ */
+class PEAR_RunTest
+{
+ var $_headers = array();
+ var $_logger;
+ var $_options;
+ var $_php;
+ var $tests_count;
+ var $xdebug_loaded;
+ /**
+ * Saved value of php executable, used to reset $_php when we
+ * have a test that uses cgi
+ *
+ * @var unknown_type
+ */
+ var $_savephp;
+ var $ini_overwrites = array(
+ 'output_handler=',
+ 'open_basedir=',
+ 'disable_functions=',
+ 'output_buffering=Off',
+ 'display_errors=1',
+ 'log_errors=0',
+ 'html_errors=0',
+ 'track_errors=1',
+ 'report_memleaks=0',
+ 'report_zend_debug=0',
+ 'docref_root=',
+ 'docref_ext=.html',
+ 'error_prepend_string=',
+ 'error_append_string=',
+ 'auto_prepend_file=',
+ 'auto_append_file=',
+ 'xdebug.default_enable=0',
+ 'allow_url_fopen=1',
+ );
+
+ /**
+ * An object that supports the PEAR_Common->log() signature, or null
+ * @param PEAR_Common|null
+ */
+ function __construct($logger = null, $options = array())
+ {
+ if (!defined('E_DEPRECATED')) {
+ define('E_DEPRECATED', 0);
+ }
+ if (!defined('E_STRICT')) {
+ define('E_STRICT', 0);
+ }
+ $this->ini_overwrites[] = 'error_reporting=' . (E_ALL & ~(E_DEPRECATED | E_STRICT));
+ if (is_null($logger)) {
+ require_once 'PEAR/Common.php';
+ $logger = new PEAR_Common;
+ }
+ $this->_logger = $logger;
+ $this->_options = $options;
+
+ $conf = &PEAR_Config::singleton();
+ $this->_php = $conf->get('php_bin');
+ }
+
+ /**
+ * Taken from php-src/run-tests.php
+ *
+ * @param string $commandline command name
+ * @param array $env
+ * @param string $stdin standard input to pass to the command
+ * @return unknown
+ */
+ function system_with_timeout($commandline, $env = null, $stdin = null)
+ {
+ $data = '';
+ $proc = proc_open($commandline, array(
+ 0 => array('pipe', 'r'),
+ 1 => array('pipe', 'w'),
+ 2 => array('pipe', 'w')
+ ), $pipes, null, $env, array('suppress_errors' => true));
+
+ if (!$proc) {
+ return false;
+ }
+
+ if (is_string($stdin)) {
+ fwrite($pipes[0], $stdin);
+ }
+ fclose($pipes[0]);
+
+ while (true) {
+ /* hide errors from interrupted syscalls */
+ $r = $pipes;
+ $e = $w = null;
+ $n = @stream_select($r, $w, $e, 60);
+
+ if ($n === 0) {
+ /* timed out */
+ $data .= "\n ** ERROR: process timed out **\n";
+ proc_terminate($proc);
+ return array(1234567890, $data);
+ } else if ($n > 0) {
+ $line = fread($pipes[1], 8192);
+ if (strlen($line) == 0) {
+ /* EOF */
+ break;
+ }
+ $data .= $line;
+ }
+ }
+ if (function_exists('proc_get_status')) {
+ $stat = proc_get_status($proc);
+ if ($stat['signaled']) {
+ $data .= "\nTermsig=".$stat['stopsig'];
+ }
+ }
+ $code = proc_close($proc);
+ if (function_exists('proc_get_status')) {
+ $code = $stat['exitcode'];
+ }
+ return array($code, $data);
+ }
+
+ /**
+ * Turns a PHP INI string into an array
+ *
+ * Turns -d "include_path=/foo/bar" into this:
+ * array(
+ * 'include_path' => array(
+ * 'operator' => '-d',
+ * 'value' => '/foo/bar',
+ * )
+ * )
+ * Works both with quotes and without
+ *
+ * @param string an PHP INI string, -d "include_path=/foo/bar"
+ * @return array
+ */
+ function iniString2array($ini_string)
+ {
+ if (!$ini_string) {
+ return array();
+ }
+ $split = preg_split('/[\s]|=/', $ini_string, -1, PREG_SPLIT_NO_EMPTY);
+ $key = $split[1][0] == '"' ? substr($split[1], 1) : $split[1];
+ $value = $split[2][strlen($split[2]) - 1] == '"' ? substr($split[2], 0, -1) : $split[2];
+ // FIXME review if this is really the struct to go with
+ $array = array($key => array('operator' => $split[0], 'value' => $value));
+ return $array;
+ }
+
+ function settings2array($settings, $ini_settings)
+ {
+ foreach ($settings as $setting) {
+ if (strpos($setting, '=') !== false) {
+ $setting = explode('=', $setting, 2);
+ $name = trim(strtolower($setting[0]));
+ $value = trim($setting[1]);
+ $ini_settings[$name] = $value;
+ }
+ }
+ return $ini_settings;
+ }
+
+ function settings2params($ini_settings)
+ {
+ $settings = '';
+ foreach ($ini_settings as $name => $value) {
+ if (is_array($value)) {
+ $operator = $value['operator'];
+ $value = $value['value'];
+ } else {
+ $operator = '-d';
+ }
+ $value = addslashes($value);
+ $settings .= " $operator \"$name=$value\"";
+ }
+ return $settings;
+ }
+
+ function _preparePhpBin($php, $file, $ini_settings)
+ {
+ $file = escapeshellarg($file);
+ $cmd = $php . $ini_settings . ' -f ' . $file;
+
+ return $cmd;
+ }
+
+ function runPHPUnit($file, $ini_settings = '')
+ {
+ if (!file_exists($file) && file_exists(getcwd() . DIRECTORY_SEPARATOR . $file)) {
+ $file = realpath(getcwd() . DIRECTORY_SEPARATOR . $file);
+ } elseif (file_exists($file)) {
+ $file = realpath($file);
+ }
+
+ $cmd = $this->_preparePhpBin($this->_php, $file, $ini_settings);
+ if (isset($this->_logger)) {
+ $this->_logger->log(2, 'Running command "' . $cmd . '"');
+ }
+
+ $savedir = getcwd(); // in case the test moves us around
+ chdir(dirname($file));
+ echo `$cmd`;
+ chdir($savedir);
+ return 'PASSED'; // we have no way of knowing this information so assume passing
+ }
+
+ /**
+ * Runs an individual test case.
+ *
+ * @param string The filename of the test
+ * @param array|string INI settings to be applied to the test run
+ * @param integer Number what the current running test is of the
+ * whole test suite being runned.
+ *
+ * @return string|object Returns PASSED, WARNED, FAILED depending on how the
+ * test came out.
+ * PEAR Error when the tester it self fails
+ */
+ function run($file, $ini_settings = array(), $test_number = 1)
+ {
+ $this->_restorePHPBinary();
+
+ if (empty($this->_options['cgi'])) {
+ // try to see if php-cgi is in the path
+ $res = $this->system_with_timeout('php-cgi -v');
+ if (false !== $res && !(is_array($res) && in_array($res[0], array(-1, 127)))) {
+ $this->_options['cgi'] = 'php-cgi';
+ }
+ }
+ if (1 < $len = strlen($this->tests_count)) {
+ $test_number = str_pad($test_number, $len, ' ', STR_PAD_LEFT);
+ $test_nr = "[$test_number/$this->tests_count] ";
+ } else {
+ $test_nr = '';
+ }
+
+ $file = realpath($file);
+ $section_text = $this->_readFile($file);
+ if (PEAR::isError($section_text)) {
+ return $section_text;
+ }
+
+ if (isset($section_text['POST_RAW']) && isset($section_text['UPLOAD'])) {
+ return PEAR::raiseError("Cannot contain both POST_RAW and UPLOAD in test file: $file");
+ }
+
+ $cwd = getcwd();
+
+ $pass_options = '';
+ if (!empty($this->_options['ini'])) {
+ $pass_options = $this->_options['ini'];
+ }
+
+ if (is_string($ini_settings)) {
+ $ini_settings = $this->iniString2array($ini_settings);
+ }
+
+ $ini_settings = $this->settings2array($this->ini_overwrites, $ini_settings);
+ if ($section_text['INI']) {
+ if (strpos($section_text['INI'], '{PWD}') !== false) {
+ $section_text['INI'] = str_replace('{PWD}', dirname($file), $section_text['INI']);
+ }
+ $ini = preg_split( "/[\n\r]+/", $section_text['INI']);
+ $ini_settings = $this->settings2array($ini, $ini_settings);
+ }
+ $ini_settings = $this->settings2params($ini_settings);
+ $shortname = str_replace($cwd . DIRECTORY_SEPARATOR, '', $file);
+
+ $tested = trim($section_text['TEST']);
+ $tested.= !isset($this->_options['simple']) ? "[$shortname]" : ' ';
+
+ if (!empty($section_text['POST']) || !empty($section_text['POST_RAW']) ||
+ !empty($section_text['UPLOAD']) || !empty($section_text['GET']) ||
+ !empty($section_text['COOKIE']) || !empty($section_text['EXPECTHEADERS'])) {
+ if (empty($this->_options['cgi'])) {
+ if (!isset($this->_options['quiet'])) {
+ $this->_logger->log(0, "SKIP $test_nr$tested (reason: --cgi option needed for this test, type 'pear help run-tests')");
+ }
+ if (isset($this->_options['tapoutput'])) {
+ return array('ok', ' # skip --cgi option needed for this test, "pear help run-tests" for info');
+ }
+ return 'SKIPPED';
+ }
+ $this->_savePHPBinary();
+ $this->_php = $this->_options['cgi'];
+ }
+
+ $temp_dir = realpath(dirname($file));
+ $main_file_name = basename($file, 'phpt');
+ $diff_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'diff';
+ $log_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'log';
+ $exp_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'exp';
+ $output_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'out';
+ $memcheck_filename = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'mem';
+ $temp_file = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'php';
+ $temp_skipif = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'skip.php';
+ $temp_clean = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name.'clean.php';
+ $tmp_post = $temp_dir . DIRECTORY_SEPARATOR . uniqid('phpt.');
+
+ // unlink old test results
+ $this->_cleanupOldFiles($file);
+
+ // Check if test should be skipped.
+ $res = $this->_runSkipIf($section_text, $temp_skipif, $tested, $ini_settings);
+ if (count($res) != 2) {
+ return $res;
+ }
+ $info = $res['info'];
+ $warn = $res['warn'];
+
+ // We've satisfied the preconditions - run the test!
+ if (isset($this->_options['coverage']) && $this->xdebug_loaded) {
+ $xdebug_file = $temp_dir . DIRECTORY_SEPARATOR . $main_file_name . 'xdebug';
+ $text = "\n" . 'function coverage_shutdown() {' .
+ "\n" . ' $xdebug = var_export(xdebug_get_code_coverage(), true);';
+ if (!function_exists('file_put_contents')) {
+ $text .= "\n" . ' $fh = fopen(\'' . $xdebug_file . '\', "wb");' .
+ "\n" . ' if ($fh !== false) {' .
+ "\n" . ' fwrite($fh, $xdebug);' .
+ "\n" . ' fclose($fh);' .
+ "\n" . ' }';
+ } else {
+ $text .= "\n" . ' file_put_contents(\'' . $xdebug_file . '\', $xdebug);';
+ }
+
+ // Workaround for http://pear.php.net/bugs/bug.php?id=17292
+ $lines = explode("\n", $section_text['FILE']);
+ $numLines = count($lines);
+ $namespace = '';
+ $coverage_shutdown = 'coverage_shutdown';
+
+ if (
+ substr($lines[0], 0, 2) == '' ||
+ substr($lines[0], 0, 5) == 'save_text($temp_file, "save_text($temp_file, $section_text['FILE']);
+ }
+
+ $args = $section_text['ARGS'] ? ' -- '.$section_text['ARGS'] : '';
+ $cmd = $this->_preparePhpBin($this->_php, $temp_file, $ini_settings);
+ $cmd.= "$args 2>&1";
+ if (isset($this->_logger)) {
+ $this->_logger->log(2, 'Running command "' . $cmd . '"');
+ }
+
+ // Reset environment from any previous test.
+ $env = $this->_resetEnv($section_text, $temp_file);
+
+ $section_text = $this->_processUpload($section_text, $file);
+ if (PEAR::isError($section_text)) {
+ return $section_text;
+ }
+
+ if (array_key_exists('POST_RAW', $section_text) && !empty($section_text['POST_RAW'])) {
+ $post = trim($section_text['POST_RAW']);
+ $raw_lines = explode("\n", $post);
+
+ $request = '';
+ $started = false;
+ foreach ($raw_lines as $i => $line) {
+ if (empty($env['CONTENT_TYPE']) &&
+ preg_match('/^Content-Type:(.*)/i', $line, $res)) {
+ $env['CONTENT_TYPE'] = trim(str_replace("\r", '', $res[1]));
+ continue;
+ }
+ if ($started) {
+ $request .= "\n";
+ }
+ $started = true;
+ $request .= $line;
+ }
+
+ $env['CONTENT_LENGTH'] = strlen($request);
+ $env['REQUEST_METHOD'] = 'POST';
+
+ $this->save_text($tmp_post, $request);
+ $cmd = "$this->_php$pass_options$ini_settings \"$temp_file\" 2>&1 < $tmp_post";
+ } elseif (array_key_exists('POST', $section_text) && !empty($section_text['POST'])) {
+ $post = trim($section_text['POST']);
+ $this->save_text($tmp_post, $post);
+ $content_length = strlen($post);
+
+ $env['REQUEST_METHOD'] = 'POST';
+ $env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
+ $env['CONTENT_LENGTH'] = $content_length;
+
+ $cmd = "$this->_php$pass_options$ini_settings \"$temp_file\" 2>&1 < $tmp_post";
+ } else {
+ $env['REQUEST_METHOD'] = 'GET';
+ $env['CONTENT_TYPE'] = '';
+ $env['CONTENT_LENGTH'] = '';
+ }
+
+ if (OS_WINDOWS && isset($section_text['RETURNS'])) {
+ ob_start();
+ system($cmd, $return_value);
+ $out = ob_get_contents();
+ ob_end_clean();
+ $section_text['RETURNS'] = (int) trim($section_text['RETURNS']);
+ $returnfail = ($return_value != $section_text['RETURNS']);
+ } else {
+ $returnfail = false;
+ $stdin = isset($section_text['STDIN']) ? $section_text['STDIN'] : null;
+ $out = $this->system_with_timeout($cmd, $env, $stdin);
+ $return_value = $out[0];
+ $out = $out[1];
+ }
+
+ $output = preg_replace('/\r\n/', "\n", trim($out));
+
+ if (isset($tmp_post) && realpath($tmp_post) && file_exists($tmp_post)) {
+ @unlink(realpath($tmp_post));
+ }
+ chdir($cwd); // in case the test moves us around
+
+ /* when using CGI, strip the headers from the output */
+ $output = $this->_stripHeadersCGI($output);
+
+ if (isset($section_text['EXPECTHEADERS'])) {
+ $testheaders = $this->_processHeaders($section_text['EXPECTHEADERS']);
+ $missing = array_diff_assoc($testheaders, $this->_headers);
+ $changed = '';
+ foreach ($missing as $header => $value) {
+ if (isset($this->_headers[$header])) {
+ $changed .= "-$header: $value\n+$header: ";
+ $changed .= $this->_headers[$header];
+ } else {
+ $changed .= "-$header: $value\n";
+ }
+ }
+ if ($missing) {
+ // tack on failed headers to output:
+ $output .= "\n====EXPECTHEADERS FAILURE====:\n$changed";
+ }
+ }
+
+ $this->_testCleanup($section_text, $temp_clean);
+
+ // Does the output match what is expected?
+ do {
+ if (isset($section_text['EXPECTF']) || isset($section_text['EXPECTREGEX'])) {
+ if (isset($section_text['EXPECTF'])) {
+ $wanted = trim($section_text['EXPECTF']);
+ } else {
+ $wanted = trim($section_text['EXPECTREGEX']);
+ }
+ $wanted_re = preg_replace('/\r\n/', "\n", $wanted);
+ if (isset($section_text['EXPECTF'])) {
+ $wanted_re = preg_quote($wanted_re, '/');
+ // Stick to basics
+ $wanted_re = str_replace("%s", ".+?", $wanted_re); //not greedy
+ $wanted_re = str_replace("%i", "[+\-]?[0-9]+", $wanted_re);
+ $wanted_re = str_replace("%d", "[0-9]+", $wanted_re);
+ $wanted_re = str_replace("%x", "[0-9a-fA-F]+", $wanted_re);
+ $wanted_re = str_replace("%f", "[+\-]?\.?[0-9]+\.?[0-9]*(E-?[0-9]+)?", $wanted_re);
+ $wanted_re = str_replace("%c", ".", $wanted_re);
+ // %f allows two points "-.0.0" but that is the best *simple* expression
+ }
+
+ /* DEBUG YOUR REGEX HERE
+ var_dump($wanted_re);
+ print(str_repeat('=', 80) . "\n");
+ var_dump($output);
+ */
+ if (!$returnfail && preg_match("/^$wanted_re\$/s", $output)) {
+ if (file_exists($temp_file)) {
+ unlink($temp_file);
+ }
+ if (array_key_exists('FAIL', $section_text)) {
+ break;
+ }
+ if (!isset($this->_options['quiet'])) {
+ $this->_logger->log(0, "PASS $test_nr$tested$info");
+ }
+ if (isset($this->_options['tapoutput'])) {
+ return array('ok', ' - ' . $tested);
+ }
+ return 'PASSED';
+ }
+ } else {
+ if (isset($section_text['EXPECTFILE'])) {
+ $f = $temp_dir . '/' . trim($section_text['EXPECTFILE']);
+ if (!($fp = @fopen($f, 'rb'))) {
+ return PEAR::raiseError('--EXPECTFILE-- section file ' .
+ $f . ' not found');
+ }
+ fclose($fp);
+ $section_text['EXPECT'] = file_get_contents($f);
+ }
+
+ if (isset($section_text['EXPECT'])) {
+ $wanted = preg_replace('/\r\n/', "\n", trim($section_text['EXPECT']));
+ } else {
+ $wanted = '';
+ }
+
+ // compare and leave on success
+ if (!$returnfail && 0 == strcmp($output, $wanted)) {
+ if (file_exists($temp_file)) {
+ unlink($temp_file);
+ }
+ if (array_key_exists('FAIL', $section_text)) {
+ break;
+ }
+ if (!isset($this->_options['quiet'])) {
+ $this->_logger->log(0, "PASS $test_nr$tested$info");
+ }
+ if (isset($this->_options['tapoutput'])) {
+ return array('ok', ' - ' . $tested);
+ }
+ return 'PASSED';
+ }
+ }
+ } while (false);
+
+ if (array_key_exists('FAIL', $section_text)) {
+ // we expect a particular failure
+ // this is only used for testing PEAR_RunTest
+ $expectf = isset($section_text['EXPECTF']) ? $wanted_re : null;
+ $faildiff = $this->generate_diff($wanted, $output, null, $expectf);
+ $faildiff = preg_replace('/\r/', '', $faildiff);
+ $wanted = preg_replace('/\r/', '', trim($section_text['FAIL']));
+ if ($faildiff == $wanted) {
+ if (!isset($this->_options['quiet'])) {
+ $this->_logger->log(0, "PASS $test_nr$tested$info");
+ }
+ if (isset($this->_options['tapoutput'])) {
+ return array('ok', ' - ' . $tested);
+ }
+ return 'PASSED';
+ }
+ unset($section_text['EXPECTF']);
+ $output = $faildiff;
+ if (isset($section_text['RETURNS'])) {
+ return PEAR::raiseError('Cannot have both RETURNS and FAIL in the same test: ' .
+ $file);
+ }
+ }
+
+ // Test failed so we need to report details.
+ $txt = $warn ? 'WARN ' : 'FAIL ';
+ $this->_logger->log(0, $txt . $test_nr . $tested . $info);
+
+ // write .exp
+ $res = $this->_writeLog($exp_filename, $wanted);
+ if (PEAR::isError($res)) {
+ return $res;
+ }
+
+ // write .out
+ $res = $this->_writeLog($output_filename, $output);
+ if (PEAR::isError($res)) {
+ return $res;
+ }
+
+ // write .diff
+ $returns = isset($section_text['RETURNS']) ?
+ array(trim($section_text['RETURNS']), $return_value) : null;
+ $expectf = isset($section_text['EXPECTF']) ? $wanted_re : null;
+ $data = $this->generate_diff($wanted, $output, $returns, $expectf);
+ $res = $this->_writeLog($diff_filename, $data);
+ if (isset($this->_options['showdiff'])) {
+ $this->_logger->log(0, "========DIFF========");
+ $this->_logger->log(0, $data);
+ $this->_logger->log(0, "========DONE========");
+ }
+ if (PEAR::isError($res)) {
+ return $res;
+ }
+
+ // write .log
+ $data = "
+---- EXPECTED OUTPUT
+$wanted
+---- ACTUAL OUTPUT
+$output
+---- FAILED
+";
+
+ if ($returnfail) {
+ $data .= "
+---- EXPECTED RETURN
+$section_text[RETURNS]
+---- ACTUAL RETURN
+$return_value
+";
+ }
+
+ $res = $this->_writeLog($log_filename, $data);
+ if (PEAR::isError($res)) {
+ return $res;
+ }
+
+ if (isset($this->_options['tapoutput'])) {
+ $wanted = explode("\n", $wanted);
+ $wanted = "# Expected output:\n#\n#" . implode("\n#", $wanted);
+ $output = explode("\n", $output);
+ $output = "#\n#\n# Actual output:\n#\n#" . implode("\n#", $output);
+ return array($wanted . $output . 'not ok', ' - ' . $tested);
+ }
+ return $warn ? 'WARNED' : 'FAILED';
+ }
+
+ function generate_diff($wanted, $output, $rvalue, $wanted_re)
+ {
+ $w = explode("\n", $wanted);
+ $o = explode("\n", $output);
+ $wr = explode("\n", $wanted_re);
+ $w1 = array_diff_assoc($w, $o);
+ $o1 = array_diff_assoc($o, $w);
+ $o2 = $w2 = array();
+ foreach ($w1 as $idx => $val) {
+ if (!$wanted_re || !isset($wr[$idx]) || !isset($o1[$idx]) ||
+ !preg_match('/^' . $wr[$idx] . '\\z/', $o1[$idx])) {
+ $w2[sprintf("%03d<", $idx)] = sprintf("%03d- ", $idx + 1) . $val;
+ }
+ }
+ foreach ($o1 as $idx => $val) {
+ if (!$wanted_re || !isset($wr[$idx]) ||
+ !preg_match('/^' . $wr[$idx] . '\\z/', $val)) {
+ $o2[sprintf("%03d>", $idx)] = sprintf("%03d+ ", $idx + 1) . $val;
+ }
+ }
+ $diff = array_merge($w2, $o2);
+ ksort($diff);
+ $extra = $rvalue ? "##EXPECTED: $rvalue[0]\r\n##RETURNED: $rvalue[1]" : '';
+ return implode("\r\n", $diff) . $extra;
+ }
+
+ // Write the given text to a temporary file, and return the filename.
+ function save_text($filename, $text)
+ {
+ if (!$fp = fopen($filename, 'w')) {
+ return PEAR::raiseError("Cannot open file '" . $filename . "' (save_text)");
+ }
+ fwrite($fp, $text);
+ fclose($fp);
+ if (1 < DETAILED) echo "
+FILE $filename {{{
+$text
+}}}
+";
+ }
+
+ function _cleanupOldFiles($file)
+ {
+ $temp_dir = realpath(dirname($file));
+ $mainFileName = basename($file, 'phpt');
+ $diff_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'diff';
+ $log_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'log';
+ $exp_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'exp';
+ $output_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'out';
+ $memcheck_filename = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'mem';
+ $temp_file = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'php';
+ $temp_skipif = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'skip.php';
+ $temp_clean = $temp_dir . DIRECTORY_SEPARATOR . $mainFileName.'clean.php';
+ $tmp_post = $temp_dir . DIRECTORY_SEPARATOR . uniqid('phpt.');
+
+ // unlink old test results
+ @unlink($diff_filename);
+ @unlink($log_filename);
+ @unlink($exp_filename);
+ @unlink($output_filename);
+ @unlink($memcheck_filename);
+ @unlink($temp_file);
+ @unlink($temp_skipif);
+ @unlink($tmp_post);
+ @unlink($temp_clean);
+ }
+
+ function _runSkipIf($section_text, $temp_skipif, $tested, $ini_settings)
+ {
+ $info = '';
+ $warn = false;
+ if (array_key_exists('SKIPIF', $section_text) && trim($section_text['SKIPIF'])) {
+ $this->save_text($temp_skipif, $section_text['SKIPIF']);
+ $output = $this->system_with_timeout("$this->_php$ini_settings -f \"$temp_skipif\"");
+ $output = $output[1];
+ $loutput = ltrim($output);
+ unlink($temp_skipif);
+ if (!strncasecmp('skip', $loutput, 4)) {
+ $skipreason = "SKIP $tested";
+ if (preg_match('/^\s*skip\s*(.+)\s*/i', $output, $m)) {
+ $skipreason .= '(reason: ' . $m[1] . ')';
+ }
+ if (!isset($this->_options['quiet'])) {
+ $this->_logger->log(0, $skipreason);
+ }
+ if (isset($this->_options['tapoutput'])) {
+ return array('ok', ' # skip ' . $reason);
+ }
+ return 'SKIPPED';
+ }
+
+ if (!strncasecmp('info', $loutput, 4)
+ && preg_match('/^\s*info\s*(.+)\s*/i', $output, $m)) {
+ $info = " (info: $m[1])";
+ }
+
+ if (!strncasecmp('warn', $loutput, 4)
+ && preg_match('/^\s*warn\s*(.+)\s*/i', $output, $m)) {
+ $warn = true; /* only if there is a reason */
+ $info = " (warn: $m[1])";
+ }
+ }
+
+ return array('warn' => $warn, 'info' => $info);
+ }
+
+ function _stripHeadersCGI($output)
+ {
+ $this->headers = array();
+ if (!empty($this->_options['cgi']) &&
+ $this->_php == $this->_options['cgi'] &&
+ preg_match("/^(.*?)(?:\n\n(.*)|\\z)/s", $output, $match)) {
+ $output = isset($match[2]) ? trim($match[2]) : '';
+ $this->_headers = $this->_processHeaders($match[1]);
+ }
+
+ return $output;
+ }
+
+ /**
+ * Return an array that can be used with array_diff() to compare headers
+ *
+ * @param string $text
+ */
+ function _processHeaders($text)
+ {
+ $headers = array();
+ $rh = preg_split("/[\n\r]+/", $text);
+ foreach ($rh as $line) {
+ if (strpos($line, ':')!== false) {
+ $line = explode(':', $line, 2);
+ $headers[trim($line[0])] = trim($line[1]);
+ }
+ }
+ return $headers;
+ }
+
+ function _readFile($file)
+ {
+ // Load the sections of the test file.
+ $section_text = array(
+ 'TEST' => '(unnamed test)',
+ 'SKIPIF' => '',
+ 'GET' => '',
+ 'COOKIE' => '',
+ 'POST' => '',
+ 'ARGS' => '',
+ 'INI' => '',
+ 'CLEAN' => '',
+ );
+
+ if (!is_file($file) || !$fp = fopen($file, "r")) {
+ return PEAR::raiseError("Cannot open test file: $file");
+ }
+
+ $section = '';
+ while (!feof($fp)) {
+ $line = fgets($fp);
+
+ // Match the beginning of a section.
+ if (preg_match('/^--([_A-Z]+)--/', $line, $r)) {
+ $section = $r[1];
+ $section_text[$section] = '';
+ continue;
+ } elseif (empty($section)) {
+ fclose($fp);
+ return PEAR::raiseError("Invalid sections formats in test file: $file");
+ }
+
+ // Add to the section text.
+ $section_text[$section] .= $line;
+ }
+ fclose($fp);
+
+ return $section_text;
+ }
+
+ function _writeLog($logname, $data)
+ {
+ if (!$log = fopen($logname, 'w')) {
+ return PEAR::raiseError("Cannot create test log - $logname");
+ }
+ fwrite($log, $data);
+ fclose($log);
+ }
+
+ function _resetEnv($section_text, $temp_file)
+ {
+ $env = $_ENV;
+ $env['REDIRECT_STATUS'] = '';
+ $env['QUERY_STRING'] = '';
+ $env['PATH_TRANSLATED'] = '';
+ $env['SCRIPT_FILENAME'] = '';
+ $env['REQUEST_METHOD'] = '';
+ $env['CONTENT_TYPE'] = '';
+ $env['CONTENT_LENGTH'] = '';
+ if (!empty($section_text['ENV'])) {
+ if (strpos($section_text['ENV'], '{PWD}') !== false) {
+ $section_text['ENV'] = str_replace('{PWD}', dirname($temp_file), $section_text['ENV']);
+ }
+ foreach (explode("\n", trim($section_text['ENV'])) as $e) {
+ $e = explode('=', trim($e), 2);
+ if (!empty($e[0]) && isset($e[1])) {
+ $env[$e[0]] = $e[1];
+ }
+ }
+ }
+ if (array_key_exists('GET', $section_text)) {
+ $env['QUERY_STRING'] = trim($section_text['GET']);
+ } else {
+ $env['QUERY_STRING'] = '';
+ }
+ if (array_key_exists('COOKIE', $section_text)) {
+ $env['HTTP_COOKIE'] = trim($section_text['COOKIE']);
+ } else {
+ $env['HTTP_COOKIE'] = '';
+ }
+ $env['REDIRECT_STATUS'] = '1';
+ $env['PATH_TRANSLATED'] = $temp_file;
+ $env['SCRIPT_FILENAME'] = $temp_file;
+
+ return $env;
+ }
+
+ function _processUpload($section_text, $file)
+ {
+ if (array_key_exists('UPLOAD', $section_text) && !empty($section_text['UPLOAD'])) {
+ $upload_files = trim($section_text['UPLOAD']);
+ $upload_files = explode("\n", $upload_files);
+
+ $request = "Content-Type: multipart/form-data; boundary=---------------------------20896060251896012921717172737\n" .
+ "-----------------------------20896060251896012921717172737\n";
+ foreach ($upload_files as $fileinfo) {
+ $fileinfo = explode('=', $fileinfo);
+ if (count($fileinfo) != 2) {
+ return PEAR::raiseError("Invalid UPLOAD section in test file: $file");
+ }
+ if (!realpath(dirname($file) . '/' . $fileinfo[1])) {
+ return PEAR::raiseError("File for upload does not exist: $fileinfo[1] " .
+ "in test file: $file");
+ }
+ $file_contents = file_get_contents(dirname($file) . '/' . $fileinfo[1]);
+ $fileinfo[1] = basename($fileinfo[1]);
+ $request .= "Content-Disposition: form-data; name=\"$fileinfo[0]\"; filename=\"$fileinfo[1]\"\n";
+ $request .= "Content-Type: text/plain\n\n";
+ $request .= $file_contents . "\n" .
+ "-----------------------------20896060251896012921717172737\n";
+ }
+
+ if (array_key_exists('POST', $section_text) && !empty($section_text['POST'])) {
+ // encode POST raw
+ $post = trim($section_text['POST']);
+ $post = explode('&', $post);
+ foreach ($post as $i => $post_info) {
+ $post_info = explode('=', $post_info);
+ if (count($post_info) != 2) {
+ return PEAR::raiseError("Invalid POST data in test file: $file");
+ }
+ $post_info[0] = rawurldecode($post_info[0]);
+ $post_info[1] = rawurldecode($post_info[1]);
+ $post[$i] = $post_info;
+ }
+ foreach ($post as $post_info) {
+ $request .= "Content-Disposition: form-data; name=\"$post_info[0]\"\n\n";
+ $request .= $post_info[1] . "\n" .
+ "-----------------------------20896060251896012921717172737\n";
+ }
+ unset($section_text['POST']);
+ }
+ $section_text['POST_RAW'] = $request;
+ }
+
+ return $section_text;
+ }
+
+ function _testCleanup($section_text, $temp_clean)
+ {
+ if ($section_text['CLEAN']) {
+ $this->_restorePHPBinary();
+
+ // perform test cleanup
+ $this->save_text($temp_clean, $section_text['CLEAN']);
+ $output = $this->system_with_timeout("$this->_php $temp_clean 2>&1");
+ if (strlen($output[1])) {
+ echo "BORKED --CLEAN-- section! output:\n", $output[1];
+ }
+ if (file_exists($temp_clean)) {
+ unlink($temp_clean);
+ }
+ }
+ }
+
+ function _savePHPBinary()
+ {
+ $this->_savephp = $this->_php;
+ }
+
+ function _restorePHPBinary()
+ {
+ if (isset($this->_savephp))
+ {
+ $this->_php = $this->_savephp;
+ unset($this->_savephp);
+ }
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Task/Common.php b/vendor/pear-pear.php.net/PEAR/PEAR/Task/Common.php
new file mode 100644
index 000000000..e433c3e26
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Task/Common.php
@@ -0,0 +1,207 @@
+
+ * @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 codes for task validation routines
+ */
+define('PEAR_TASK_ERROR_NOATTRIBS', 1);
+define('PEAR_TASK_ERROR_MISSING_ATTRIB', 2);
+define('PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE', 3);
+define('PEAR_TASK_ERROR_INVALID', 4);
+/**#@-*/
+define('PEAR_TASK_PACKAGE', 1);
+define('PEAR_TASK_INSTALL', 2);
+define('PEAR_TASK_PACKAGEANDINSTALL', 3);
+/**
+ * A task is an operation that manipulates the contents of a file.
+ *
+ * Simple tasks operate on 1 file. Multiple tasks are executed after all files have been
+ * processed and installed, and are designed to operate on all files containing the task.
+ * The Post-install script task simply takes advantage of the fact that it will be run
+ * after installation, replace is a simple task.
+ *
+ * Combining tasks is possible, but ordering is significant.
+ *
+ *
+ *
+ *
+ *
+ *
+ * This will first replace any instance of @data-dir@ in the test.php file
+ * with the path to the current data directory. Then, it will include the
+ * test.php file and run the script it contains to configure the package post-installation.
+ *
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ * @abstract
+ */
+class PEAR_Task_Common
+{
+ /**
+ * Valid types for this version are 'simple' and 'multiple'
+ *
+ * - simple tasks operate on the contents of a file and write out changes to disk
+ * - multiple tasks operate on the contents of many files and write out the
+ * changes directly to disk
+ *
+ * Child task classes must override this property.
+ *
+ * @access protected
+ */
+ protected $type = 'simple';
+ /**
+ * Determines which install phase this task is executed under
+ */
+ public $phase = PEAR_TASK_INSTALL;
+ /**
+ * @access protected
+ */
+ protected $config;
+ /**
+ * @access protected
+ */
+ protected $registry;
+ /**
+ * @access protected
+ */
+ public $logger;
+ /**
+ * @access protected
+ */
+ protected $installphase;
+ /**
+ * @param PEAR_Config
+ * @param PEAR_Common
+ */
+ function __construct(&$config, &$logger, $phase)
+ {
+ $this->config = &$config;
+ $this->registry = &$config->getRegistry();
+ $this->logger = &$logger;
+ $this->installphase = $phase;
+ if ($this->type == 'multiple') {
+ $GLOBALS['_PEAR_TASK_POSTINSTANCES'][get_class($this)][] = &$this;
+ }
+ }
+
+ /**
+ * Validate the basic contents of a task tag.
+ *
+ * @param PEAR_PackageFile_v2
+ * @param array
+ * @param PEAR_Config
+ * @param array the entire parsed tag
+ *
+ * @return true|array On error, return an array in format:
+ * array(PEAR_TASK_ERROR_???[, param1][, param2][, ...])
+ *
+ * For PEAR_TASK_ERROR_MISSING_ATTRIB, pass the attribute name in
+ * For PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, pass the attribute name and
+ * an array of legal values in
+ *
+ * @abstract
+ */
+ public static function validateXml($pkg, $xml, $config, $fileXml)
+ {
+ }
+
+ /**
+ * Initialize a task instance with the parameters
+ *
+ * @param array raw, parsed xml
+ * @param array attributes from the tag containing this task
+ * @param string|null last installed version of this package
+ * @abstract
+ */
+ public function init($xml, $fileAttributes, $lastVersion)
+ {
+ }
+
+ /**
+ * Begin a task processing session. All multiple tasks will be processed
+ * after each file has been successfully installed, all simple tasks should
+ * perform their task here and return any errors using the custom
+ * throwError() method to allow forward compatibility
+ *
+ * This method MUST NOT write out any changes to disk
+ *
+ * @param PEAR_PackageFile_v2
+ * @param string file contents
+ * @param string the eventual final file location (informational only)
+ * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail
+ * (use $this->throwError), otherwise return the new contents
+ * @abstract
+ */
+ public function startSession($pkg, $contents, $dest)
+ {
+ }
+
+ /**
+ * This method is used to process each of the tasks for a particular
+ * multiple class type. Simple tasks need not implement this method.
+ *
+ * @param array an array of tasks
+ * @access protected
+ */
+ public static function run($tasks)
+ {
+ }
+
+ /**
+ * @final
+ */
+ public static function hasPostinstallTasks()
+ {
+ return isset($GLOBALS['_PEAR_TASK_POSTINSTANCES']);
+ }
+
+ /**
+ * @final
+ */
+ public static function runPostinstallTasks()
+ {
+ foreach ($GLOBALS['_PEAR_TASK_POSTINSTANCES'] as $class => $tasks) {
+ $err = call_user_func(
+ array($class, 'run'),
+ $GLOBALS['_PEAR_TASK_POSTINSTANCES'][$class]
+ );
+ if ($err) {
+ return PEAR_Task_Common::throwError($err);
+ }
+ }
+ unset($GLOBALS['_PEAR_TASK_POSTINSTANCES']);
+ }
+
+ /**
+ * Determines whether a role is a script
+ * @return bool
+ */
+ public function isScript()
+ {
+ return $this->type == 'script';
+ }
+
+ public function throwError($msg, $code = -1)
+ {
+ include_once 'PEAR.php';
+
+ return PEAR::raiseError($msg, $code);
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Task/Postinstallscript.php b/vendor/pear-pear.php.net/PEAR/PEAR/Task/Postinstallscript.php
new file mode 100644
index 000000000..457ac28f6
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Task/Postinstallscript.php
@@ -0,0 +1,350 @@
+
+ *
+ * PHP versions 4 and 5
+ *
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+/**
+ * Base class
+ */
+require_once 'PEAR/Task/Common.php';
+/**
+ * Implements the postinstallscript file task.
+ *
+ * Note that post-install scripts are handled separately from installation, by the
+ * "pear run-scripts" command
+ *
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_Task_Postinstallscript extends PEAR_Task_Common
+{
+ public $type = 'script';
+ public $_class;
+ public $_params;
+ public $_obj;
+ /**
+ *
+ * @var PEAR_PackageFile_v2
+ */
+ public $_pkg;
+ public $_contents;
+ public $phase = PEAR_TASK_INSTALL;
+
+ /**
+ * Validate the raw xml at parsing-time.
+ *
+ * This also attempts to validate the script to make sure it meets the criteria
+ * for a post-install script
+ *
+ * @param PEAR_PackageFile_v2
+ * @param array The XML contents of the tag
+ * @param PEAR_Config
+ * @param array the entire parsed tag
+ */
+ public static function validateXml($pkg, $xml, $config, $fileXml)
+ {
+ if ($fileXml['role'] != 'php') {
+ return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
+ $fileXml['name'].'" must be role="php"', );
+ }
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ $file = $pkg->getFileContents($fileXml['name']);
+ if (PEAR::isError($file)) {
+ PEAR::popErrorHandling();
+
+ return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
+ $fileXml['name'].'" is not valid: '.
+ $file->getMessage(), );
+ } elseif ($file === null) {
+ return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
+ $fileXml['name'].'" could not be retrieved for processing!', );
+ } else {
+ $analysis = $pkg->analyzeSourceCode($file, true);
+ if (!$analysis) {
+ PEAR::popErrorHandling();
+ $warnings = '';
+ foreach ($pkg->getValidationWarnings() as $warn) {
+ $warnings .= $warn['message']."\n";
+ }
+
+ return array(PEAR_TASK_ERROR_INVALID, 'Analysis of post-install script "'.
+ $fileXml['name'].'" failed: '.$warnings, );
+ }
+ if (count($analysis['declared_classes']) != 1) {
+ PEAR::popErrorHandling();
+
+ return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
+ $fileXml['name'].'" must declare exactly 1 class', );
+ }
+ $class = $analysis['declared_classes'][0];
+ if ($class != str_replace(
+ array('/', '.php'), array('_', ''),
+ $fileXml['name']
+ ).'_postinstall') {
+ PEAR::popErrorHandling();
+
+ return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
+ $fileXml['name'].'" class "'.$class.'" must be named "'.
+ str_replace(
+ array('/', '.php'), array('_', ''),
+ $fileXml['name']
+ ).'_postinstall"', );
+ }
+ if (!isset($analysis['declared_methods'][$class])) {
+ PEAR::popErrorHandling();
+
+ return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
+ $fileXml['name'].'" must declare methods init() and run()', );
+ }
+ $methods = array('init' => 0, 'run' => 1);
+ foreach ($analysis['declared_methods'][$class] as $method) {
+ if (isset($methods[$method])) {
+ unset($methods[$method]);
+ }
+ }
+ if (count($methods)) {
+ PEAR::popErrorHandling();
+
+ return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
+ $fileXml['name'].'" must declare methods init() and run()', );
+ }
+ }
+ PEAR::popErrorHandling();
+ $definedparams = array();
+ $tasksNamespace = $pkg->getTasksNs().':';
+ if (!isset($xml[$tasksNamespace.'paramgroup']) && isset($xml['paramgroup'])) {
+ // in order to support the older betas, which did not expect internal tags
+ // to also use the namespace
+ $tasksNamespace = '';
+ }
+ if (isset($xml[$tasksNamespace.'paramgroup'])) {
+ $params = $xml[$tasksNamespace.'paramgroup'];
+ if (!is_array($params) || !isset($params[0])) {
+ $params = array($params);
+ }
+ foreach ($params as $param) {
+ if (!isset($param[$tasksNamespace.'id'])) {
+ return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
+ $fileXml['name'].'" must have '.
+ 'an '.$tasksNamespace.'id> tag', );
+ }
+ if (isset($param[$tasksNamespace.'name'])) {
+ if (!in_array($param[$tasksNamespace.'name'], $definedparams)) {
+ return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
+ $fileXml['name'].'" '.$tasksNamespace.
+ 'paramgroup> id "'.$param[$tasksNamespace.'id'].
+ '" parameter "'.$param[$tasksNamespace.'name'].
+ '" has not been previously defined', );
+ }
+ if (!isset($param[$tasksNamespace.'conditiontype'])) {
+ return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
+ $fileXml['name'].'" '.$tasksNamespace.
+ 'paramgroup> id "'.$param[$tasksNamespace.'id'].
+ '" must have a '.$tasksNamespace.
+ 'conditiontype> tag containing either "=", '.
+ '"!=", or "preg_match"', );
+ }
+ if (!in_array(
+ $param[$tasksNamespace.'conditiontype'],
+ array('=', '!=', 'preg_match')
+ )) {
+ return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
+ $fileXml['name'].'" '.$tasksNamespace.
+ 'paramgroup> id "'.$param[$tasksNamespace.'id'].
+ '" must have a '.$tasksNamespace.
+ 'conditiontype> tag containing either "=", '.
+ '"!=", or "preg_match"', );
+ }
+ if (!isset($param[$tasksNamespace.'value'])) {
+ return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
+ $fileXml['name'].'" '.$tasksNamespace.
+ 'paramgroup> id "'.$param[$tasksNamespace.'id'].
+ '" must have a '.$tasksNamespace.
+ 'value> tag containing expected parameter value', );
+ }
+ }
+ if (isset($param[$tasksNamespace.'instructions'])) {
+ if (!is_string($param[$tasksNamespace.'instructions'])) {
+ return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
+ $fileXml['name'].'" '.$tasksNamespace.
+ 'paramgroup> id "'.$param[$tasksNamespace.'id'].
+ '" '.$tasksNamespace.'instructions> must be simple text', );
+ }
+ }
+ if (!isset($param[$tasksNamespace.'param'])) {
+ continue; // is no longer required
+ }
+ $subparams = $param[$tasksNamespace.'param'];
+ if (!is_array($subparams) || !isset($subparams[0])) {
+ $subparams = array($subparams);
+ }
+ foreach ($subparams as $subparam) {
+ if (!isset($subparam[$tasksNamespace.'name'])) {
+ return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
+ $fileXml['name'].'" parameter for '.
+ $tasksNamespace.'paramgroup> id "'.
+ $param[$tasksNamespace.'id'].'" must have '.
+ 'a '.$tasksNamespace.'name> tag', );
+ }
+ if (!preg_match(
+ '/[a-zA-Z0-9]+/',
+ $subparam[$tasksNamespace.'name']
+ )) {
+ return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
+ $fileXml['name'].'" parameter "'.
+ $subparam[$tasksNamespace.'name'].
+ '" for '.$tasksNamespace.'paramgroup> id "'.
+ $param[$tasksNamespace.'id'].
+ '" is not a valid name. Must contain only alphanumeric characters', );
+ }
+ if (!isset($subparam[$tasksNamespace.'prompt'])) {
+ return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
+ $fileXml['name'].'" parameter "'.
+ $subparam[$tasksNamespace.'name'].
+ '" for '.$tasksNamespace.'paramgroup> id "'.
+ $param[$tasksNamespace.'id'].
+ '" must have a '.$tasksNamespace.'prompt> tag', );
+ }
+ if (!isset($subparam[$tasksNamespace.'type'])) {
+ return array(PEAR_TASK_ERROR_INVALID, 'Post-install script "'.
+ $fileXml['name'].'" parameter "'.
+ $subparam[$tasksNamespace.'name'].
+ '" for '.$tasksNamespace.'paramgroup> id "'.
+ $param[$tasksNamespace.'id'].
+ '" must have a '.$tasksNamespace.'type> tag', );
+ }
+ $definedparams[] = $param[$tasksNamespace.'id'].'::'.
+ $subparam[$tasksNamespace.'name'];
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Initialize a task instance with the parameters
+ * @param array $xml raw, parsed xml
+ * @param array $fileattribs attributes from the tag containing
+ * this task
+ * @param string|null $lastversion last installed version of this package,
+ * if any (useful for upgrades)
+ */
+ public function init($xml, $fileattribs, $lastversion)
+ {
+ $this->_class = str_replace('/', '_', $fileattribs['name']);
+ $this->_filename = $fileattribs['name'];
+ $this->_class = str_replace('.php', '', $this->_class).'_postinstall';
+ $this->_params = $xml;
+ $this->_lastversion = $lastversion;
+ }
+
+ /**
+ * Strip the tasks: namespace from internal params
+ *
+ * @access private
+ */
+ public function _stripNamespace($params = null)
+ {
+ if ($params === null) {
+ $params = array();
+ if (!is_array($this->_params)) {
+ return;
+ }
+ foreach ($this->_params as $i => $param) {
+ if (is_array($param)) {
+ $param = $this->_stripNamespace($param);
+ }
+ $params[str_replace($this->_pkg->getTasksNs().':', '', $i)] = $param;
+ }
+ $this->_params = $params;
+ } else {
+ $newparams = array();
+ foreach ($params as $i => $param) {
+ if (is_array($param)) {
+ $param = $this->_stripNamespace($param);
+ }
+ $newparams[str_replace($this->_pkg->getTasksNs().':', '', $i)] = $param;
+ }
+
+ return $newparams;
+ }
+ }
+
+ /**
+ * Unlike other tasks, the installed file name is passed in instead of the
+ * file contents, because this task is handled post-installation
+ *
+ * @param mixed $pkg PEAR_PackageFile_v1|PEAR_PackageFile_v2
+ * @param string $contents file name
+ * @param string $dest the eventual final file location (informational only)
+ *
+ * @return bool|PEAR_Error false to skip this file, PEAR_Error to fail
+ * (use $this->throwError)
+ */
+ public function startSession($pkg, $contents, $dest)
+ {
+ if ($this->installphase != PEAR_TASK_INSTALL) {
+ return false;
+ }
+ // remove the tasks: namespace if present
+ $this->_pkg = $pkg;
+ $this->_stripNamespace();
+ $this->logger->log(
+ 0, 'Including external post-installation script "'.
+ $contents.'" - any errors are in this script'
+ );
+ include_once $contents;
+ if (class_exists($this->_class)) {
+ $this->logger->log(0, 'Inclusion succeeded');
+ } else {
+ return $this->throwError(
+ 'init of post-install script class "'.$this->_class
+ .'" failed'
+ );
+ }
+ $this->_obj = new $this->_class();
+ $this->logger->log(1, 'running post-install script "'.$this->_class.'->init()"');
+ PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
+ $res = $this->_obj->init($this->config, $pkg, $this->_lastversion);
+ PEAR::popErrorHandling();
+ if ($res) {
+ $this->logger->log(0, 'init succeeded');
+ } else {
+ return $this->throwError(
+ 'init of post-install script "'.$this->_class.
+ '->init()" failed'
+ );
+ }
+ $this->_contents = $contents;
+
+ return true;
+ }
+
+ /**
+ * No longer used
+ *
+ * @see PEAR_PackageFile_v2::runPostinstallScripts()
+ * @param array an array of tasks
+ * @param string install or upgrade
+ * @access protected
+ */
+ public static function run($tasks)
+ {
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Task/Postinstallscript/rw.php b/vendor/pear-pear.php.net/PEAR/PEAR/Task/Postinstallscript/rw.php
new file mode 100644
index 000000000..10f5e7b26
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Task/Postinstallscript/rw.php
@@ -0,0 +1,182 @@
+ - read/write version
+ *
+ * PHP versions 4 and 5
+ *
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a10
+ */
+/**
+ * Base class
+ */
+require_once 'PEAR/Task/Postinstallscript.php';
+/**
+ * Abstracts the postinstallscript file task xml.
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a10
+ */
+class PEAR_Task_Postinstallscript_rw extends PEAR_Task_Postinstallscript
+{
+ /**
+ * parent package file object
+ *
+ * @var PEAR_PackageFile_v2_rw
+ */
+ public $_pkg;
+ /**
+ * Enter description here...
+ *
+ * @param PEAR_PackageFile_v2_rw $pkg Package
+ * @param PEAR_Config $config Config
+ * @param PEAR_Frontend $logger Logger
+ * @param array $fileXml XML
+ *
+ * @return PEAR_Task_Postinstallscript_rw
+ */
+ function __construct(&$pkg, &$config, &$logger, $fileXml)
+ {
+ parent::__construct($config, $logger, PEAR_TASK_PACKAGE);
+ $this->_contents = $fileXml;
+ $this->_pkg = &$pkg;
+ $this->_params = array();
+ }
+
+ public function validate()
+ {
+ return $this->validateXml($this->_pkg, $this->_params, $this->config, $this->_contents);
+ }
+
+ public function getName()
+ {
+ return 'postinstallscript';
+ }
+
+ /**
+ * add a simple to the post-install script
+ *
+ * Order is significant, so call this method in the same
+ * sequence the users should see the paramgroups. The $params
+ * parameter should either be the result of a call to {@link getParam()}
+ * or an array of calls to getParam().
+ *
+ * Use {@link addConditionTypeGroup()} to add a containing
+ * a tag
+ *
+ * @param string $id id as seen by the script
+ * @param array|false $params array of getParam() calls, or false for no params
+ * @param string|false $instructions
+ */
+ public function addParamGroup($id, $params = false, $instructions = false)
+ {
+ if ($params && isset($params[0]) && !isset($params[1])) {
+ $params = $params[0];
+ }
+ $stuff =
+ array(
+ $this->_pkg->getTasksNs().':id' => $id,
+ );
+ if ($instructions) {
+ $stuff[$this->_pkg->getTasksNs().':instructions'] = $instructions;
+ }
+ if ($params) {
+ $stuff[$this->_pkg->getTasksNs().':param'] = $params;
+ }
+ $this->_params[$this->_pkg->getTasksNs().':paramgroup'][] = $stuff;
+ }
+
+ /**
+ * Add a complex to the post-install script with conditions
+ *
+ * This inserts a with
+ *
+ * Order is significant, so call this method in the same
+ * sequence the users should see the paramgroups. The $params
+ * parameter should either be the result of a call to {@link getParam()}
+ * or an array of calls to getParam().
+ *
+ * Use {@link addParamGroup()} to add a simple
+ *
+ * @param string $id id as seen by the script
+ * @param string $oldgroup id of the section referenced by
+ *
+ * @param string $param name of the from the older section referenced
+ * by
+ * @param string $value value to match of the parameter
+ * @param string $conditiontype one of '=', '!=', 'preg_match'
+ * @param array|false $params array of getParam() calls, or false for no params
+ * @param string|false $instructions
+ */
+ public function addConditionTypeGroup($id,
+ $oldgroup,
+ $param,
+ $value,
+ $conditiontype = '=',
+ $params = false,
+ $instructions = false
+ ) {
+ if ($params && isset($params[0]) && !isset($params[1])) {
+ $params = $params[0];
+ }
+ $stuff = array(
+ $this->_pkg->getTasksNs().':id' => $id,
+ );
+ if ($instructions) {
+ $stuff[$this->_pkg->getTasksNs().':instructions'] = $instructions;
+ }
+ $stuff[$this->_pkg->getTasksNs().':name'] = $oldgroup.'::'.$param;
+ $stuff[$this->_pkg->getTasksNs().':conditiontype'] = $conditiontype;
+ $stuff[$this->_pkg->getTasksNs().':value'] = $value;
+ if ($params) {
+ $stuff[$this->_pkg->getTasksNs().':param'] = $params;
+ }
+ $this->_params[$this->_pkg->getTasksNs().':paramgroup'][] = $stuff;
+ }
+
+ public function getXml()
+ {
+ return $this->_params;
+ }
+
+ /**
+ * Use to set up a param tag for use in creating a paramgroup
+ *
+ * @param mixed $name Name of parameter
+ * @param mixed $prompt Prompt
+ * @param string $type Type, defaults to 'string'
+ * @param mixed $default Default value
+ *
+ * @return array
+ */
+ public function getParam(
+ $name, $prompt, $type = 'string', $default = null
+ ) {
+ if ($default !== null) {
+ return
+ array(
+ $this->_pkg->getTasksNs().':name' => $name,
+ $this->_pkg->getTasksNs().':prompt' => $prompt,
+ $this->_pkg->getTasksNs().':type' => $type,
+ $this->_pkg->getTasksNs().':default' => $default,
+ );
+ }
+
+ return
+ array(
+ $this->_pkg->getTasksNs().':name' => $name,
+ $this->_pkg->getTasksNs().':prompt' => $prompt,
+ $this->_pkg->getTasksNs().':type' => $type,
+ );
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Task/Replace.php b/vendor/pear-pear.php.net/PEAR/PEAR/Task/Replace.php
new file mode 100644
index 000000000..1ea71bfe5
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Task/Replace.php
@@ -0,0 +1,186 @@
+
+ *
+ * PHP versions 4 and 5
+ *
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+/**
+ * Base class
+ */
+require_once 'PEAR/Task/Common.php';
+/**
+ * Implements the replace file task.
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_Task_Replace extends PEAR_Task_Common
+{
+ public $type = 'simple';
+ public $phase = PEAR_TASK_PACKAGEANDINSTALL;
+ public $_replacements;
+
+ /**
+ * Validate the raw xml at parsing-time.
+ *
+ * @param PEAR_PackageFile_v2
+ * @param array raw, parsed xml
+ * @param PEAR_Config
+ */
+ public static function validateXml($pkg, $xml, $config, $fileXml)
+ {
+ if (!isset($xml['attribs'])) {
+ return array(PEAR_TASK_ERROR_NOATTRIBS);
+ }
+ if (!isset($xml['attribs']['type'])) {
+ return array(PEAR_TASK_ERROR_MISSING_ATTRIB, 'type');
+ }
+ if (!isset($xml['attribs']['to'])) {
+ return array(PEAR_TASK_ERROR_MISSING_ATTRIB, 'to');
+ }
+ if (!isset($xml['attribs']['from'])) {
+ return array(PEAR_TASK_ERROR_MISSING_ATTRIB, 'from');
+ }
+ if ($xml['attribs']['type'] == 'pear-config') {
+ if (!in_array($xml['attribs']['to'], $config->getKeys())) {
+ return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'to', $xml['attribs']['to'],
+ $config->getKeys(), );
+ }
+ } elseif ($xml['attribs']['type'] == 'php-const') {
+ if (defined($xml['attribs']['to'])) {
+ return true;
+ } else {
+ return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'to', $xml['attribs']['to'],
+ array('valid PHP constant'), );
+ }
+ } elseif ($xml['attribs']['type'] == 'package-info') {
+ if (in_array(
+ $xml['attribs']['to'],
+ array('name', 'summary', 'channel', 'notes', 'extends', 'description',
+ 'release_notes', 'license', 'release-license', 'license-uri',
+ 'version', 'api-version', 'state', 'api-state', 'release_date',
+ 'date', 'time', )
+ )) {
+ return true;
+ } else {
+ return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'to', $xml['attribs']['to'],
+ array('name', 'summary', 'channel', 'notes', 'extends', 'description',
+ 'release_notes', 'license', 'release-license', 'license-uri',
+ 'version', 'api-version', 'state', 'api-state', 'release_date',
+ 'date', 'time', ), );
+ }
+ } else {
+ return array(PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE, 'type', $xml['attribs']['type'],
+ array('pear-config', 'package-info', 'php-const'), );
+ }
+
+ return true;
+ }
+
+ /**
+ * Initialize a task instance with the parameters
+ * @param array raw, parsed xml
+ * @param unused
+ * @param unused
+ */
+ public function init($xml, $attribs, $lastVersion = null)
+ {
+ $this->_replacements = isset($xml['attribs']) ? array($xml) : $xml;
+ }
+
+ /**
+ * Do a package.xml 1.0 replacement, with additional package-info fields available
+ *
+ * See validateXml() source for the complete list of allowed fields
+ *
+ * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+ * @param string file contents
+ * @param string the eventual final file location (informational only)
+ * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail
+ * (use $this->throwError), otherwise return the new contents
+ */
+ public function startSession($pkg, $contents, $dest)
+ {
+ $subst_from = $subst_to = array();
+ foreach ($this->_replacements as $a) {
+ $a = $a['attribs'];
+ $to = '';
+ if ($a['type'] == 'pear-config') {
+ if ($this->installphase == PEAR_TASK_PACKAGE) {
+ return false;
+ }
+ if ($a['to'] == 'master_server') {
+ $chan = $this->registry->getChannel($pkg->getChannel());
+ if (!PEAR::isError($chan)) {
+ $to = $chan->getServer();
+ } else {
+ $this->logger->log(0, "$dest: invalid pear-config replacement: $a[to]");
+
+ return false;
+ }
+ } else {
+ if ($this->config->isDefinedLayer('ftp')) {
+ // try the remote config file first
+ $to = $this->config->get($a['to'], 'ftp', $pkg->getChannel());
+ if (is_null($to)) {
+ // then default to local
+ $to = $this->config->get($a['to'], null, $pkg->getChannel());
+ }
+ } else {
+ $to = $this->config->get($a['to'], null, $pkg->getChannel());
+ }
+ }
+ if (is_null($to)) {
+ $this->logger->log(0, "$dest: invalid pear-config replacement: $a[to]");
+
+ return false;
+ }
+ } elseif ($a['type'] == 'php-const') {
+ if ($this->installphase == PEAR_TASK_PACKAGE) {
+ return false;
+ }
+ if (defined($a['to'])) {
+ $to = constant($a['to']);
+ } else {
+ $this->logger->log(0, "$dest: invalid php-const replacement: $a[to]");
+
+ return false;
+ }
+ } else {
+ if ($t = $pkg->packageInfo($a['to'])) {
+ $to = $t;
+ } else {
+ $this->logger->log(0, "$dest: invalid package-info replacement: $a[to]");
+
+ return false;
+ }
+ }
+ if (!is_null($to)) {
+ $subst_from[] = $a['from'];
+ $subst_to[] = $to;
+ }
+ }
+ $this->logger->log(
+ 3, "doing ".sizeof($subst_from).
+ " substitution(s) for $dest"
+ );
+ if (sizeof($subst_from)) {
+ $contents = str_replace($subst_from, $subst_to, $contents);
+ }
+
+ return $contents;
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Task/Replace/rw.php b/vendor/pear-pear.php.net/PEAR/PEAR/Task/Replace/rw.php
new file mode 100644
index 000000000..a2ffc24b1
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Task/Replace/rw.php
@@ -0,0 +1,59 @@
+ - read/write version
+ *
+ * PHP versions 4 and 5
+ *
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a10
+ */
+/**
+ * Base class
+ */
+require_once 'PEAR/Task/Replace.php';
+/**
+ * Abstracts the replace task xml.
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a10
+ */
+class PEAR_Task_Replace_rw extends PEAR_Task_Replace
+{
+ public function __construct(&$pkg, &$config, &$logger, $fileXml)
+ {
+ parent::__construct($config, $logger, PEAR_TASK_PACKAGE);
+ $this->_contents = $fileXml;
+ $this->_pkg = &$pkg;
+ $this->_params = array();
+ }
+
+ public function validate()
+ {
+ return $this->validateXml($this->_pkg, $this->_params, $this->config, $this->_contents);
+ }
+
+ public function setInfo($from, $to, $type)
+ {
+ $this->_params = array('attribs' => array('from' => $from, 'to' => $to, 'type' => $type));
+ }
+
+ public function getName()
+ {
+ return 'replace';
+ }
+
+ public function getXml()
+ {
+ return $this->_params;
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Task/Unixeol.php b/vendor/pear-pear.php.net/PEAR/PEAR/Task/Unixeol.php
new file mode 100644
index 000000000..3b1d84c9a
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Task/Unixeol.php
@@ -0,0 +1,79 @@
+
+ *
+ * PHP versions 4 and 5
+ *
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a1
+ */
+/**
+ * Base class
+ */
+require_once 'PEAR/Task/Common.php';
+/**
+ * Implements the unix line endings file task.
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.10.3
+ * @link http://pear.php.net/package/PEAR
+ * @since Class available since Release 1.4.0a1
+ */
+class PEAR_Task_Unixeol extends PEAR_Task_Common
+{
+ public $type = 'simple';
+ public $phase = PEAR_TASK_PACKAGE;
+ public $_replacements;
+
+ /**
+ * Validate the raw xml at parsing-time.
+ *
+ * @param PEAR_PackageFile_v2
+ * @param array raw, parsed xml
+ * @param PEAR_Config
+ */
+ public static function validateXml($pkg, $xml, $config, $fileXml)
+ {
+ if ($xml != '') {
+ return array(PEAR_TASK_ERROR_INVALID, 'no attributes allowed');
+ }
+
+ return true;
+ }
+
+ /**
+ * Initialize a task instance with the parameters
+ * @param array raw, parsed xml
+ * @param unused
+ * @param unused
+ */
+ public function init($xml, $attribs, $lastVersion = null)
+ {
+ }
+
+ /**
+ * Replace all line endings with line endings customized for the current OS
+ *
+ * See validateXml() source for the complete list of allowed fields
+ *
+ * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
+ * @param string file contents
+ * @param string the eventual final file location (informational only)
+ * @return string|false|PEAR_Error false to skip this file, PEAR_Error to fail
+ * (use $this->throwError), otherwise return the new contents
+ */
+ public function startSession($pkg, $contents, $dest)
+ {
+ $this->logger->log(3, "replacing all line endings with \\n in $dest");
+
+ return preg_replace("/\r\n|\n\r|\r|\n/", "\n", $contents);
+ }
+}
diff --git a/vendor/pear-pear.php.net/PEAR/PEAR/Task/Unixeol/rw.php b/vendor/pear-pear.php.net/PEAR/PEAR/Task/Unixeol/rw.php
new file mode 100644
index 000000000..7e98f2184
--- /dev/null
+++ b/vendor/pear-pear.php.net/PEAR/PEAR/Task/Unixeol/rw.php
@@ -0,0 +1,55 @@
+ - read/write version
+ *
+ * PHP versions 4 and 5
+ *
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 1.4.0a10
+ */
+/**
+ * Base class
+ */
+require_once 'PEAR/Task/Unixeol.php';
+/**
+ * Abstracts the unixeol task xml.
+ * @category pear
+ * @package PEAR
+ * @author Greg Beaver